聊聊Oracle共享池的Duration機(jī)制
ORA-4031問(wèn)題是我們這代DBA經(jīng)常會(huì)面對(duì)的靈魂拷問(wèn)。每當(dāng)出現(xiàn)問(wèn)題,用戶都會(huì)問(wèn)幾個(gè)問(wèn)題:“為什么會(huì)出問(wèn)題?”、“問(wèn)題出在什么地方了?”、“為什么共享池還有那么多空閑,就4031了”、“下回如何避免類(lèi)似問(wèn)題發(fā)生?”?;贠racle復(fù)雜的共享池結(jié)構(gòu)和用戶千差萬(wàn)別的應(yīng)用場(chǎng)景。想要好好回答出這些問(wèn)題并不容易。對(duì)于二十多年前的那些DBA來(lái)說(shuō),ORA-4031問(wèn)題也是督促他們認(rèn)真學(xué)習(xí)Oracle Internal技術(shù)的主因之一。
Oracle的共享池從問(wèn)世開(kāi)始這幾十年來(lái),一直是十分考驗(yàn)DBA能力的存在,這涉及到Oracle內(nèi)存堆HEAP的管理(KGL)算法問(wèn)題、SQL解析問(wèn)題、SQL共享問(wèn)題、并發(fā)控制問(wèn)題等多個(gè)領(lǐng)域。共享池出問(wèn)題后分析與處理的復(fù)雜程度,如果沒(méi)有經(jīng)歷過(guò),絕對(duì)是不敢想象的。
閱讀SHARED POOL HEAP DUMP是很多那個(gè)時(shí)代DBA都必須具備的能力。共享池是Oracle解決超高并發(fā)問(wèn)題的關(guān)鍵,為了讓共享池更加高效同時(shí)管理更加簡(jiǎn)單,Oracle不斷地在優(yōu)化其算法,甚至對(duì)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)做了多次調(diào)整。從最初把LARGE POOL采用獨(dú)立的鏈表、留出獨(dú)立的空閑空間Reserved Pool用于大內(nèi)存分析,到9i開(kāi)始引入的SubPool,都是為了讓共享池更加高效并發(fā),并且盡可能少出問(wèn)題。自從10g引入了ASMM,并且服務(wù)器的物理內(nèi)存越來(lái)越便宜之后,共享池出大問(wèn)題,在業(yè)務(wù)高峰期影響業(yè)務(wù)系統(tǒng)運(yùn)行的問(wèn)題才少了很多。Oracle 11g之后,隨著共享池管理的再優(yōu)化,再加上針對(duì)cursor mutex的各種優(yōu)化,DBA才離ORA-4031更遠(yuǎn)了一些。
關(guān)于Oracle的共享池的SUBPOOL的問(wèn)題,大家討論得比較多,大多數(shù)認(rèn)真學(xué)習(xí)過(guò)OCP教材的朋友都爛熟于心了,今天不再討論。有時(shí)候共享池太大,分成了多個(gè)SUBPOOL,如果碎片化比較嚴(yán)重,那么出現(xiàn)分配較大的CHUNK的時(shí)候,就很容易出現(xiàn)ORA-4031。不過(guò)有些時(shí)候好像有些時(shí)候每個(gè)SUBPOOL里好像也有充足的空閑空間,照樣報(bào)ORA-4031,而且刷共享池都解決不了問(wèn)題,必須重啟數(shù)據(jù)庫(kù)才行。
似乎我們所掌握的知識(shí)還不足以解釋某些特殊的情況,一般遇到這種情況,我會(huì)認(rèn)為一定是有我們所還沒(méi)有掌握的一些技術(shù)細(xì)節(jié)讓我們無(wú)法繼續(xù)向下分析。今天我給大家科普一個(gè)小常識(shí),subpool下面還有一層subpool,也就是官方所說(shuō)的durations。當(dāng)Oracle數(shù)據(jù)庫(kù)啟用AMM/ASMM的時(shí)候,shared sub pool會(huì)根據(jù)預(yù)期需要的持續(xù)時(shí)間對(duì)分配的內(nèi)存進(jìn)行分類(lèi),將SUBPOOL分成4個(gè)durations。4個(gè)分區(qū)分別是:
lduration 0 (instance):實(shí)例級(jí)的永久性內(nèi)存,只有實(shí)例shutdown才會(huì)釋放。該部分內(nèi)存無(wú)法通過(guò)flush shared pool等手段釋放。包括:參數(shù)表、kgsp-heap,kglsim object batch等實(shí)例數(shù)據(jù)結(jié)構(gòu)。
lduration 1:session
lduration 2:cursor
lduration 3:execution
圖片
每個(gè)duration都是一個(gè)單獨(dú)的存儲(chǔ)桶,當(dāng)內(nèi)存分片分配給duration時(shí),該分片中的內(nèi)存不可用于子池中的任何其他duration。已經(jīng)分配給duration的分片內(nèi)存移動(dòng)到另一duration的唯一方法是根據(jù)需要將分片轉(zhuǎn)移到緩沖區(qū)緩存,然后返回共享池,不過(guò)這種情況實(shí)際上很少發(fā)生。因此分配給duration的granules通常會(huì)停留在那里。如果在較大的分片上分配較小的內(nèi)存,可能導(dǎo)致大部分空閑內(nèi)存未被使用,并且不可用于任何其他duration。這會(huì)增加共享池出現(xiàn)ORA-4031的機(jī)會(huì)。
圖片
上面是一個(gè)Oracle 11.2.0.4的shared pool heap dump,其中sga heap(1,0)表示這是SUBPOOL1的duration 0的dump。我們可以看到在這個(gè)dump中顯示duration是開(kāi)啟的。
將subpool再劃分為多個(gè)duration會(huì)加大共享池碎片化的程度。特別是當(dāng)duration 0無(wú)內(nèi)存可分配時(shí),哪怕其他duration還有很多空間,也無(wú)法再擴(kuò)充空間,此時(shí)產(chǎn)生宕機(jī)的機(jī)會(huì)很大。Oracle提供了一個(gè)隱含參數(shù)來(lái)開(kāi)啟duration,默認(rèn)情況,這個(gè)參數(shù)是true。通過(guò)設(shè)置"_enable_shared_pool_durations"=false可以關(guān)閉duration功能。不過(guò)要關(guān)閉duration要考慮清楚,因?yàn)閜erment空間可能會(huì)在關(guān)閉duration后 快速增長(zhǎng),導(dǎo)致必須重啟數(shù)據(jù)庫(kù)實(shí)例才能完全釋放。甚至有些時(shí)候需要在重啟實(shí)例前在spfile中去掉”__shared_pool_size”參數(shù),確保實(shí)例啟動(dòng)后ASMM合理分配共享池的空間。
圖片
Oracle 12.1之后,duration機(jī)制做了優(yōu)化,0,1,2三個(gè)duration被合并為一個(gè),只保留了0,3兩個(gè)duration,這樣的話出現(xiàn)因?yàn)閮?nèi)存使用不均勻而導(dǎo)致的ORA-4031被大大減少了。這個(gè)功能被backport到了11.2.0.2以后的版本中,被ORA-4031引發(fā)宕機(jī)困擾的11G用戶,可以通過(guò)打補(bǔ)丁8857940來(lái)擺脫煩惱了。
今天和大家分享了Oracle shared pool duration的一些基本概念,希望大家遇到類(lèi)似問(wèn)題的時(shí)候,這篇文章能有所幫助。其實(shí)從Oracle 共享池subpool和duration的變遷,是不是也看出一個(gè)好的數(shù)據(jù)庫(kù)產(chǎn)品不大可能被設(shè)計(jì)出來(lái),而是要在用戶場(chǎng)景中千錘百煉才能變得越來(lái)越好呢?