前言
PC Server發(fā)展到今天,在性能方面有著長足的進(jìn)步。64位的CPU在數(shù)年前都已經(jīng)進(jìn)入到尋常的家用PC之中,更別說是更高端的PC Server;在Intel和AMD兩大處理器巨頭的努力下,x86 CPU在處理能力上不斷提升;同時隨著制造工藝的發(fā)展,在PC Server上能夠安裝的內(nèi)存容量也越來越大,現(xiàn)在隨處可見數(shù)十G內(nèi)存的PC Server。正是硬件的發(fā)展,使得PC Server的處理能力越來越強(qiáng)大,性能越來越高。而在穩(wěn)定性方面,搭配PCServer和Linux操作系統(tǒng),同樣能夠滿重要業(yè)務(wù)系統(tǒng)所需要的穩(wěn)定性和可靠性。當(dāng)然在成本方面,引用一位在行業(yè)軟件廠商的網(wǎng)友的話來說,“如果不用PC Server改用小型機(jī),那我們賺什么錢???”。不管從初期的購買,運(yùn)行期的能耗和維護(hù)成本,PC Server都比相同處理能力的小型機(jī)便宜很多。正是在性能和成本這兩個重要因素的影響下,運(yùn)行在PC Server上的數(shù)據(jù)庫越來越多。筆者所服務(wù)的一些客戶,甚至把高端的PCServer虛擬化成多臺機(jī)器,在每臺虛擬機(jī)上跑一套Oracle數(shù)據(jù)庫,這些數(shù)據(jù)庫不乏承載著重要的生產(chǎn)系統(tǒng)。
毫無疑問,在PC Server上運(yùn)行Oracle數(shù)據(jù)庫,最適合的操作系統(tǒng)無疑是Linux。作為與UNIX極為類似的操作系統(tǒng),在穩(wěn)定性、可靠性和性能方面有著與UNIX同樣優(yōu)異的表現(xiàn)。但是Linux在內(nèi)存分頁處理機(jī)制上與AIX、HP-UX等操作系統(tǒng)相比有一個明顯的缺陷,而這個缺陷在使用較大SGA的Oracle數(shù)據(jù)庫上體現(xiàn)尤為明顯,嚴(yán)重時對數(shù)據(jù)庫性能有著顯著的負(fù)面影響,甚至?xí)?dǎo)致數(shù)據(jù)庫完全停止響應(yīng)。而本文就將從一個案例來詳述這種缺陷,并使用Linux下的大內(nèi)存頁來解決這一問題。
一、案例的引入
客戶的一套系統(tǒng),出現(xiàn)了嚴(yán)重的性能問題。在問題出現(xiàn)時,系統(tǒng)基本不可使用,應(yīng)用上所有的業(yè)務(wù)操作完全失去響應(yīng)。系統(tǒng)的數(shù)據(jù)庫是運(yùn)行在RHEL 5.2 (Red Hat Enterprise Linux Server release 5 (Tikanga))下的Oracle 10.2.0.4 Oracle Database,CPU為4顆4核至強(qiáng)處理器(Intel(R)Xeon(R) CPU E7430 @ 2.13GHz),也就是邏輯CPU為16,內(nèi)存32GB。故障期間,數(shù)據(jù)庫服務(wù)器的CPU長期保持在100%。甚至將應(yīng)用的所有Weblogic Server都關(guān)閉之后,數(shù)據(jù)庫服務(wù)器的CPU利用率在數(shù)分鐘之內(nèi)都一直是100%,然后逐漸下降,大約需要經(jīng)過20分鐘才會下降到正常的空閑狀態(tài),因?yàn)檫@個時候所有的應(yīng)用都已經(jīng)關(guān)閉,只有非常低的CPU利用率才是正常的狀態(tài)。據(jù)這套系統(tǒng)的數(shù)據(jù)庫維護(hù)人員反映,這種情況已經(jīng)出現(xiàn)多次,就算是重啟數(shù)據(jù)庫之后,過不了一兩天,這樣的故障同樣會出現(xiàn)。同時這套系統(tǒng)最近也沒做過大的變動。
筆者在接到接到故障報(bào)告后,通過SSH連接到數(shù)據(jù)庫數(shù)據(jù)庫都非常慢,需要差不多1分鐘才能連接上去。先簡單的看一下服務(wù)器的性能狀況,發(fā)展IO極低、內(nèi)存剩余還比較多,至少還有1GB以上,也沒有page in / page out。而最顯著的現(xiàn)象就是CPU利用率相當(dāng)?shù)馗?,一直保持?00%,同時CPU利用率的SYS部分,均在95%以上。而操作系統(tǒng)運(yùn)行隊(duì)列也一直在200以上。服務(wù)器內(nèi)存的使用情況如下:
$cat/proc/meminfo
MemTotal: 32999792 kB
MemFree: 1438672 kB
Buffers: 112304 kB
Cached: 23471680 kB
SwapCached: 1296 kB
Active: 19571024 kB
Inactive: 6085396 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 32999792 kB
LowFree: 1438672 kB
SwapTotal: 38371320 kB
SwapFree: 38260796 kB
Dirty: 280 kB
Writeback: 0kB
AnonPages: 2071192 kB
Mapped: 12455324 kB
Slab: 340140 kB
PageTables: 4749076 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
CommitLimit: 54871216kB
Committed_AS: 17226744 kB
VmallocTotal:34359738367 kB
VmallocUsed: 22016 kB
VmallocChunk:34359716303 kB
從現(xiàn)象上看,SYS CPU高是分析問題的一個重要線索。
在以最快的速度了解了一下操作系統(tǒng)層面的性能情況之后,立即通過Sqlplus連接到數(shù)據(jù)庫,查看數(shù)據(jù)庫內(nèi)部的性能信息:
(注:以下數(shù)據(jù)關(guān)于SQL、服務(wù)器名稱、數(shù)據(jù)庫名稱等相關(guān)信息經(jīng)過處理。)
SQL> select sid,serial#,program,machine,sql_id,eventfrom v$session where type='USER' and status='ACTIVE';
SID SERIAL# PROGRAM MACHINE SQL_ID EVENT
-------------------- ------------------------------ ---------- -------------
519 4304 xxx_app1 0gc4uvt2pqvpu latch: cache buffers chains
459 12806 xxx_app1 0gc4uvt2pqvpu latch: cache buffers chains
454 5518 xxx_app1 15hq76k17h4ta latch: cache buffers chains
529 7708 xxx_app1 0gc4uvt2pqvpu latch: cache buffers chains
420 40948 xxx_app1 0gc4uvt2pqvpu latch: cache buffers chains
353 56222 xxx_app1 f7fxxczffp5rx latch: cache buffers chains
243 42611 xxx_app1 2zqg4sbrq7zay latch: cache buffers chains
458 63221 xxxTimer.exe APPSERVER 9t1ujakwt6fnf local write wait
...為節(jié)省篇幅,省略部分內(nèi)容...
409 4951 xxx_app1 7d4c6m3ytcx87 read by other session
239 51959 xxx_app1 7d4c6m3ytcx87 read by other session
525 3815 xxxTimer.exe APPSERVER 0ftnnr7pfw7r6 enq: RO -fast object reu
518 7845 xxx_app1 log file sync
473 1972 xxxTimer.exe APPSERVER 5017jsr7kdk3b log file sync
197 37462 xxx_app1 cbvbzbfdxn2w7 db file sequential read
319 4939 xxxTimer.exe APPSERVER 6vmk5uzu1p45m db file sequentialread
434 2939 xxx_app1 gw921z764rmkc latch: shared pool
220 50017 xxx_app1 2zqg4sbrq7zay latch: library cache
301 36418 xxx_app1 02dw161xqmrgf latch: library cache
193 25003 oracle@xxx_db1 (J001) xxx_db1 jobq slave wait
368 64846 oracle@xxx_db1 (J000) xxx_db1 jobq slave wait
218 13307 sqlplus@xxx_db1 (TNS V1-V3) xxx_db1 5rby2rfcgs6b7 SQL*Net message to client
435 1883 xxx_app1 fd7369jwkuvty SQL*Net message from client
448 3001 xxxTimer.exe APPSERVER bsk0kpawwztnwSQL*Net message from dblink
SQL>@waitevent
SID EVENT SECONDS_IN_WAIT STATE
----------------------------------- --------------- -------------------
556 latch: cache buffers chains 35 WAITED KNOWN TIME
464 latch:cache buffers chai ns 2 WAITING
427 latch:cache buffers chai ns 34 WAITED SHORT TIME
458 localwrite wait 63 WAITING
403 writecomplete waits 40 WAITING
502 writecomplete waits 41 WAITING
525 enq:RO - fast object reuse 40 WAITING
368 enq:RO - fast object reu se 23 WAITING
282 db file sequential read 0 WAITING
501 dbfile sequential read 2 WAITED SHORT TIME
478 db file sequential read 0 WAITING
281 db file sequential read 6 WAITED KNOWN TIME
195 db file sequential read 4 WAITED KNOWN TIME
450 db file sequential read 2 WAITED KNOWN TIME
529 db file sequential read 1 WAITING
310 dbfile sequential read 0 WAITED KNOWN TIME
316 db filesequential read 89 WAITED SHORT TIME
370 db file sequential read 1 WAITING
380 db file sequential read 1 WAITED SHORT TIME
326 jobq slave wait 122 WAITING
378 jobq slave wait 2 WAITING
425 jobq slave wait 108 WAITING
208 SQL*Net more data from db 11 WAITED SHORT TIME link
537 Streams AQ: waiting for t 7042 WAITING ime management or cleanup tasks
549 Streams AQ: qmn coordinat 1585854 WAITING or idle wait
507 Streams AQ: qmn slave idl 1585854 WAITING e wait
430 latch free 2 WAITED KNOWN TIME
565 latch:cache buffers lru 136 WAITED SHORT TIME chain
從數(shù)據(jù)庫中的活動以及等待事件來看,并沒有太大的異常。值得注意的是,在數(shù)據(jù)庫服務(wù)器CPU利用率長期在100%,或物理內(nèi)存耗盡并伴有大量的交換內(nèi)存換入換出時,需要仔細(xì)地診斷數(shù)據(jù)庫中的性能現(xiàn)象,比如某類較多的等待事件,是由CPU或內(nèi)存不足導(dǎo)致的結(jié)果還是因?yàn)檫@些數(shù)據(jù)庫中的特定的活動才是Root Cause引起CPU過高或內(nèi)存耗盡。
從上面的數(shù)據(jù)來看,活動會話并不是特別多,不到50個,加上后臺進(jìn)程的數(shù)量,與操作系統(tǒng)中高達(dá)200的運(yùn)行相比,存在不小的差異。數(shù)據(jù)庫中主要有三類的非空閑等待事件,IO相關(guān)的等待如db file sequential read,database link相關(guān)的SQL*Net more data from dblink以及l(fā)atch 相關(guān)的等待事件。在這三類種,通常只有l(wèi)atch這類等待事件才會引起CPU的利用率增加。
通過分析對比AWR報(bào)告,在故障期間和正常期間,從數(shù)據(jù)庫活動來說,沒有特別明顯的差異。但是在系統(tǒng)統(tǒng)計(jì)上,差異較大:
StatisticName 1st 2nd Value
----------------------------------- -------------- -------------- ------------------------
BUSY_TIME 3,475,776 1,611,753
IDLE_TIME 2,266,224 4,065,506
IOWAIT_TIME 520,453 886,345
LOAD -67 -3
NICE_TIME 0 0
NUM_CPU_SOCKETS 0 0
PHYSICAL_MEMORY_BYTES 0 0
RSRC_MGR_CPU_WAIT_TIME 0 0
SYS_TIME 1,802,025 205,644
USER_TIME 1,645,837 1,381,719
上面的數(shù)據(jù)中,是來自于包含故障時間段的1小時(1st)和正常時間段1小時(2nd)的AWR的對比數(shù)據(jù)。對于故障分析來說,特別是故障時間比較短的情況下,1小時的AWR報(bào)告會不夠準(zhǔn)確地反映故障期間的性能情況。但是我們在Trouble Shooting之時,首要的是需要從各種數(shù)據(jù)中,確定方向。正如前面提到,SYS部分的CPU利用率過高是一個很重要的線索,而數(shù)據(jù)庫內(nèi)部的其他性能數(shù)據(jù)相差不大的情況下,可以先從CPU這一點(diǎn)著手。
二、操作系統(tǒng)中CPU使用分析
那么,在操作系統(tǒng)中,SYS和USER這兩個不同的利用率代表著什么?或者說二者有什么區(qū)別?
簡單來說,CPU利用率中的SYS部分,指的是操作系統(tǒng)內(nèi)核(Kernel)使用的CPU部分,也就是運(yùn)行在內(nèi)核態(tài)的代碼所消耗的CPU,最常見的就是系統(tǒng)調(diào)用(SYS CALL)時消耗的CPU。而USER部分則是應(yīng)用軟件自己的代碼使用的CPU部分,也就是運(yùn)行在用戶態(tài)的代碼所消耗的CPU。比如Oracle在執(zhí)行SQL時,從磁盤讀數(shù)據(jù)到db buffer cache,需要發(fā)起read調(diào)用,這個read調(diào)用主要是由操作系統(tǒng)內(nèi)核包括設(shè)備驅(qū)動程序的代碼在運(yùn)行,因此消耗的CPU計(jì)算到SYS部分;而Oracle在解析從磁盤中讀到的數(shù)據(jù)時,則只是Oracle自己的代碼在運(yùn)行,因此消耗的CPU計(jì)算到USER部分。
那么SYS部分的CPU主要會由哪些操作或是系統(tǒng)調(diào)用產(chǎn)生呢:
1. I/O操作,比如讀寫文件、訪問外設(shè)、通過網(wǎng)絡(luò)傳輸數(shù)據(jù)等。這部分操作一般不會消耗太多的CPU,因?yàn)橹饕臅r間消耗會在IO操作的設(shè)備上。比如從磁盤讀文件時,主要的時間在磁盤內(nèi)部的操作上,而消耗的CPU時間只占I/O操作響應(yīng)時間的少部分。只有在過高的并發(fā)I/O時才可能會使SYS CPU有所增加。
2. 內(nèi)存管理,比如應(yīng)用進(jìn)程向操作系統(tǒng)申請內(nèi)存,操作系統(tǒng)維護(hù)系統(tǒng)可用內(nèi)存,交換空間換頁等。其實(shí)與Oracle類似,越大的內(nèi)存,越頻繁的內(nèi)存管理操作,CPU的消耗會越高。
3. 進(jìn)程調(diào)度。這部分CPU的使用,在于操作系統(tǒng)中運(yùn)行隊(duì)列的長短,越長的運(yùn)行隊(duì)列,表明越多的進(jìn)程需要調(diào)度,那么內(nèi)核的負(fù)擔(dān)也就越高。
4. 其他,包括進(jìn)程間通信、信號量處理、設(shè)備驅(qū)動程序內(nèi)部一些活動等等。
從系統(tǒng)故障時的性能數(shù)據(jù)來看,內(nèi)存管理和進(jìn)程調(diào)度這兩項(xiàng)可能是引起SYS CPU很高的原因。但是運(yùn)行隊(duì)列高達(dá)200以上,很可能是由于CPU利用率高導(dǎo)致的結(jié)果,而不是因?yàn)檫\(yùn)行隊(duì)列高導(dǎo)致了CPU利用率高。從數(shù)據(jù)庫里面來看活動會話數(shù)不是特別高。那么接下來,需要關(guān)注是否是由于系統(tǒng)內(nèi)存管理方面的問題導(dǎo)致了CPU利用率過高?
回顧本文開始部分收集的/proc/meminfo中系統(tǒng)內(nèi)存方面數(shù)據(jù),可以發(fā)現(xiàn)一項(xiàng)重要的數(shù)據(jù):
從數(shù)據(jù)可以看到,PageTables內(nèi)存達(dá)到了4637MB。PageTables在字面意思上是指“頁面表”。簡單地說,就是操作系統(tǒng)內(nèi)核用于維護(hù)進(jìn)程線性虛擬地址和實(shí)際物理內(nèi)存地址對應(yīng)關(guān)系的表格。
現(xiàn)代計(jì)算機(jī)對于物理內(nèi)存,通常是將其以頁(Page Frame)為單位進(jìn)行管理和分配,在 x86處理器架構(gòu)上,頁面大小為4K。運(yùn)行在操作系統(tǒng)上的進(jìn)程,可訪問的地址空間稱為虛地址空間,跟處理器位數(shù)有關(guān)。對于32位的x86處理器,進(jìn)程的可訪問地址空間為4GB。在操作系統(tǒng)中運(yùn)行的每一個進(jìn)程,都有其獨(dú)立的虛地址空間或線性地址空間,而這個地址空間同樣也是按頁(Page)進(jìn)行管理,在Linux中,頁大小通常為4KB。進(jìn)程在訪問內(nèi)存時,由操作系統(tǒng)和硬件配合,負(fù)責(zé)將進(jìn)程的虛擬地址轉(zhuǎn)換成為物理地址。兩個不同的進(jìn)程,其相同的虛擬線性地址,指向的物理內(nèi)存,可能相同,比如共享內(nèi)存;也可能不同,比如進(jìn)程的私有內(nèi)存。
下圖是關(guān)于虛擬地址和物理內(nèi)存對應(yīng)關(guān)系的示意圖:
假設(shè)有兩個進(jìn)程A、B,分別有一個內(nèi)存指針指向的地址為0x12345(0x表示16進(jìn)制數(shù)),比如一個進(jìn)程fork或clone出另一個進(jìn)程,那么這2個進(jìn)程就會存在指向相同內(nèi)存地址的指針的情況。進(jìn)程在訪問0x12345這個地址指向的內(nèi)存時,操作系統(tǒng)將這個地址轉(zhuǎn)換為物理地址,比如A進(jìn)程為0x23456,B進(jìn)程為0x34567,二者互不影響。那么這個物理地址是什么時候得來?對于進(jìn)程私有內(nèi)存(大部分情況均是如此)來說,是進(jìn)程在向操作系統(tǒng)請求分配內(nèi)存時得來。進(jìn)程向操作系統(tǒng)請求分配內(nèi)存時,操作系統(tǒng)將空閑的物理內(nèi)存以Page為單位分配給進(jìn)程,同時給進(jìn)程產(chǎn)生一個虛擬線程地址,在虛擬地址和物理內(nèi)存地址之間建立 映射關(guān)系,這個虛擬地址作為結(jié)果返回給進(jìn)程。
Page Table(頁表)就是用于操作系統(tǒng)維護(hù)進(jìn)程虛擬地址和物理內(nèi)存對應(yīng)關(guān)系的數(shù)據(jù)結(jié)構(gòu)。下圖是一個比較簡單情況下的Page Table示意圖:
下面簡單地描述在32位系統(tǒng)下,頁大小為4K時,操作系統(tǒng)是如何為進(jìn)程的虛擬地址和實(shí)際物理地址之間進(jìn)行轉(zhuǎn)換的。
1. 目錄表是用于索引頁表的數(shù)據(jù)結(jié)構(gòu),每個目錄項(xiàng)占32位,即4字節(jié),存儲一個頁表的位置。目錄表剛好占用1頁內(nèi)存,即4KB,可以存儲1024個目錄項(xiàng),也就是可以存儲1024個頁表的位置。
2. 頁表項(xiàng)(Page Table Entry)大小為4字節(jié),存儲一個物理內(nèi)存頁起始地址。每個頁表同樣占用4K內(nèi)存,可以存儲1024個物理內(nèi)存頁起始地址。由于物理內(nèi)存頁起始地址以4KB為單位對齊,所以32位中,只需要20位來表示地址,其他12位用于其他用途,比如表示這1內(nèi)存頁是只讀還是可寫等等。
3. 1024個頁表,每個頁表1024個物理內(nèi)存頁起始地址,合計(jì)就是1M個地址,每個地址指向的物理內(nèi)存頁大小為4KB,合計(jì)為4GB。
4. 操作系統(tǒng)及硬件將虛擬地址映射為物理地址時,將虛擬地址的31-22這10位用于從目錄項(xiàng)中索引到1024個頁表中的一個;將虛擬地址的12-21這10位用于從頁表中索引到1024個頁表項(xiàng)中的一個。從這個索引到的頁表項(xiàng)中得到物理內(nèi)存頁的起始地址,然后將虛擬地址的0-11這12位用作4KB內(nèi)存頁中的偏移量。那么物理內(nèi)存頁起始地址加上偏移量就是進(jìn)程所需要訪問的物理內(nèi)存的地址。
再看看目錄表和頁表這2種數(shù)據(jù)結(jié)構(gòu)占用的空間會有多少。目錄表固定只有4KB。而頁表呢?由于最多有1024個頁表,每個頁表占用4KB,因此頁表最多占用4MB內(nèi)存。
實(shí)際上32位Linux中的進(jìn)程通常不會那么大的頁表。進(jìn)程不可能用完所有的4GB大小地址空間,甚至有1GB虛擬地址空間分給了內(nèi)核。同時Linux不會為進(jìn)程一次性建立那么大的頁表,只有進(jìn)程在分配和訪問內(nèi)存時,操作系統(tǒng)才會為進(jìn)程建立相應(yīng)地址的映射。
這里只描述了最簡單情況下的分頁映射。實(shí)際上頁表目錄連同頁表一共有四級。同時在32位下啟用PAE或64位系統(tǒng),其頁表結(jié)構(gòu)比上面的示意圖更復(fù)雜。但無論怎么樣,最后一級即頁表的結(jié)構(gòu)是一致的。
在64位系統(tǒng)中,Page Table(頁表)中的頁表項(xiàng),與32位相比,大小從32位變?yōu)?4位。那么這會有多大的影響?假如一個進(jìn)程,訪問的物理內(nèi)存有1GB,即262144個內(nèi)存頁,在32位系統(tǒng)中,頁表需要262144*4/1024/1024=1MB,而在64位系統(tǒng)下,頁表占用的空間增加1倍,即為2MB。
那再看看對于Linux系統(tǒng)中運(yùn)行的Oracle數(shù)據(jù)庫,又是怎么樣一番情景。本文案例中數(shù)據(jù)庫的SGA大小12GB,如果一個OracleProcess訪問到了所有的SGA內(nèi)存,那么其頁表大小會是24MB,這是一個驚人的數(shù)字。這里忽略掉PGA,因?yàn)槠骄聛砻總€進(jìn)程的PGA不超過2M,與SGA相比實(shí)在太小。從AWR報(bào)告來看,有300個左右的會話,那么這300個連接的頁表會達(dá)到7200MB,只不過并不是每個進(jìn)程都會訪問到SGA中所有的內(nèi)存。而從meminfo查看到的Page Tables大小達(dá)到4637MB,這么大的Page Table空間,正是300個會話,SGA大小達(dá)到12GB的結(jié)果。
系統(tǒng)中顯然不會只有Page Table這唯一的內(nèi)存管理數(shù)據(jù)結(jié)構(gòu),還有其他一些數(shù)據(jù)結(jié)構(gòu)用于管理內(nèi)存。這些過大的內(nèi)存管理結(jié)構(gòu),無疑會大大增加操作系統(tǒng)內(nèi)核的負(fù)擔(dān)和對CPU的消耗。而在負(fù)載變化或其他原因?qū)е聝?nèi)存需求大幅變化,比如多進(jìn)程同時申請大量的內(nèi)存,可能引起CPU在短時間內(nèi)達(dá)到高峰,從而引起問題。
三、使用大內(nèi)存頁來解決問題
雖然沒有確實(shí)的證據(jù),也沒有足夠長的時間來收集足夠的證據(jù)來證明是過大的Page Table導(dǎo)致了問題,那需要面臨多次半小時以上的系統(tǒng)不可用故障。但是從目前來看,這是最大的可疑點(diǎn)。因此,決定先使用大內(nèi)存頁來調(diào)優(yōu)系統(tǒng)的內(nèi)存使用。
大內(nèi)存頁是一種統(tǒng)稱,在低版本的Linux中為Large Page,而當(dāng)前主流的Linux版本中為Huge Page。下面以Huge Page為例來說明Huge Page的優(yōu)點(diǎn)及如何使用。
使用大內(nèi)存頁有哪些好處:
1. 減少頁表(Page Table)大小。每一個Huge Page,對應(yīng)的是連續(xù)的2MB物理內(nèi)存,這樣12GB的物理內(nèi)存只需要48KB的Page Table,與原來的24MB相比減少很多。
2. Huge Page內(nèi)存只能鎖定在物理內(nèi)存中,不能被交換到交換區(qū)。這樣避免了交換引起的性能影響。
3. 由于頁表數(shù)量的減少,使得CPU中的TLB(可理解為CPU對頁表的CACHE)的命中率大大提高。
4. 針對Huge Page的頁表,在各進(jìn)程之間可以共享,也降低了Page Table的大小。實(shí)際上這里可以反映出Linux在分頁處理機(jī)制上的缺陷。而其他操作系統(tǒng),比如AIX,對于共享內(nèi)存段這樣的內(nèi)存,進(jìn)程共享相同的頁表,避免了Linux的這種問題。像筆者維護(hù)的一套系統(tǒng),連接數(shù)平常都是5000以上,實(shí)例的SGA在60GB左右,要是按Linux的分頁處理方式,系統(tǒng)中大部分內(nèi)存都會被頁表給用掉。
那么,怎么樣為Oracle啟用大內(nèi)存頁(Huge Page)?以下是實(shí)施步驟。由于案例中涉及的數(shù)據(jù)庫在過一段時間后將SGA調(diào)整為了18G,這里就以18G為例:
1、檢查/proc/meminfo,確認(rèn)系統(tǒng)支持HugePage:
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
Hugepagesize: 2048 kB
HugePages Total表示系統(tǒng)中配置的大內(nèi)存頁頁面數(shù)。HugePages Free表示沒有訪問過的大內(nèi)存頁面數(shù),這里free容易引起誤解,這在稍后有所解釋。HugePages Rsvd表示已經(jīng)分配但是還未使用的頁面數(shù)。Hugepagesize表示大內(nèi)存頁面大小,這里為2MB,注意在有的內(nèi)核配置中可能為4MB。
比如HugePages總計(jì)11GB,SGA_MAX_SIZE為10GB,SGA_TARGET為8GB。那么數(shù)據(jù)庫啟動后,會根據(jù)SGA_MAX_SIZE分配HugePage內(nèi)存,這里為10GB,真正Free的HugePage內(nèi)存為11-10=1G。但是SGA_TARGET只有8GB,那么會有2GB不會被訪問到,則HugePage_Free為2+1=3GB,HugePage_Rsvd內(nèi)存有2GB。這里實(shí)際上可以給其他實(shí)例使用的只有1GB,也就是真正意義上的Free只有1GB。
2. 計(jì)劃要設(shè)置的內(nèi)存頁數(shù)量。到目前為止,大內(nèi)存頁只能用于共享內(nèi)存段等少量類型 的內(nèi)存。一旦將物理內(nèi)存用作大內(nèi)存頁,那么這些物理內(nèi)存就不能用作其他用途,比如作為進(jìn)程的私有內(nèi)存。因此不能將過多的內(nèi)存設(shè)置為大內(nèi)存頁。我們通常將大內(nèi)存頁用作Oracle數(shù)據(jù)庫的SGA,那么大內(nèi)存頁數(shù)量:
HugePages_Total=ceil(SGA_MAX_SIZE/Hugepagesize)+N
比如,為數(shù)據(jù)庫設(shè)置的SGA_MAX_SIZE為18GB,那么頁面數(shù)可以為ceil(18*1024/2)+2=9218。
這里加上N,是需要將HugePage內(nèi)存空間設(shè)置得比SGA_MAX_SIZE稍大,通常為1-2即可。我們通過ipcs -m命令查看共享內(nèi)存段的大小,可以看到共享內(nèi)存段的大小實(shí)際上比SGA_MAX_SIZE約大。如果服務(wù)器上有多個Oracle實(shí)例,需要為每個實(shí)例考慮共享內(nèi)存段多出的部分,即N值會越大。另外,Oracle數(shù)據(jù)庫要么全部使用大內(nèi)存頁,要么完全不使用大內(nèi)存頁,因此不合適的HugePages_Total將造成內(nèi)存的浪費(fèi)。
除了使用SGA_MAX_SIZE計(jì)算,也可以通過ipcs -m所獲取的共享內(nèi)存段大小計(jì)算出更準(zhǔn)確的HugePages_Total。
HugePages_Total=sum(ceil(share_segment_size/Hugepagesize))
3. 修改/etc/sysctl.conf文件,增加如下行:
然后執(zhí)行sysctl –p命令,使配置生效。
這里vm.nr_hugepages這個參數(shù)值為第2步計(jì)算出的大內(nèi)存頁數(shù)量。然后檢查/proc/meminfo,如果HugePages_Total小于設(shè)置的數(shù)量,那么表明沒有足夠的連續(xù)物理內(nèi)存用于這些大內(nèi)存頁,需要重啟服務(wù)器。
4. 在/etc/security/limits.conf文件中增加如下行:
oracle soft memlock 18878464
oracle hard memlock 18878464
這里設(shè)定oracle用戶可以鎖定內(nèi)存的大小 ,以KB為單位。
然后重新以oracle用戶連接到數(shù)據(jù)庫服務(wù)器,使用ulimit -a命令,可以看到:
max lockedmemory (kbytes, -l) 18878464
這里將memlock配置為unlimited也可以。
5. 如果數(shù)據(jù)庫使用MANUAL方式管理SGA,需要改為AUTO方式,即將SGA_TARGET_SIZE設(shè)置為大于0的值。對于11g,由于HugePage只能用于共享內(nèi)存,不能用于PGA,所以不能使用AMM,即不能設(shè)置MEMORY_TARGET為大于0,只能分別設(shè)置SGA和PGA,SGA同樣只能是AUTO方式管理。
6. 最后啟動數(shù)據(jù)庫,檢查/proc/meminfo中查看HugePages_Free是否已經(jīng)減少。如果已經(jīng)減少,表明已經(jīng)使用到HugePage Memory。
不過查看出故障數(shù)據(jù)庫服務(wù)器上的/proc/meminfo時發(fā)現(xiàn),居然沒有HugePage相關(guān)的信息,sysctl -a查看所有系統(tǒng)參數(shù)也沒有找到vm.nr_hugepages這個參數(shù)。這是由于Linux內(nèi)核沒有編譯進(jìn)HugePage這個特性。我們需要使用其他的內(nèi)核來啟用HugePage。
查看/boot/grub/grub.conf:
# grub.confgenerated by anaconda
# Note thatyou do not have to rerun grub after making changes to this file
#NOTICE: You have a /boot partition. This means that
# all kerneland initrd paths are relative to /boot/, eg.
# root(hd0,0)
# kernel/vmlinuz-version ro root=/dev/VolGroup00/LogVol00
# initrd/initrd-version.img
#boot=/dev/cciss/c0d0
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Red HatEnterprise Linux Server (2.6.18-8.el5xen) with RDAC
root (hd0,0)
kernel /xen.gz-2.6.18-8.el5
module /vmlinuz-2.6.18-8.el5xen roroot=/dev/VolGroup00/LogVol00 rhgb quiet
module /mpp-2.6.18-8.el5xen.img
title Red HatEnterprise Linux Server (2.6.18-8.el5xen)
root (hd0,0)
kernel /xen.gz-2.6.18-8.el5
module /vmlinuz-2.6.18-8.el5xen roroot=/dev/VolGroup00/LogVol00 rhgb quiet
module /initrd-2.6.18-8.el5xen.img
title Red HatEnterprise Linux Server-base (2.6.18-8.el5)
root (hd0,0)
kernel /vmlinuz-2.6.18-8.el5 roroot=/dev/VolGroup00/LogVol00 rhgb quiet
module/initrd-2.6.18-8.el5.img
發(fā)現(xiàn)這個系統(tǒng)使用的內(nèi)核帶有"xen"字樣,我們修改這個文件,將default=0改為default=2,或者將前面2種內(nèi)核用#號屏蔽掉,然后重啟數(shù)據(jù)庫服務(wù)器,發(fā)現(xiàn)新的內(nèi)核已經(jīng)支持HugePage。
數(shù)據(jù)庫啟用大內(nèi)存頁之后,本文描述的性能問題甚至是在增大了SGA的情況下也沒有出現(xiàn)。觀察/proc/meminfo數(shù)據(jù),PageTables占用的內(nèi)存一直保持在120M以下,與原來相比,減少了4500MB。據(jù)觀察,CPU的利用率也較使用HugePages之前有所下降,而系統(tǒng)運(yùn)行也相當(dāng)?shù)胤€(wěn)定,至少沒有出現(xiàn)因使用HugePage而產(chǎn)生的BUG。
測試表明,對于OLTP系統(tǒng)來說,在運(yùn)行Oracle數(shù)據(jù)庫的Linux上啟用HugePage,數(shù)據(jù)庫處理能力和響應(yīng)時間均有不同程度的提高,最高甚至可以達(dá)到10%以上。
四、小結(jié)
本文以一個案例,介紹了Linux操作系統(tǒng)下大內(nèi)存頁在性能提升方面的作用,以及如何設(shè)置相應(yīng)的參數(shù)來啟用大內(nèi)存頁。在本文最后,筆者建議在Linux操作系統(tǒng)中運(yùn)行Oracle數(shù)據(jù)庫時,啟用大內(nèi)存頁來避免本文案例遇到的性能問題,或進(jìn)一步提高系統(tǒng)性能。可以說,HugePage是少數(shù)不需要額外代價(jià)就能提升性能的特性。另外值得高興的是,新版本的Linux內(nèi)核提供了Transparent Huge Pages,以便運(yùn)行在Linux上的應(yīng)用能更廣泛更方便地使用大內(nèi)存頁,而不僅僅是只有共享內(nèi)存這類內(nèi)存才能使用大內(nèi)存頁。對于這一特性引起的變化,讓我們拭目以待。
文章來源:《Oracle DBA手記 3》Linux大內(nèi)存頁Oracle數(shù)據(jù)庫優(yōu)化 作者:熊軍
配圖來源: http://2.bp.blogspot.com/-o1ihxahkl0o/VQFhFj2lHwI/AAAAAAAAAV4/egUhLwaYtmc/s1600/oracle_linux.png
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。