Oracle Memory Management and HugePage (連載二)

沃趣科技發表於2016-04-18

作者:沃趣科技高階資料庫工程師  魏興華 




MSMM



10GSGA的管理是通過手工設定一系列的引數來實現的,例如重要的引數有以下幾個:

●             buffer_cache_size

●             shared_pool_size

●             large_pool_size

●             stream_pool_size

●             log_buffer

SGA是一大塊記憶體的統稱,由上面列出的元件組成,10G之前的版本,DBA需要對SGA的各個記憶體區域進行手工設定,這可能對一個DBA無形中要求變得非常的高,需要了解業務,瞭解熱點資料量,瞭解SQL的使用方式,是否存在大量不同文字的SQL等等來決策來給每個區域分配多少記憶體。使用過這個版本的DBA基本都遭遇過一個經典的報錯:ORA-04031,一般是由於shared pool記憶體不夠導致,這個不夠的原因可能有很多,共享池記憶體的嚴重碎片化,大量的硬解析,巨大的PL/SQL文字等等都可能會導致這個問題。下面我們來看下,手工管理SGA情況下,如何考慮為buffer cacheshared pool這兩個最重要的記憶體元件分配記憶體。

Buffer Cache

Buffer Cache俗稱資料塊快取記憶體,是用來快取資料塊的拷貝的,Oracle通過改進後的LRU演算法以期待這些資料塊後續被高效的重用。伺服器程式從磁碟讀入的資料就放在這塊記憶體中,修改資料時,也是在這個區域對資料進行修改。並沒有一個給buffer cache分配記憶體的黃金法則,還是要根據作業系統的記憶體大小,業務的熱點資料量、業務的型別等因素來決定給buffer cache分配多大的記憶體大小。我們先看下如何決定整個SGA的大小,對於SGA的分配原則,官方建議如下:

上面的公式格式跟PGA的公式大同小異,刨去20%記憶體給作業系統之後,分為了不同的系統型別,基本上是OLTP系統,大部分的記憶體給buffer cacheDSS類的系統,buffer cache沒那麼重要,可以給到50%甚至更低。 至於SGA中多少可以分配給buffer_cache,要看實際情況。DBA可以通過檢視buffer cache的命中率來粗略瞭解是否給buffer cache分配了足夠的記憶體。但是熟悉我的朋友都知道,我是OWI方法論的踐行者,對於命中率的崇拜在Oracle裡已然不應該再存在,但是命中率作為一種效能診斷的輔助手段依然具有它的價值。如果系統的SQL都足夠優化後,命中率不高,一定程度上意味著可能buffer cache給小了或者你的業務訪問的資料非常的離散,熱點數量太少。這裡肉絲給出的優化思路是自頂向下,命中率低是一個表象,最上層的應用是不是呼叫了大量不需要呼叫的SQL,這些SQL是不是缺少索引,SQL都足夠優化後,DBA是不是考慮加大buffer cache來提升效能,加大之後還是不行,是不是要考慮增加系統記憶體來進一步提高buffer cache的大小,最後是不是需要為資料庫多加幾個盤或者使用SSD來提高效能。採用自頂向下的分析方法有利於真正發現問題所在而且以最低的代價解決問題,如果僅僅是一個SQL由於缺少索引而導致整個資料庫系統緩慢,DBA直接就去加盤擴容IO,那麼最終會發現花費了這麼大的代價,治標不治本,問題依然沒有解決。上面給出的公式並不適用於所有情況,特別是OLTP系統,如果程式數非常的多,那麼需要進一步降低SGA佔用記憶體的比例,以預留出更多記憶體給PGA使用。

Shared Pool

Oracle佔用量最大的兩塊記憶體除了buffer cache區就是Shared Pool的記憶體了,它的結構非常的複雜,而且由於要快取SQL程式碼這種非標準大小的文字,經常會產生大量的碎片化記憶體,shared pool總體上包含了兩大部分,一塊是library cache區,用來快取SQLPL/SQL程式碼,儲存它們的執行計劃,提高SQL的解析效率,如果你的應用程式碼從來不使用繫結變數,那麼這一塊的記憶體對你來說是一個很大的負擔,但是Oracle裡是無法關閉library cache區的,因此對於OLTP系統,請確保SQL都使用了繫結變數。第二大塊區域是row cache區,用來快取資料庫的資料字典,由於儲存在裡面的資訊是以行的形式存在,因此叫row cache。對於這一塊的記憶體,依據資料庫中元資訊(metadata)的多少而決定,如果資料庫中有幾十萬的物件,那麼這一塊的記憶體就會佔用比較大,同時表上的很多列都有直方圖資訊,也會導致這一區的記憶體佔用比較大。在一個穩定的系統中,這一區域的記憶體基本上是靜態的,Oracle中幾乎沒有操作會頻繁修改row cache區。有個例外情況是沒有cache屬性的sequence,如果這種sequence呼叫頻繁,就會觸發頻繁的修改sequence的屬性值,進而可能會產生row cache lock的一些等待,優化的辦法是為每一個sequence設定足夠的cache值。 >如果應用程式沒有使用繫結變數,而且難以修改,可以通過設定cursor_sharingforce來嘗試解決問題。

這裡肉絲再講一個親身經歷的案例,老DBA嘛,可能技能已經不多,但故事還是有的????,曾經幫一位客戶解決了一個free buffer waits的案例,這個等待事件的出現一般說明buffer cache過小,或者全表掃描、寫入操作比較多、寫髒資料比較慢,從AWR報告看,free buffer waits排在TOP EVENT的第一名,佔用的DB TIME已達到了百分之七八十,而且從awr報告中發現客戶的shared pool記憶體佔用已經達到了接近50G,而分析資料庫一個月之前的AWR報告,shared pool的記憶體只有3G左右的大小,基本上可以認定為shared pool記憶體佔用過大,而導致buffer cache不夠用,進而出現了free buffer waits等待事件,經過跟客戶溝通後知道,以前一直比較穩定,最近做過的大的變更是給資料庫使用了oracle flahcache,通過MOS上搜尋flashcache關鍵字最終發現,在11.2.0.4Oracle RAC如果使用了flash cache,那麼會在shared pool 中分配額外的記憶體存放GCS資源。多出的記憶體為:208 bytes * the total number of (flash) buffer blocks。因為這裡提醒廣大DBA朋友,如果你打算使用OracleFlashCache那麼請為它預留出足夠的shared pool記憶體。

ASMM


10G 版本Oracle推出了ASMM,自動SGA管理,它的出現一定程度上幫助DBA解決了管理SGA的問題,通過設定引數sga_target為非0值來啟用ASMM。但是在10GR1,包括10GR2的早期版本,ASMM還不夠成熟存在比較多的BUG,導致了比較多的問題,所以當時DBA在一些核心的生產環境,還是沿用了9I時候的手工SGA管理。自動SGA管理,不再需要為每個記憶體元件設定值,當然如果你設定sga_target的同時,設定了db_cache_size這些引數,那麼db_cache_size這些引數值會作為最小值要求。

如果sga_target設定為0memory_target也為0,則迴歸到傳統的MSMM管理。通過使用ASMM可以很大程度上解決上面提到的ORA-04031的錯誤。在使用了ASMM後,去檢視spfile檔案,會發現多了一些雙下劃線打頭的記憶體引數如__db_cache_size,這些記憶體引數是Oracle例項執行過程中動態產生固化到spfile中的,如果例項執行的時間足夠長,這些引數的值被固話後,相當於有了一個基於自身環境的最佳實踐引數,資料庫例項重啟後,會沿用固化在spfile中的這些引數值。 > 11G版本即使sga_target設定為0memory_target也設定為0,也可能會發現SGApool之間Granule的移動,這是11G的新Linux特性,通過引數_memory_imm_mode_without_autosga來控制。 >

Granule

ASMM技術的實現,內部是通過Granule在記憶體元件之間移動來實現。這裡對Granule做一點解釋,Oracle 10G引入的自動共享記憶體管理,目的是為了解決下面的問題,我應該把db_cache_size設定為多大?我應該把shared_pool_size設定多大?那麼10G以後,Oracle給出的答案是,你不用再考慮這個問題了,我通過演算法幫你搞定。簡單來說,就是通過比較通過增加資料塊快取減少的磁碟IO時間與通過增加共享池優化而節省的時間,通過比對,來得出是否需要在兩者間來移動記憶體。為了讓記憶體在db_cache_sizeshared_pool_size之間高效移動,Oracle9I版本中重新構建了SGA,也就是使用固定大小的記憶體塊-GranuleGranule會隨著作業系統、Oracle版本以及SGA大小的不同而不同,讀者可以通過如下的SQL語句來檢視當前例項的Granule的大小:



AMM


有了PGA的自動管理,SGA的自動管理,Oracle 這個強迫症患者終於在11G這個版本推出了AMM,自動記憶體管理,由於使用了AMM後就不能使用大頁,因此這個功能其實一直沒被廣泛使用,通過這個功能DBA只需要設定memory_target一個引數就可以完成整個資料庫例項記憶體的配置,就像ASMM導致了一些雙下劃線隱含引數的產生,AMM同樣導致了一些雙下劃線隱含引數的產生,例如:__pga_aggregate_target__sga_target。而且在11.2.0.2版本之前,DBCA建庫預設就是AMM管理(有些時候Oracle膽子真的是很大),11.2.0.3以後開始DBCA建庫時會檢測作業系統記憶體大小,大於4G記憶體預設為ASMM,小於4G記憶體預設為AMM。同樣如果你設定AMM後,也設定了SGA_TARGET等引數,那麼這些引數會作為最小值要求。

AMM最大的問題是不能使用大頁記憶體。關於使用大頁的重要性會在本文後面部分詳細介紹。 >Doc 749851.1 > > Doc 1453227.1.

11G後由於出現了AMM,如果你做DBA時間足夠長,你一定遇到過下面這個錯誤



這個錯誤給人莫名其妙的感覺,“MEMORY_TARGET特性不被支援,其實不是特性不被支援,這是由於AMM使用的是作業系統的共享記憶體檔案系統,位於/dev/shm下,如果配置的記憶體檔案系統比較小,小於了memory_target的值就會報錯,一般在Linux主流的作業系統上,這個記憶體共享檔案系統的值是記憶體大小的一半,如果讀者遭遇了這個問題,要不去調小memory_target的引數值,要不通過如下辦法去修改這個共享記憶體檔案系統的大小:



這裡指出一點,11G ASM預設會使用AMM,官方強烈建議不要修改這個預設行為。ASM裡要求MEMORY_TARGET的最小值為256M。如果設定了低於256M的值,Oracle會自動增加記憶體到256M。 對於ASM的釋出版:11.2.0.3/11.2.0.4/12.1Oracle強烈建議把memory_target設定為1536M,這個值被證明在絕大部分的環境裡都是足夠的。

使用了ASM後,資料庫例項的shared_pool記憶體需要重新評估計算,如下公式是在正常shared pool的基礎上需要額外增加的大小:



?             如果ASM磁碟組是external redundancy,需要在2MB基礎上,每100G的空間,增加1MB

?             如果ASM磁碟組是normal redundancy,需要在4MB基礎上,每50G的空間,增加1MB

?             如果ASM磁碟組是high redundancy,需要在6MB基礎上,每33G的空間,增加1MB

ASM & Shared Pool (ORA-4031) (文件 ID 437924.1)


大頁


對於類Linux系統,CPU必須把虛擬地址轉換程實體記憶體地址才能真正訪問記憶體。為了提高這個轉換效率,CPU會快取最近的虛擬記憶體地址和實體記憶體地址的對映關係,並儲存在一個由CPU維護的對映表中,為了儘量提高記憶體的訪問速度,需要在對映表中儲存儘量多的對映關係。這個對映表在Linux中每個程式都要持有一份,如果對映表太大,就會大大降低CPUTLB命中率,主流的Linux作業系統,預設頁的大小是4K,對於大記憶體來說,這會產生非常多的page table entries,上面已經提到,Linux下頁表不是共享的,每個程式都有自己的頁表,現在隨便一個主機的記憶體都配置的是幾十個G,幾百個G,甚至上T,如果在上面跑Oracle不使用大頁,基本上是找死,因為Oracle是多程式架構的,每一個連線都是一個獨佔的程式,大記憶體+多程式+不使用大頁=災難,肉絲在8年的DBA生涯裡,至少幫助不下5個客戶處理過由於沒有使用大頁而導致的系統故障,而這5個客戶都是近三四年遇到的,為什麼大頁這個詞提前個三五年並沒有被頻繁提起,而當下,大頁這個詞在各種技術大會,最佳實踐中成為熱門詞彙?這是因為最近幾年是Linux系統被大量普及應用的幾年,也是大記憶體遍地開花的幾年,而且現在一個資料庫系統動不動就是幾百上千個連線,這些都促成了大頁被越來越多的被關注到。

大頁的好處

我們來看一下使用了大頁的好處:

●               少的page table entries,減少頁表記憶體

●               pinSGA,沒有page out

●               提高TLB命中率,減少核心cpu消耗

在沒有使用大頁的系統上,經常可能會發現幾十上百G的頁表,嚴重情況下,系統CPUsys部分的消耗非常大,這些都是沒使用大頁的情況下的一些症狀。

大頁的特點/缺點

●               要預先分配

●               不夠靈活,甚至需要重啟主機

●               如果分配過多,會造成浪費,不能被其他程式使用。

大頁的分配方法

通過在檔案/etc/sysctl.cnf中增加vm.nr_hugepages引數來為大頁設定一個合理的值,值的單位為2MB。或者通過echo 一個值到/proc/sys/vm/nr_hugepages中也可以臨時性的對大頁進行設定。 至於應該為大頁設定多大的值,這個要根據系統SGA的配置來定,一般建議大頁的總佔用量大於系統上所有SGA總和+2GB

HugePages on Oracle Linux 64-bit (文件 ID 361468.1),AIX頁表共享,一般不用設定大頁。

大頁的原理



以下的內容是基於32位的系統,4K的記憶體頁大小做出的計算: 1)目錄表,用來存放頁表的位置,共包含1024個目錄entry,每個目錄entry指向一個頁表位置,每個目錄entry4b大小,目錄表共4b*1024=4K大小 2)頁表,用來存放實體地址頁的起始地址,每個頁表entry也是4b大小,每個頁表共1024個頁表entry,因此一個頁表的大小也是4K,共1024個頁表,因此頁表的最大大小是1024*4K=4M大小 3)每個頁表entry指向的是4K的實體記憶體頁,因此頁表一共可以指向的實體記憶體大小為:1024(頁表數)*1024(每個頁表的entry數)*4K(一個頁表entry代表的頁大小)=4G 4)作業系統將虛擬地址對映為實體地址時,將虛擬地址的31-2210位用於從目錄表中索引到1024個頁表中的一個,將虛擬地址的12-2110位用於從頁表中索引到1024個頁表entry中的一個。從這個頁表entry中獲得實體記憶體頁的起始地址,然後將虛擬地址的0-12位用作4KB記憶體頁中的偏移量,那麼實體記憶體頁起始地址加上偏移量就是進出所需要訪問的實體記憶體地址。

由於32位作業系統不會出現4M的頁表,因為一個程式不能使用到4GB的記憶體空間,有些空間被保留使用,比如用來做作業系統核心的記憶體。而且頁表entry的建立出現在程式訪問到一塊記憶體的時候,而不是一開始就建立。

頁表記憶體計算

32位系統下,一個程式訪問1GB的記憶體,會產生1M的頁表,如果是在64位系統,將會增大到2M。 很容易推算,如果一個SGA設定為60G,有1500Oracle使用者程式,64Linux的系統上,最大的頁表佔用記憶體為:60*2*1500/1024=175G,是的,你沒看錯,是175G!但是實際情況看到的頁表佔用可能沒有這麼大,打個百分之四五十的折扣,這是因為只有伺服器程式訪問到SGA的特定區域後,程式才需要把這一塊對應的頁表項加入到自己的頁表中。

11.2.0.3版本

11.2.0.3版本之前,如果分配的大頁數量不足,那麼Oracle啟動過程中不會使用大頁,轉而使用小頁,但是在11.2.0.3版本後,Oracle在啟動時同樣會嘗試使用大頁,如果大頁的數量不夠,那麼會把當前配置的大頁使用完,不夠的部分再從小頁中去獲取,這一行為實際上是通過Oracle的一個引數來控制USE_LARGE_PAGES,後面會對這個引數做詳細解釋。通過資料庫例項的alert檔案可以清楚的看到這一情況的發生:




Total Shared Global Region in Large Pages = 1024 MB (85%),代表只有85%SGA被放在了大頁中。RECOMMENDATION部分,建議你至少增加89個大頁來讓SGA完全放到大頁中。

USE_LARGE_PAGES

這個引數用來控制資料庫例項啟動時,對於大頁記憶體的使用行為。有3個值在11.2.0.3版本之前,11.2.0.3版本多了一個值auto

?             true 預設值,儘可能使用大頁,有可能有一些頁在大頁中,有一些在小頁中,這種情況下通過作業系統命令ipcs -ma可能會看到記憶體分段(記憶體分段可能有多重情況都會導致,例如開啟numa也可能會導致記憶體分段)

?             false 不使用大頁

?             only 選項代表強制使用大頁,否則無法啟動

?             auto 11.2.0.3)在例項啟動時,通過後臺程式dism echo xxx > /proc/sys/vm/nr_hugepages 來儘可能的使用大頁

以下程式碼為在引數設定為auto情況下alert的輸出:



可以看到啟動例項過程中,優先啟動了DISM程式,通過這個程式來自動完成大頁的配置。$Oracle_HOME/bin/oradism的許可權也是root許可權,因為如果是grid許可權不能完成大頁的配置echo xxx > /proc/sys/vm/nr_hugepages



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28218939/viewspace-2083178/,如需轉載,請註明出處,否則將追究法律責任。

相關文章