用好HugePage,告別Linux效能故障

lhrbest發表於2016-04-20

第一章 用好HugePage,告別Linux效能故障

DBAplus社群 | 2016-04-14 20:31

1概述

Oracle發展這麼多年,提供了多種的記憶體管理方式,從最早SGA、PGA手工管理,到9I版本出現的PGA的自動管理,到10G版本出現的SGA自動管理(ASMM),再到11G版本出現的memory自動管理(AMM),Oracle基本是在朝著智慧化、傻瓜化、自動化的方向穩步前進著,對於初學Oracle的DBA來說,看到這些不同的記憶體管理方式一定心裡有著不同程度的疑惑,例如:

Oracle有這麼多記憶體分配的管理方式,我該使用哪一種?是使用11G版本推出的AMM管理方式,還是使用10G版本出現的ASMM管理方式?或者乾脆使用最舊的手工方式管理記憶體?

我該為我的例項SGA,PGA分別設定多大呢?

我該為buffer cache,shared pool分配多大的記憶體空間?

什麼情況下我該使用大頁?為什麼大頁這個詞最近幾年這麼容易聽到?

有沒有一些簡單粗暴的演算法來搞定這一切?

寫這篇文章的初衷也來源於上面這些非常正常的疑問,如果這篇文章能給有這些疑惑的DBA朋友一些指導和幫助,那肉絲我也就真的功莫大焉了。

2Memory構成

在一個執行著Oracle資料庫的專用伺服器上,記憶體基本上被以下內容所佔用:

Kernel Memory

OS Page Table

檔案系統Cache

SGA

PGA

Oracle程式

其他程式(RMAN,非Oracle的程式等等)

wps86F5.tmp

嚴格來說OS Page Table也算是Kernel Memory部分的內容,由於本文後面會重點講大頁的內容,因此把OS Page Table這部分在圖中獨立了出來,以引起讀者注意。必須要強調,Oracle不應該使用掉主機上的所有記憶體,過量的記憶體分配會誘發作業系統SWAP的產生,導致Oracle效能嚴重降低,在RAC環境下,記憶體不足還非常容易導致RAC節點的驅逐。對於Oracle兩大塊記憶體:SGA和PGA,DBA一定要仔細根據系統特點、業務使用特點做好規劃和設計,以防出現OS記憶體不夠用的情況。

3記憶體自動化發展歷程

我們首先了解一下Oracle記憶體發展的歷程,基本上Oracle的記憶體管理在版本的演進過程中沿著越來越智慧化、自動化、傻瓜化的方向前進。接觸過MYSQL等資料庫的DBA朋友應該比較清楚,這些資料庫基本上都還需要DBA去決定每個記憶體元件的大小,而Oracle已經從9I版本開始就邁向智慧化、自動化的過程了。下圖是Oracle記憶體管理的一個演進圖:

wps8705.tmp

4PGA 自動管理

Oracle是多程式的架構,這點區別於MYSQL,MYSQL是單程式多執行緒的架構,Oracle會為每一個使用者連線建立一個獨立的作業系統程式來為使用者提供服務,這個程式叫做伺服器程式或者影子程式,它像是使用者的一個代理,來運算元據檔案或者SGA記憶體,由於伺服器程式的程式碼是Oracle公司開發的,所以Oracle公司完全相信這些程式或程式碼是安全的,因此這些程式可以直接運算元據檔案和SGA記憶體,這些程式接受使用者程式傳送的指令,並完成相關的操作,並根據需要來給使用者程式返回結果。

由於伺服器程式是作業系統上的一個程式,因此它本身需要佔用一些作業系統記憶體,除此之外,程式在對資料進行讀取、排序、hash過程中,也會佔用一定量的記憶體,在Oracle 9I版本之前,對於伺服器程式的記憶體管理是由一些引數去控制的,以下引數代表每一個伺服器程式可以使用的不同區域的記憶體大小(都是程式的私有記憶體區域):

SORT_AREA_SIZE

HASH_AREA_SIZE

BITMAP_MERGE_AREA_SIZE

CREATE_BITMAP_AREA_SIZE

例如,SORT_AREA_SIZE控制了每一個程式可用的排序區大小,HASH_AREA_SIZE引數控制了每一個程式可用的hash區大小,這些引數都有預設值,但是預設值是否合適,需要打上一個大大的問號,因為不同的任務對於PGA記憶體的不同區域有不同的要求,例如,如果是做排序操作,就對排序區記憶體要求較大,而對hash區沒任何的要求。當然如果預設值不合適,DBA可以手工調整這些區域的大小。

Oracle 9I版本出現了PGA的自動管理,不再需要像9I之前版本需要設定一系列引數來控制PGA的使用,只需要設定PGA_AGGREGATE_TARGET為一個值,就可以控制所有的伺服器程式的PGA使用量,至於每個伺服器程式使用了多少排序區,hash區,都交給Oracle去控制。

一般情況下對於PGA的大量使用有如下幾種操作:

hash 對於hash join操作,hash桶所佔用的記憶體就在程式的私有PGA記憶體中,而不是在共享記憶體SGA中,如果使用PGA手工管理的話,可以通過HASH_AREA_SIZE引數來動態調整會話進行hash操作能夠使用的記憶體量。

sort 對於排序操作,例如查詢語句裡的order by、建立索引的排序操作等佔用的記憶體也在PGA中,如果使用PGA手工管理,可以通過SORT_AREA_SIZE引數動態調整會話排序操作可以使用的記憶體量。

parallel 並行操作簡直可以說是PGA記憶體的殺手,每一個並行程式都能使用到最多2G的PGA記憶體,當然Oracle會確保所有的並行slave使用的PGA記憶體不能超過PGA_AGGREGATE_TARGET的一半。

現在Oracle的版本已經出到了12C,PGA的自動管理已經發展了很多個年頭,如果是個人,也應該是一個非常成熟的小夥子了,甚至是位大叔了,絕大部分資料庫操作完全沒必要再去手工調整PGA的一些引數。

不過,我們依然能從網際網路上、論壇上看到有很多DBA對這種手工調整PGA的技術崇拜有加(我以前也是),確實在一些情況下,通過手工調整PGA的相關記憶體區,可以達到加速排序等一些操作的目的,但是如果需要操作的資料量非常的大,那這種調整往往是費時費力,甚至是徒勞的,因為對於一個程式的私有PGA記憶體來說,像sort,hash等P區域的記憶體分配是有限制的,現在11GR2的版本對於每個程式的PGA記憶體最大限制預設是2個G,且排序區可以使用的只有1個G,如果你的排序等操作需要的記憶體遠遠不止1,2個G,那麼這種優化就非常的徒勞,甚至還可能變慢(肉絲親身遭遇過變慢的案例)。

是否使用PGA自動管理由引數WORKAREA_SIZE_POLICY控制,它的值可以為auto和manual,顧名思義,auto為PGA自動管理,manual為PGA手工管理,回到9I之前的使用方式。

這裡肉絲提供幾個大家可能會感興趣的隱含引數,比如我上面提到了每個程式最大能使用的PGA不能超過2個G,通過修改隱含引數可以突破這個限制。>肉絲在這裡警戒各位,這些引數如果要在生產環境使用,請在你的資料庫版本下做好測試(包括相同的OS及版本)。

以下為11GR2版本的情況,其他版本並未做測試:

_PGA_MAX_SIZE 每個程式的PGA的最大記憶體大小。預設值為:2147483648,2個G,單位為B。

_SMM_MAX_SIZE 每個程式的工作區的大小,預設值為1/2 _PGA_MAX_SIZE,1048576 ,單位KB,1GB,排序區、hash區都屬於工作區的範圍。64位系統下真實使用的排序區記憶體不能超過4GB。

_SMM_PX_MAX_SIZE 所有並行查詢的SLAVE程式能夠用到的PGA總量。預設值為 1/2 pga_aggregate_target,單位為KB,RAC環境下,每個節點都可以用到這麼多記憶體。

以上全部為動態引數,可以在session/system級別來線上修改。

wps8706.tmp

上面的引數調整後,一定要設定對應的pga_aggregate_target,否則以上調整可能會不起作用,建議設定為修改後的_SMM_PX_MAX_SIZE的值的兩倍。

預設情況下,每個程式使用的排序區不能超過1G。由引數_SMM_MAX_SIZE(單位KB)控制,預設為_PGA_MAX_SIZE(單位B)的一半。例如,並行度20建立索引,總共可以使用的排序區大小為20*1G=20G,但是同時還受引數_SMM_PX_MAX_SIZE的控制,所有的slave佔用的記憶體不能超過_SMM_PX_MAX_SIZE的值(單位為KB),預設為pga_aggregate_target的一半。同時64位系統下,每個程式可以使用的排序空間不能超過4個G。所以即使把_SMM_MAX_SIZE調整大於4個G也沒有用。_SMM_PX_MAX_SIZE,所有並行查詢的SLAVE程式能夠用到的PGA總量。每個RAC 節點都可以用到這麼多,限制的是本節點所有並行slave能夠消耗的PGA。

如何為PGA_AGGREGATE_TARGET設定一個合理的值?

PGA_AGGREGATE_TARGET的設定經常是一個摸索的過程,這裡給出官方的一個分配指導原則

wps8717.tmp

上面公式中的TOTAL_MEM * 80%代表著Oracle可以使用的所有記憶體為作業系統的80%,再根據不同型別業務的特點,OLTP系統,可以在此基礎上分配20%的記憶體給PGA,DSS分析型系統,可以給出剩餘記憶體的50%。這個只是一個指導的意見,具體情況要具體分析。例如,你的OLTP系統上有成千上萬個連線,那麼你可以粗略的按照每個程式佔用10M的記憶體來大體的計算一下PGA需要佔用的記憶體空間,再者,假如你的系統不但連線數非常多,而且活躍的連線數也非常的多,那麼你可以按照每個程式至少12M的記憶體來進行估算,更為重要的,系統中假如存在非常多的臨時性的計算任務,那麼要為PGA預留的記憶體就更多了。 例如,並行度設定為5建立索引,每個並行程式佔用的PGA記憶體接近1個G:

wps8718.tmp

wps8719.tmp

所以你在為系統規劃PGA記憶體時不要忘了這些臨時性任務需要佔用的記憶體。他們可能是很大的一塊哦。

該為資料庫分配多少的PGA記憶體,除了把連線數的多少這個指標作為一個考量因素外,還需要關注活躍連線數的多少,這是因為很多系統連線數雖然非常的多,但是去資料庫裡一統計發現,絕大部分的連線已經幾個小時甚至幾天都沒活躍過了,這往往是應用程式的連線池不加以管理的結果(也可能是其他原因)。對於不活躍的連線,Oracle每個程式的PGA佔用不會太大,按照10M計算是個合理安全的值。AIX下可以大一些,按照每個15M-20M計算。

這裡再提供一種估算每個空閒的伺服器程式佔用OS記憶體的方法。 首先通過作業系統命令free -m檢視一下當前OS剩餘的記憶體,69590M

wps872A.tmp

wps872B.tmp

wps872C.tmp

再次檢視剩餘的作業系統記憶體,通過沒建立連線之前的剩餘記憶體減去建立完2000個連線之後的剩餘記憶體可以估算出每個程式佔用的記憶體大約為(59332-44548)/ 2000=7M

wps873C.tmp

讀者需要牢記,減少的7M記憶體中,絕大部分都是程式本身佔用的,只有1-2M的記憶體是PGA佔用的。因此上面給大家推薦的值是10-12M,也就是給程式預留出一些PGA的記憶體來。

確認一個空閒程式佔用的真正PGA記憶體有多大,可以通過v$process檢視中PGA_ALLOC_MEM欄位來獲得,如下:只有1.49M。但是就像上面已經提到的,這個程式從作業系統層面看卻佔用了7M左右的記憶體。

wps873D.tmp

pga_aggregate_target引數指定的值並不是一個硬限制,直到Oracle 12C才提供了一個引數來強制限制PGA的使用量。如果讀者不知道該為自己系統的PGA設定一個什麼樣的值,可以通過檢視v$pgastat中的maximumPGAallocated,totalPGAallocated值作為參考,前者代表自例項啟動以來最大的PGA使用峰值,後者代表當前PGA的使用量,不過這個檢視最大的缺點是不能看到各個時間段的PGA總體使用情況,這裡肉絲給大家提供一個更好的檢視來作為參考vsysmetric_history

wps874E.tmp

上面查詢的輸出代表了各個時間段的,PGA記憶體的使用量,結果集並沒有完全列出來,讀者可以根據PGA各個時間段的使用量來更加精準的去為自己系統的PGA如何做設定做決策。設定PGA的過程是一個循序漸進的過程。再次強調,一個程式佔用的記憶體除了PGA之外,程式本身也會佔用記憶體,這點上面我們已經討論過。

按照Oracle 2015年OOW上的一份PPT提到,12C之前版本,PGA最多可用的記憶體可達到PGA_AGGREGATE_TARGET設定值的三倍,這裡你聽一下就行了,不必當真。

如果生產環境真的遭遇了PGA嚴重使用過量的情況,可以通過Event 10261 來限制某個/所有程式PGA的使用,level後面值的單位為KB。

wps874F.tmp

一旦程式超出PGA的設定配額,會被後臺程式殺掉並報錯,不同的版本可能報錯的資訊不一樣:

For 11.2.0.4 and 12.1.0.1+, ORA-10260

For 11.1 - 11.2.0.3, ORA-600 [723]

12C PGA_AGGREGATE_LIMIT

12C之前的版本對於PGA的使用限制並沒有一個硬限制,這個可能會導致一些問題,比如不加以限制後可能會導致OS SWAP的問題,一旦出現SWAP會導致Oracle效能的急劇下降,甚至導致DOWN機,我曾經遭遇過的一個案例是出現SWAP後,LGWR程式本身的記憶體出現了SWAP,資料庫系統的表現是幾乎完全HANG死,最後沒辦法只能重啟解決問題。

對於這個新特性的使用是通過引數PGA_AGGREGATE_LIMIT來限制PGA的使用上線,它是一個推導引數,在使用ASMM情況下,取以下的最大值

2GB

200% PGA_AGGREGATE_TARGET

3MB* PROCESSES

在使用AMM情況下,肉絲還未找到PGA_AGGREGATE_LIMIT取值的規律,如果你知道,請告訴我哦。

5MSMM

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

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 cache和shared pool這兩個最重要的記憶體元件分配記憶體。

Buffer Cache

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

wps8750.tmp

上面的公式格式跟PGA的公式大同小異,刨去20%記憶體給作業系統之後,分為了不同的系統型別,基本上是OLTP系統,大部分的記憶體給buffer cache,DSS類的系統,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區,用來快取SQL、PL/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_sharing為force來嘗試解決問題。

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

7ASMM

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設定為0,memory_target也為0,則迴歸到傳統的MSMM管理。通過使用ASMM可以很大程度上解決上面提到的ORA-04031的錯誤。在使用了ASMM後,去檢視spfile檔案,會發現多了一些雙下劃線打頭的記憶體引數如__db_cache_size,這些記憶體引數是Oracle例項執行過程中動態產生固化到spfile中的,如果例項執行的時間足夠長,這些引數的值被固話後,相當於有了一個基於自身環境的最佳實踐引數,資料庫例項重啟後,會沿用固化在spfile中的這些引數值。 > 11G版本即使sga_target設定為0,memory_target也設定為0,也可能會發現SGA的pool之間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_size和shared_pool_size之間高效移動,Oracle在9I版本中重新構建了SGA,也就是使用固定大小的記憶體塊-Granule,Granule會隨著作業系統、Oracle版本以及SGA大小的不同而不同,讀者可以通過如下的SQL語句來檢視當前例項的Granule的大小:

wps8751.tmp

in Oracle Database 11.2.0.2 indicates that the granule size increases from 64MB to 128MB when the SGA_TARGET parameter is set to 1 byte greater than 32G, and jumps to 256MB when the SGA_TARGET parameter is set to 1 byte greater than 64G. A granule size of 32MB is possible when the SGA_TARGET was set to a value between 8G + 1 byte to 16G.

8AMM

有了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時間足夠長,你一定遇到過下面這個錯誤

wps8752.tmp

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

wps8763.tmp

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

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

wps8764.tmp

如果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)

9大頁

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

這是因為最近幾年是Linux系統被大量普及應用的幾年,也是大記憶體遍地開花的幾年,而且現在一個資料庫系統動不動就是幾百上千個連線,這些都促成了大頁被越來越多的被關注到。

大頁的好處

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

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

pin住SGA,沒有page out

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

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

大頁的特點/缺點

要預先分配

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

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

大頁的分配方法

通過在檔案/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頁表共享,一般不用設定大頁。

大頁的原理

wps8774.tmp

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

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

頁表記憶體計算

在32位系統下,一個程式訪問1GB的記憶體,會產生1M的頁表,如果是在64位系統,將會增大到2M。 很容易推算,如果一個SGA設定為60G,有1500個Oracle使用者程式,64位Linux的系統上,最大的頁表佔用記憶體為: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檔案可以清楚的看到這一情況的發生:

wps8785.tmp

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的輸出:

wps8795.tmp

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

Transparent Hugepage

從RedHat6, RedHat7, OL6, OL7 SLES11 和 UEK2 kernels開始transparent hugepage被預設開啟,它允許大頁做動態的分配,而不是系統啟動後就分配好,根據Oracle MOS DOC:1557478.1,transparent hugepage導致了很多的問題,建議將其關閉 檢視是否啟用了transparent hugepage cat /sys/kernel/mm/transparent_hugepage/enabled [always] never []內的值是當前啟用的值,上面的輸出說明啟用了transparent hugepage。 可以通過 /etc/grub.conf 檔案來關閉transparent hugepage。

wps8796.tmp

通過增加關鍵字transparent_hugepage=never來講transparent hugepage關閉。 也可以通過開機啟動後,echo相應的值到對應的檔案來動態關閉transparent hugepage。

wps8797.tmp

OS層面檢視大頁使用情況

cat /proc/meminfo

HugePages_Total: 43000

HugePages_Free: 29493

HugePages_Rsvd: 23550

Hugepagesize: 2048 kB

HugePages_Total為所分配的頁面數目,和Hugepagesize相乘後得到所分配的記憶體大小。43000*2/1024大約為84GB。

HugePages_Free為從來沒有被使用過的Hugepages數目。即使Oracle sga已經分配了這部分記憶體,但是如果沒有實際寫入,那麼看到的還是Free的。這是很容易誤解的地方。

HugePages_Rsvd為已經被分配預留但是還沒有使用的page數目。在Oracle剛剛啟動時,大部分記憶體應該都是Reserved並且Free的,隨著Oracle SGA的使用,Reserved和Free都會不斷的降低。

HugePages_Free – HugePages_Rsvd 這部分是沒有被使用到的記憶體,如果沒有其他的Oracle instance,這部分記憶體也許永遠都不會被使用到,也就是被浪費了。在該系統上有11.5GB的記憶體被浪費了。

10最佳實踐

對於Oracle來說,這是一個最佳實踐氾濫的時代,所有的最佳實踐其實都有特定的應用場景,而不是放之四海皆準,但是當今資訊爆炸時代(資料庫種類爆炸時代),很多DBA沒有那麼多的耐心去專注學習一門資料庫,只是拿來主義從網上找出一些最佳實踐來,不管三七二十一就用到自己的環境中(甚至是生產環境中),一定程度上來說,崇拜最佳實踐是懶惰的結果。

針對於Oracle的記憶體分配方式,肉絲給大家推薦在核心繫統上:

1.使用手工的SGA管理,這種管理方式已經非常的成熟,但是這種方式對DBA要求較高,一定程度上需要了解業務特點。

2.如果第一種方法你感覺到比較難,那麼使用ASMM,但是為buffer cache,shared pool設定最小值的方式,這種方式是我非常推薦的方式。

至於AMM這種記憶體分配方式,由於不能使用大頁,建議不要去用。

具體到記憶體如何分配,針對是OLTP場景,還是OLAP場景,有著不同的記憶體分配原則,即使是OLTP場景,針對程式數的多少,併發數的多少,SQL語句的特點,都會導致產生不同的記憶體分配方法。作為DBA要掌握基本的Oracle記憶體使用原理,然後根據實際情況去根據業務自身特點分配記憶體。

不管是OLTP系統或者OLAP系統,一般都建議至少為作業系統預留出20%的記憶體空間,這些記憶體空間用於kernal、page table以及一些其他的程式需要,例如rman備份,檔案系統快取。這個也是Oracle官方的建議。

把這一部分的記憶體刨去後,針對OLTP系統,可以考慮先嚐試預留出20%的記憶體給PGA使用,80%的記憶體給SGA使用。如果系統上程式數比較多,特別是同時活躍的程式數比較多,需要給PGA預留出更多的記憶體,可以按照每個程式12M的PGA佔用進行計算。

針對OLAP系統,刨去作業系統的預留記憶體後,可以考慮預留出50%的記憶體給PGA使用,50%的記憶體給SGA使用。畢竟在純OLAP下,buffer cache其實不需要那麼大的記憶體空間。

wps87A8.tmp

SGA、PGA分配好後,要考慮到是否需要為buffer cache、shared pool來手工設定一個值,就像上文已經提到過的,可以參考buffer cache 的命中率,Library Hit的命中率作為一個輔助參考.如果命中率較低,有可能是記憶體分配的不夠合理。

當然你還需要藉助於像AWR報告這樣的工具,根據SQL的執行計劃等內容來進一步的做診斷,比如命中率低的原因可能不是分配的buffer cache小,而是存在大量的低效的全表掃描,進而導致命中率低,這樣的話,需要優化的就是SQL,而不是繼續加大buffer cache。再比如,如果你發現Library cache Hit比較低,可能並不是shared pool比較小,還可能是系統的SQL存在大量未使用繫結變數的情況,導致硬解析過重。

優化經常是個系統工程,不能一蹴而就,特別像Oracle是一個很龐大的複雜系統,對於問題的出現,更是要仔細推敲,不能輕易的下結論。隨著做DBA時間越來越長,你也會越來越懂TOM的一句話:It depends。

About Me

....................................................................................................................................................

本文來自於微信公眾號轉載文章,若有侵權,請聯絡小麥苗及時刪除

ITPUB BLOGhttp://blog.itpub.net/26736162

QQ642808185 若加QQ請註明您所正在讀的文章標題

【版權所有,文章允許轉載,但須以連結方式註明源地址,否則追究法律責任】

.................................................................................................................................................... 

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

相關文章