前言
PC Server發(fā)展到今天,在性能方面有著長(zhǎng)足的進(jìn)步。64位的CPU在數(shù)年前都已經(jīng)進(jìn)入到尋常的家用PC之中,更別說(shuō)是更高端的PC Server;在Intel和AMD兩大處理器巨頭的努力下,x86 CPU在處理能力上不斷提升;同時(shí)隨著制造工藝的發(fā)展,在PC Server上能夠安裝的內(nèi)存容量也越來(lái)越大,現(xiàn)在隨處可見(jiàn)數(shù)十G內(nèi)存的PC Server。正是硬件的發(fā)展,使得PC Server的處理能力越來(lái)越強(qiáng)大,性能越來(lái)越高。而在穩(wěn)定性方面,搭配PCServer和Linux操作系統(tǒng),同樣能夠滿重要業(yè)務(wù)系統(tǒng)所需要的穩(wěn)定性和可靠性。當(dāng)然在成本方面,引用一位在行業(yè)軟件廠商的網(wǎng)友的話來(lái)說(shuō),“如果不用PC Server改用小型機(jī),那我們賺什么錢(qián)???”。不管從初期的購(gòu)買(mǎi),運(yùn)行期的能耗和維護(hù)成本,PC Server都比相同處理能力的小型機(jī)便宜很多。正是在性能和成本這兩個(gè)重要因素的影響下,運(yùn)行在PC Server上的數(shù)據(jù)庫(kù)越來(lái)越多。筆者所服務(wù)的一些客戶,甚至把高端的PCServer虛擬化成多臺(tái)機(jī)器,在每臺(tái)虛擬機(jī)上跑一套Oracle數(shù)據(jù)庫(kù),這些數(shù)據(jù)庫(kù)不乏承載著重要的生產(chǎn)系統(tǒng)。
毫無(wú)疑問(wèn),在PC Server上運(yùn)行Oracle數(shù)據(jù)庫(kù),最適合的操作系統(tǒng)無(wú)疑是Linux。作為與UNIX極為類似的操作系統(tǒng),在穩(wěn)定性、可靠性和性能方面有著與UNIX同樣優(yōu)異的表現(xiàn)。但是Linux在內(nèi)存分頁(yè)處理機(jī)制上與AIX、HP-UX等操作系統(tǒng)相比有一個(gè)明顯的缺陷,而這個(gè)缺陷在使用較大SGA的Oracle數(shù)據(jù)庫(kù)上體現(xiàn)尤為明顯,嚴(yán)重時(shí)對(duì)數(shù)據(jù)庫(kù)性能有著顯著的負(fù)面影響,甚至?xí)?dǎo)致數(shù)據(jù)庫(kù)完全停止響應(yīng)。而本文就將從一個(gè)案例來(lái)詳述這種缺陷,并使用Linux下的大內(nèi)存頁(yè)來(lái)解決這一問(wèn)題。
一、案例的引入
客戶的一套系統(tǒng),出現(xiàn)了嚴(yán)重的性能問(wèn)題。在問(wèn)題出現(xiàn)時(shí),系統(tǒng)基本不可使用,應(yīng)用上所有的業(yè)務(wù)操作完全失去響應(yīng)。系統(tǒng)的數(shù)據(jù)庫(kù)是運(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ù)庫(kù)服務(wù)器的CPU長(zhǎng)期保持在100%。甚至將應(yīng)用的所有Weblogic Server都關(guān)閉之后,數(shù)據(jù)庫(kù)服務(wù)器的CPU利用率在數(shù)分鐘之內(nèi)都一直是100%,然后逐漸下降,大約需要經(jīng)過(guò)20分鐘才會(huì)下降到正常的空閑狀態(tài),因?yàn)檫@個(gè)時(shí)候所有的應(yīng)用都已經(jīng)關(guān)閉,只有非常低的CPU利用率才是正常的狀態(tài)。據(jù)這套系統(tǒng)的數(shù)據(jù)庫(kù)維護(hù)人員反映,這種情況已經(jīng)出現(xiàn)多次,就算是重啟數(shù)據(jù)庫(kù)之后,過(guò)不了一兩天,這樣的故障同樣會(huì)出現(xiàn)。同時(shí)這套系統(tǒng)最近也沒(méi)做過(guò)大的變動(dòng)。
筆者在接到接到故障報(bào)告后,通過(guò)SSH連接到數(shù)據(jù)庫(kù)數(shù)據(jù)庫(kù)都非常慢,需要差不多1分鐘才能連接上去。先簡(jiǎn)單的看一下服務(wù)器的性能狀況,發(fā)展IO極低、內(nèi)存剩余還比較多,至少還有1GB以上,也沒(méi)有page in / page out。而最顯著的現(xiàn)象就是CPU利用率相當(dāng)?shù)馗?,一直保持?00%,同時(shí)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高是分析問(wèn)題的一個(gè)重要線索。
在以最快的速度了解了一下操作系統(tǒng)層面的性能情況之后,立即通過(guò)Sqlplus連接到數(shù)據(jù)庫(kù),查看數(shù)據(jù)庫(kù)內(nèi)部的性能信息:
(注:以下數(shù)據(jù)關(guān)于SQL、服務(wù)器名稱、數(shù)據(jù)庫(kù)名稱等相關(guān)信息經(jīng)過(guò)處理。)
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ù)庫(kù)中的活動(dòng)以及等待事件來(lái)看,并沒(méi)有太大的異常。值得注意的是,在數(shù)據(jù)庫(kù)服務(wù)器CPU利用率長(zhǎng)期在100%,或物理內(nèi)存耗盡并伴有大量的交換內(nèi)存換入換出時(shí),需要仔細(xì)地診斷數(shù)據(jù)庫(kù)中的性能現(xiàn)象,比如某類較多的等待事件,是由CPU或內(nèi)存不足導(dǎo)致的結(jié)果還是因?yàn)檫@些數(shù)據(jù)庫(kù)中的特定的活動(dòng)才是Root Cause引起CPU過(guò)高或內(nèi)存耗盡。
從上面的數(shù)據(jù)來(lái)看,活動(dòng)會(huì)話并不是特別多,不到50個(gè),加上后臺(tái)進(jìn)程的數(shù)量,與操作系統(tǒng)中高達(dá)200的運(yùn)行相比,存在不小的差異。數(shù)據(jù)庫(kù)中主要有三類的非空閑等待事件,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這類等待事件才會(huì)引起CPU的利用率增加。
通過(guò)分析對(duì)比AWR報(bào)告,在故障期間和正常期間,從數(shù)據(jù)庫(kù)活動(dòng)來(lái)說(shuō),沒(méi)有特別明顯的差異。但是在系統(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ù)中,是來(lái)自于包含故障時(shí)間段的1小時(shí)(1st)和正常時(shí)間段1小時(shí)(2nd)的AWR的對(duì)比數(shù)據(jù)。對(duì)于故障分析來(lái)說(shuō),特別是故障時(shí)間比較短的情況下,1小時(shí)的AWR報(bào)告會(huì)不夠準(zhǔn)確地反映故障期間的性能情況。但是我們?cè)赥rouble Shooting之時(shí),首要的是需要從各種數(shù)據(jù)中,確定方向。正如前面提到,SYS部分的CPU利用率過(guò)高是一個(gè)很重要的線索,而數(shù)據(jù)庫(kù)內(nèi)部的其他性能數(shù)據(jù)相差不大的情況下,可以先從CPU這一點(diǎn)著手。
二、操作系統(tǒng)中CPU使用分析
那么,在操作系統(tǒng)中,SYS和USER這兩個(gè)不同的利用率代表著什么?或者說(shuō)二者有什么區(qū)別?
簡(jiǎn)單來(lái)說(shuō),CPU利用率中的SYS部分,指的是操作系統(tǒng)內(nèi)核(Kernel)使用的CPU部分,也就是運(yùn)行在內(nèi)核態(tài)的代碼所消耗的CPU,最常見(jiàn)的就是系統(tǒng)調(diào)用(SYS CALL)時(shí)消耗的CPU。而USER部分則是應(yīng)用軟件自己的代碼使用的CPU部分,也就是運(yùn)行在用戶態(tài)的代碼所消耗的CPU。比如Oracle在執(zhí)行SQL時(shí),從磁盤(pán)讀數(shù)據(jù)到db buffer cache,需要發(fā)起read調(diào)用,這個(gè)read調(diào)用主要是由操作系統(tǒng)內(nèi)核包括設(shè)備驅(qū)動(dòng)程序的代碼在運(yùn)行,因此消耗的CPU計(jì)算到SYS部分;而Oracle在解析從磁盤(pán)中讀到的數(shù)據(jù)時(shí),則只是Oracle自己的代碼在運(yùn)行,因此消耗的CPU計(jì)算到USER部分。
那么SYS部分的CPU主要會(huì)由哪些操作或是系統(tǒng)調(diào)用產(chǎn)生呢:
1. I/O操作,比如讀寫(xiě)文件、訪問(wèn)外設(shè)、通過(guò)網(wǎng)絡(luò)傳輸數(shù)據(jù)等。這部分操作一般不會(huì)消耗太多的CPU,因?yàn)橹饕臅r(shí)間消耗會(huì)在IO操作的設(shè)備上。比如從磁盤(pán)讀文件時(shí),主要的時(shí)間在磁盤(pán)內(nèi)部的操作上,而消耗的CPU時(shí)間只占I/O操作響應(yīng)時(shí)間的少部分。只有在過(guò)高的并發(fā)I/O時(shí)才可能會(huì)使SYS CPU有所增加。
2. 內(nèi)存管理,比如應(yīng)用進(jìn)程向操作系統(tǒng)申請(qǐng)內(nèi)存,操作系統(tǒng)維護(hù)系統(tǒng)可用內(nèi)存,交換空間換頁(yè)等。其實(shí)與Oracle類似,越大的內(nèi)存,越頻繁的內(nèi)存管理操作,CPU的消耗會(huì)越高。
3. 進(jìn)程調(diào)度。這部分CPU的使用,在于操作系統(tǒng)中運(yùn)行隊(duì)列的長(zhǎng)短,越長(zhǎng)的運(yùn)行隊(duì)列,表明越多的進(jìn)程需要調(diào)度,那么內(nèi)核的負(fù)擔(dān)也就越高。
4. 其他,包括進(jìn)程間通信、信號(hào)量處理、設(shè)備驅(qū)動(dòng)程序內(nèi)部一些活動(dòng)等等。
從系統(tǒng)故障時(shí)的性能數(shù)據(jù)來(lái)看,內(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ù)庫(kù)里面來(lái)看活動(dòng)會(huì)話數(shù)不是特別高。那么接下來(lái),需要關(guān)注是否是由于系統(tǒng)內(nèi)存管理方面的問(wèn)題導(dǎo)致了CPU利用率過(guò)高?
回顧本文開(kāi)始部分收集的/proc/meminfo中系統(tǒng)內(nèi)存方面數(shù)據(jù),可以發(fā)現(xiàn)一項(xiàng)重要的數(shù)據(jù):
從數(shù)據(jù)可以看到,PageTables內(nèi)存達(dá)到了4637MB。PageTables在字面意思上是指“頁(yè)面表”。簡(jiǎn)單地說(shuō),就是操作系統(tǒng)內(nèi)核用于維護(hù)進(jìn)程線性虛擬地址和實(shí)際物理內(nèi)存地址對(duì)應(yīng)關(guān)系的表格。
現(xiàn)代計(jì)算機(jī)對(duì)于物理內(nèi)存,通常是將其以頁(yè)(Page Frame)為單位進(jìn)行管理和分配,在 x86處理器架構(gòu)上,頁(yè)面大小為4K。運(yùn)行在操作系統(tǒng)上的進(jìn)程,可訪問(wèn)的地址空間稱為虛地址空間,跟處理器位數(shù)有關(guān)。對(duì)于32位的x86處理器,進(jìn)程的可訪問(wèn)地址空間為4GB。在操作系統(tǒng)中運(yùn)行的每一個(gè)進(jìn)程,都有其獨(dú)立的虛地址空間或線性地址空間,而這個(gè)地址空間同樣也是按頁(yè)(Page)進(jìn)行管理,在Linux中,頁(yè)大小通常為4KB。進(jìn)程在訪問(wèn)內(nèi)存時(shí),由操作系統(tǒng)和硬件配合,負(fù)責(zé)將進(jìn)程的虛擬地址轉(zhuǎn)換成為物理地址。兩個(gè)不同的進(jìn)程,其相同的虛擬線性地址,指向的物理內(nèi)存,可能相同,比如共享內(nèi)存;也可能不同,比如進(jìn)程的私有內(nèi)存。
下圖是關(guān)于虛擬地址和物理內(nèi)存對(duì)應(yīng)關(guān)系的示意圖:
假設(shè)有兩個(gè)進(jìn)程A、B,分別有一個(gè)內(nèi)存指針指向的地址為0x12345(0x表示16進(jìn)制數(shù)),比如一個(gè)進(jìn)程fork或clone出另一個(gè)進(jìn)程,那么這2個(gè)進(jìn)程就會(huì)存在指向相同內(nèi)存地址的指針的情況。進(jìn)程在訪問(wèn)0x12345這個(gè)地址指向的內(nèi)存時(shí),操作系統(tǒng)將這個(gè)地址轉(zhuǎn)換為物理地址,比如A進(jìn)程為0x23456,B進(jìn)程為0x34567,二者互不影響。那么這個(gè)物理地址是什么時(shí)候得來(lái)?對(duì)于進(jìn)程私有內(nèi)存(大部分情況均是如此)來(lái)說(shuō),是進(jìn)程在向操作系統(tǒng)請(qǐng)求分配內(nèi)存時(shí)得來(lái)。進(jìn)程向操作系統(tǒng)請(qǐng)求分配內(nèi)存時(shí),操作系統(tǒng)將空閑的物理內(nèi)存以Page為單位分配給進(jìn)程,同時(shí)給進(jìn)程產(chǎn)生一個(gè)虛擬線程地址,在虛擬地址和物理內(nèi)存地址之間建立 映射關(guān)系,這個(gè)虛擬地址作為結(jié)果返回給進(jìn)程。
Page Table(頁(yè)表)就是用于操作系統(tǒng)維護(hù)進(jìn)程虛擬地址和物理內(nèi)存對(duì)應(yīng)關(guān)系的數(shù)據(jù)結(jié)構(gòu)。下圖是一個(gè)比較簡(jiǎn)單情況下的Page Table示意圖:
下面簡(jiǎn)單地描述在32位系統(tǒng)下,頁(yè)大小為4K時(shí),操作系統(tǒng)是如何為進(jìn)程的虛擬地址和實(shí)際物理地址之間進(jìn)行轉(zhuǎn)換的。
1. 目錄表是用于索引頁(yè)表的數(shù)據(jù)結(jié)構(gòu),每個(gè)目錄項(xiàng)占32位,即4字節(jié),存儲(chǔ)一個(gè)頁(yè)表的位置。目錄表剛好占用1頁(yè)內(nèi)存,即4KB,可以存儲(chǔ)1024個(gè)目錄項(xiàng),也就是可以存儲(chǔ)1024個(gè)頁(yè)表的位置。
2. 頁(yè)表項(xiàng)(Page Table Entry)大小為4字節(jié),存儲(chǔ)一個(gè)物理內(nèi)存頁(yè)起始地址。每個(gè)頁(yè)表同樣占用4K內(nèi)存,可以存儲(chǔ)1024個(gè)物理內(nèi)存頁(yè)起始地址。由于物理內(nèi)存頁(yè)起始地址以4KB為單位對(duì)齊,所以32位中,只需要20位來(lái)表示地址,其他12位用于其他用途,比如表示這1內(nèi)存頁(yè)是只讀還是可寫(xiě)等等。
3. 1024個(gè)頁(yè)表,每個(gè)頁(yè)表1024個(gè)物理內(nèi)存頁(yè)起始地址,合計(jì)就是1M個(gè)地址,每個(gè)地址指向的物理內(nèi)存頁(yè)大小為4KB,合計(jì)為4GB。
4. 操作系統(tǒng)及硬件將虛擬地址映射為物理地址時(shí),將虛擬地址的31-22這10位用于從目錄項(xiàng)中索引到1024個(gè)頁(yè)表中的一個(gè);將虛擬地址的12-21這10位用于從頁(yè)表中索引到1024個(gè)頁(yè)表項(xiàng)中的一個(gè)。從這個(gè)索引到的頁(yè)表項(xiàng)中得到物理內(nèi)存頁(yè)的起始地址,然后將虛擬地址的0-11這12位用作4KB內(nèi)存頁(yè)中的偏移量。那么物理內(nèi)存頁(yè)起始地址加上偏移量就是進(jìn)程所需要訪問(wèn)的物理內(nèi)存的地址。
再看看目錄表和頁(yè)表這2種數(shù)據(jù)結(jié)構(gòu)占用的空間會(huì)有多少。目錄表固定只有4KB。而頁(yè)表呢?由于最多有1024個(gè)頁(yè)表,每個(gè)頁(yè)表占用4KB,因此頁(yè)表最多占用4MB內(nèi)存。
實(shí)際上32位Linux中的進(jìn)程通常不會(huì)那么大的頁(yè)表。進(jìn)程不可能用完所有的4GB大小地址空間,甚至有1GB虛擬地址空間分給了內(nèi)核。同時(shí)Linux不會(huì)為進(jìn)程一次性建立那么大的頁(yè)表,只有進(jìn)程在分配和訪問(wèn)內(nèi)存時(shí),操作系統(tǒng)才會(huì)為進(jìn)程建立相應(yīng)地址的映射。
這里只描述了最簡(jiǎn)單情況下的分頁(yè)映射。實(shí)際上頁(yè)表目錄連同頁(yè)表一共有四級(jí)。同時(shí)在32位下啟用PAE或64位系統(tǒng),其頁(yè)表結(jié)構(gòu)比上面的示意圖更復(fù)雜。但無(wú)論怎么樣,最后一級(jí)即頁(yè)表的結(jié)構(gòu)是一致的。
在64位系統(tǒng)中,Page Table(頁(yè)表)中的頁(yè)表項(xiàng),與32位相比,大小從32位變?yōu)?4位。那么這會(huì)有多大的影響?假如一個(gè)進(jìn)程,訪問(wèn)的物理內(nèi)存有1GB,即262144個(gè)內(nèi)存頁(yè),在32位系統(tǒng)中,頁(yè)表需要262144*4/1024/1024=1MB,而在64位系統(tǒng)下,頁(yè)表占用的空間增加1倍,即為2MB。
那再看看對(duì)于Linux系統(tǒng)中運(yùn)行的Oracle數(shù)據(jù)庫(kù),又是怎么樣一番情景。本文案例中數(shù)據(jù)庫(kù)的SGA大小12GB,如果一個(gè)OracleProcess訪問(wèn)到了所有的SGA內(nèi)存,那么其頁(yè)表大小會(huì)是24MB,這是一個(gè)驚人的數(shù)字。這里忽略掉PGA,因?yàn)槠骄聛?lái)每個(gè)進(jìn)程的PGA不超過(guò)2M,與SGA相比實(shí)在太小。從AWR報(bào)告來(lái)看,有300個(gè)左右的會(huì)話,那么這300個(gè)連接的頁(yè)表會(huì)達(dá)到7200MB,只不過(guò)并不是每個(gè)進(jìn)程都會(huì)訪問(wèn)到SGA中所有的內(nèi)存。而從meminfo查看到的Page Tables大小達(dá)到4637MB,這么大的Page Table空間,正是300個(gè)會(huì)話,SGA大小達(dá)到12GB的結(jié)果。
系統(tǒng)中顯然不會(huì)只有Page Table這唯一的內(nèi)存管理數(shù)據(jù)結(jié)構(gòu),還有其他一些數(shù)據(jù)結(jié)構(gòu)用于管理內(nèi)存。這些過(guò)大的內(nèi)存管理結(jié)構(gòu),無(wú)疑會(huì)大大增加操作系統(tǒng)內(nèi)核的負(fù)擔(dān)和對(duì)CPU的消耗。而在負(fù)載變化或其他原因?qū)е聝?nèi)存需求大幅變化,比如多進(jìn)程同時(shí)申請(qǐng)大量的內(nèi)存,可能引起CPU在短時(shí)間內(nèi)達(dá)到高峰,從而引起問(wèn)題。
三、使用大內(nèi)存頁(yè)來(lái)解決問(wèn)題
雖然沒(méi)有確實(shí)的證據(jù),也沒(méi)有足夠長(zhǎng)的時(shí)間來(lái)收集足夠的證據(jù)來(lái)證明是過(guò)大的Page Table導(dǎo)致了問(wèn)題,那需要面臨多次半小時(shí)以上的系統(tǒng)不可用故障。但是從目前來(lái)看,這是最大的可疑點(diǎn)。因此,決定先使用大內(nèi)存頁(yè)來(lái)調(diào)優(yōu)系統(tǒng)的內(nèi)存使用。
大內(nèi)存頁(yè)是一種統(tǒng)稱,在低版本的Linux中為L(zhǎng)arge Page,而當(dāng)前主流的Linux版本中為Huge Page。下面以Huge Page為例來(lái)說(shuō)明Huge Page的優(yōu)點(diǎn)及如何使用。
使用大內(nèi)存頁(yè)有哪些好處:
1. 減少頁(yè)表(Page Table)大小。每一個(gè)Huge Page,對(duì)應(yīng)的是連續(xù)的2MB物理內(nèi)存,這樣12GB的物理內(nèi)存只需要48KB的Page Table,與原來(lái)的24MB相比減少很多。
2. Huge Page內(nèi)存只能鎖定在物理內(nèi)存中,不能被交換到交換區(qū)。這樣避免了交換引起的性能影響。
3. 由于頁(yè)表數(shù)量的減少,使得CPU中的TLB(可理解為CPU對(duì)頁(yè)表的CACHE)的命中率大大提高。
4. 針對(duì)Huge Page的頁(yè)表,在各進(jìn)程之間可以共享,也降低了Page Table的大小。實(shí)際上這里可以反映出Linux在分頁(yè)處理機(jī)制上的缺陷。而其他操作系統(tǒng),比如AIX,對(duì)于共享內(nèi)存段這樣的內(nèi)存,進(jìn)程共享相同的頁(yè)表,避免了Linux的這種問(wèn)題。像筆者維護(hù)的一套系統(tǒng),連接數(shù)平常都是5000以上,實(shí)例的SGA在60GB左右,要是按Linux的分頁(yè)處理方式,系統(tǒng)中大部分內(nèi)存都會(huì)被頁(yè)表給用掉。
那么,怎么樣為Oracle啟用大內(nèi)存頁(yè)(Huge Page)?以下是實(shí)施步驟。由于案例中涉及的數(shù)據(jù)庫(kù)在過(guò)一段時(shí)間后將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)存頁(yè)頁(yè)面數(shù)。HugePages Free表示沒(méi)有訪問(wèn)過(guò)的大內(nèi)存頁(yè)面數(shù),這里free容易引起誤解,這在稍后有所解釋。HugePages Rsvd表示已經(jīng)分配但是還未使用的頁(yè)面數(shù)。Hugepagesize表示大內(nèi)存頁(yè)面大小,這里為2MB,注意在有的內(nèi)核配置中可能為4MB。
比如HugePages總計(jì)11GB,SGA_MAX_SIZE為10GB,SGA_TARGET為8GB。那么數(shù)據(jù)庫(kù)啟動(dòng)后,會(huì)根據(jù)SGA_MAX_SIZE分配HugePage內(nèi)存,這里為10GB,真正Free的HugePage內(nèi)存為11-10=1G。但是SGA_TARGET只有8GB,那么會(huì)有2GB不會(huì)被訪問(wèn)到,則HugePage_Free為2+1=3GB,HugePage_Rsvd內(nèi)存有2GB。這里實(shí)際上可以給其他實(shí)例使用的只有1GB,也就是真正意義上的Free只有1GB。
2. 計(jì)劃要設(shè)置的內(nèi)存頁(yè)數(shù)量。到目前為止,大內(nèi)存頁(yè)只能用于共享內(nèi)存段等少量類型 的內(nèi)存。一旦將物理內(nèi)存用作大內(nèi)存頁(yè),那么這些物理內(nèi)存就不能用作其他用途,比如作為進(jìn)程的私有內(nèi)存。因此不能將過(guò)多的內(nèi)存設(shè)置為大內(nèi)存頁(yè)。我們通常將大內(nèi)存頁(yè)用作Oracle數(shù)據(jù)庫(kù)的SGA,那么大內(nèi)存頁(yè)數(shù)量:
HugePages_Total=ceil(SGA_MAX_SIZE/Hugepagesize)+N
比如,為數(shù)據(jù)庫(kù)設(shè)置的SGA_MAX_SIZE為18GB,那么頁(yè)面數(shù)可以為ceil(18*1024/2)+2=9218。
這里加上N,是需要將HugePage內(nèi)存空間設(shè)置得比SGA_MAX_SIZE稍大,通常為1-2即可。我們通過(guò)ipcs -m命令查看共享內(nèi)存段的大小,可以看到共享內(nèi)存段的大小實(shí)際上比SGA_MAX_SIZE約大。如果服務(wù)器上有多個(gè)Oracle實(shí)例,需要為每個(gè)實(shí)例考慮共享內(nèi)存段多出的部分,即N值會(huì)越大。另外,Oracle數(shù)據(jù)庫(kù)要么全部使用大內(nèi)存頁(yè),要么完全不使用大內(nèi)存頁(yè),因此不合適的HugePages_Total將造成內(nèi)存的浪費(fèi)。
除了使用SGA_MAX_SIZE計(jì)算,也可以通過(guò)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這個(gè)參數(shù)值為第2步計(jì)算出的大內(nèi)存頁(yè)數(shù)量。然后檢查/proc/meminfo,如果HugePages_Total小于設(shè)置的數(shù)量,那么表明沒(méi)有足夠的連續(xù)物理內(nèi)存用于這些大內(nèi)存頁(yè),需要重啟服務(wù)器。
4. 在/etc/security/limits.conf文件中增加如下行:
oracle soft memlock 18878464
oracle hard memlock 18878464
這里設(shè)定oracle用戶可以鎖定內(nèi)存的大小 ,以KB為單位。
然后重新以oracle用戶連接到數(shù)據(jù)庫(kù)服務(wù)器,使用ulimit -a命令,可以看到:
max lockedmemory (kbytes, -l) 18878464
這里將memlock配置為unlimited也可以。
5. 如果數(shù)據(jù)庫(kù)使用MANUAL方式管理SGA,需要改為AUTO方式,即將SGA_TARGET_SIZE設(shè)置為大于0的值。對(duì)于11g,由于HugePage只能用于共享內(nèi)存,不能用于PGA,所以不能使用AMM,即不能設(shè)置MEMORY_TARGET為大于0,只能分別設(shè)置SGA和PGA,SGA同樣只能是AUTO方式管理。
6. 最后啟動(dòng)數(shù)據(jù)庫(kù),檢查/proc/meminfo中查看HugePages_Free是否已經(jīng)減少。如果已經(jīng)減少,表明已經(jīng)使用到HugePage Memory。
不過(guò)查看出故障數(shù)據(jù)庫(kù)服務(wù)器上的/proc/meminfo時(shí)發(fā)現(xiàn),居然沒(méi)有HugePage相關(guān)的信息,sysctl -a查看所有系統(tǒng)參數(shù)也沒(méi)有找到vm.nr_hugepages這個(gè)參數(shù)。這是由于Linux內(nèi)核沒(méi)有編譯進(jìn)HugePage這個(gè)特性。我們需要使用其他的內(nèi)核來(lá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)這個(gè)系統(tǒng)使用的內(nèi)核帶有"xen"字樣,我們修改這個(gè)文件,將default=0改為default=2,或者將前面2種內(nèi)核用#號(hào)屏蔽掉,然后重啟數(shù)據(jù)庫(kù)服務(wù)器,發(fā)現(xiàn)新的內(nèi)核已經(jīng)支持HugePage。
數(shù)據(jù)庫(kù)啟用大內(nèi)存頁(yè)之后,本文描述的性能問(wèn)題甚至是在增大了SGA的情況下也沒(méi)有出現(xiàn)。觀察/proc/meminfo數(shù)據(jù),PageTables占用的內(nèi)存一直保持在120M以下,與原來(lái)相比,減少了4500MB。據(jù)觀察,CPU的利用率也較使用HugePages之前有所下降,而系統(tǒng)運(yùn)行也相當(dāng)?shù)胤€(wěn)定,至少?zèng)]有出現(xiàn)因使用HugePage而產(chǎn)生的BUG。
測(cè)試表明,對(duì)于OLTP系統(tǒng)來(lái)說(shuō),在運(yùn)行Oracle數(shù)據(jù)庫(kù)的Linux上啟用HugePage,數(shù)據(jù)庫(kù)處理能力和響應(yīng)時(shí)間均有不同程度的提高,最高甚至可以達(dá)到10%以上。
四、小結(jié)
本文以一個(gè)案例,介紹了Linux操作系統(tǒng)下大內(nèi)存頁(yè)在性能提升方面的作用,以及如何設(shè)置相應(yīng)的參數(shù)來(lái)啟用大內(nèi)存頁(yè)。在本文最后,筆者建議在Linux操作系統(tǒng)中運(yùn)行Oracle數(shù)據(jù)庫(kù)時(shí),啟用大內(nèi)存頁(yè)來(lái)避免本文案例遇到的性能問(wèn)題,或進(jìn)一步提高系統(tǒng)性能??梢哉f(shuō),HugePage是少數(shù)不需要額外代價(jià)就能提升性能的特性。另外值得高興的是,新版本的Linux內(nèi)核提供了Transparent Huge Pages,以便運(yùn)行在Linux上的應(yīng)用能更廣泛更方便地使用大內(nèi)存頁(yè),而不僅僅是只有共享內(nèi)存這類內(nèi)存才能使用大內(nèi)存頁(yè)。對(duì)于這一特性引起的變化,讓我們拭目以待。
文章來(lái)源:《Oracle DBA手記 3》Linux大內(nèi)存頁(yè)Oracle數(shù)據(jù)庫(kù)優(yōu)化 作者:熊軍
配圖來(lái)源: http://2.bp.blogspot.com/-o1ihxahkl0o/VQFhFj2lHwI/AAAAAAAAAV4/egUhLwaYtmc/s1600/oracle_linux.png
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。