[Oracle10G新特性]_17.自動(dòng)共享內(nèi)存管理
?
??? 關(guān)于Orace的內(nèi)存管理,之前了解過一些基礎(chǔ)的概念,但是對(duì)于具體如何分配這個(gè)層面,倒還真是沒有了解過,這篇文章只是簡單得講了一下SGA的分配,不過對(duì)于理解Oracle的內(nèi)部工作機(jī)制還是很有益處的。至少可以知道如何啟用或者關(guān)閉Oracle的自動(dòng)內(nèi)存管理。
?
??? 不過對(duì)于這方面的需求,關(guān)鍵還是要知道到底各個(gè)pool的工作機(jī)制,以及實(shí)際所需要的大小預(yù)計(jì)是多少,這些才是關(guān)鍵所在,需要有深刻的理解才可以。
?
------------------------------------------------------------------------------
?
自動(dòng)共享內(nèi)存管理
?
是不是很難準(zhǔn)確地分配不同的池所需的內(nèi)存數(shù)?自動(dòng)共享內(nèi)存管理特性使得自動(dòng)將內(nèi)存分配到最需要的地方去成為可能。
?
??? 無論您是一個(gè)剛?cè)腴T的 DBA 還是一個(gè)經(jīng)驗(yàn)豐富的 DBA,您肯定至少看到過一次類似以下的錯(cuò)誤:
?
ORA-04031:unable to allocate 2216 bytes of shared memory ("shared pool"... ...
?
??? 或者這種錯(cuò)誤:
?
ORA-04031:unable to allocate XXXX bytes of shared memory
("large pool","unknown object","session heap","frame")
("large pool","unknown object","session heap","frame")
?
??? 或者可能這種錯(cuò)誤:
?
ORA-04031:unable to allocate bytes of shared memory ("shared pool",
"unknown object","joxlod:init h", "JOX:ioc_allocate_pal")
"unknown object","joxlod:init h", "JOX:ioc_allocate_pal")
?
??? 第一種錯(cuò)誤的原因很明顯:分配給共享池的內(nèi)存不足以滿足用戶請(qǐng)求。(在某些情況下,原因可能不是池本身的大小,而是未使用綁定變量導(dǎo)致的過多分析造成的碎片,這是我很喜歡的一個(gè)主題;但目前讓我們把重點(diǎn)放在手頭的問題上。)其它的錯(cuò)誤分別來自大型池和 Java 池的空間不足。
?
??? 您需要解決這些錯(cuò)誤情況,而不作任何與應(yīng)用程序相關(guān)的修改。那么有哪些方案可選呢?問題是如何在 Oracle 例程所需的所有池之間劃分可用的內(nèi)存。
?
?
餡餅怎么分?
?
??? 正如您所了解的,一個(gè) Oracle 例程的系統(tǒng)全局區(qū)域 (SGA) 包含幾個(gè)內(nèi)存區(qū)域(包括緩沖高速緩存、共享池、Java 池、大型池和重做日志緩沖)。這些池在操作系統(tǒng)的內(nèi)存空間中占據(jù)了固定的內(nèi)存數(shù);它們的大小由 DBA 在初始化參數(shù)文件中指定。
?
??? 這四個(gè)池(數(shù)據(jù)庫塊緩沖高速緩存、共享池、Java 池和大型池)幾乎占據(jù)了 SGA 中所有的空間。(與其它區(qū)域相比,重做日志緩沖沒有占據(jù)多少空間,對(duì)我們這里的討論無關(guān)緊要。)作為 DBA,您必須確保它們各自的內(nèi)存分配是充足的。
?
??? 假定您決定了這些池的值分別是 2GB、1GB、1GB 和 1GB。您將設(shè)置以下初始化參數(shù)來為數(shù)據(jù)庫例程規(guī)定池的大小。
?
db_cache_size = 2g
shared_pool_size = 1g
large_pool_size = 1g
java_pool_size = 1g
shared_pool_size = 1g
large_pool_size = 1g
java_pool_size = 1g
?
??? 現(xiàn)在,仔細(xì)看一下這些參數(shù)。坦白講,這些值是否準(zhǔn)確?
?
??? 我相信您一定會(huì)有疑慮。在實(shí)際中,沒有人能夠?yàn)檫@些池指定確切的內(nèi)存數(shù) — 它們太依賴于數(shù)據(jù)庫內(nèi)部的處理,而處理的特性隨時(shí)在變化。
?
??? 下面是一個(gè)示例場景。假定您有一個(gè)典型的、大部分屬于 OLTP 的數(shù)據(jù)庫,并且為緩沖高速緩存分配的專用內(nèi)存比為純 OLTP 數(shù)據(jù)庫(現(xiàn)在已經(jīng)很少見了)分配的要少。有一天,您的用戶放開了一些非常大的全表掃描,以創(chuàng)建當(dāng)天的結(jié)束報(bào)表。Oracle9i 數(shù)據(jù)庫為您提供了在線修改內(nèi)存分配的功能,但由于提供的總物理內(nèi)存有限,您決定從大型池和 Java 池中取出一些內(nèi)存:
?
alter system set db_cache_size = 3g scope=memory;
alter system set large_pool_size = 512m scope=memory;
alter system set java_pool_size = 512m scope=memory;
alter system set large_pool_size = 512m scope=memory;
alter system set java_pool_size = 512m scope=memory;
?
??? 這個(gè)解決方案能夠很好地工作一段時(shí)間,但是接著夜間的 RMAN 作業(yè)(它們使用大型池)開始了,大型池將立即出現(xiàn)內(nèi)存不足。同樣,您從數(shù)據(jù)庫高速緩存中取出一些內(nèi)存來補(bǔ)充大型池,以挽救這種局面。
?
??? RMAN 作業(yè)完成,然后啟動(dòng)一個(gè)廣泛使用 Java 的批處理程序,接著您開始看到與 Java 池相關(guān)的錯(cuò)誤。因此,您(再次)重新分配池,以滿足 Java 池和數(shù)據(jù)庫高速緩存上的內(nèi)存需求:
?
alter system set db_cache_size = 2G scope=memory;
alter system set large_pool_size = 512M scope=memory;
alter system set java_pool_size = 1.5G scope=memory;
alter system set large_pool_size = 512M scope=memory;
alter system set java_pool_size = 1.5G scope=memory;
?
??? 第二天早上,OLTP 作業(yè)恢復(fù)在線,這個(gè)循環(huán)又完全重復(fù)!
?
??? 解決這種惡性循環(huán)的一種替代方法是永久設(shè)置每個(gè)池的最大需求。不過,這么做的話,您分配的總的 SGA 可能超出可用的內(nèi)存 — 從而在為每個(gè)池分配的內(nèi)存數(shù)不足時(shí),將增加交換和分頁的風(fēng)險(xiǎn)。人工重新分配的方法(雖然不實(shí)際)目前看起來很不錯(cuò)。
?
??? 另一種替代方法是將值設(shè)為可接受的最小值。不過,當(dāng)需求增長且內(nèi)存不能完全滿足時(shí),性能將受到影響。
?
??? 注意在所有這些示例中,分配給 SGA 的總內(nèi)存保持不變,而池之間的內(nèi)存分配根據(jù)即時(shí)的需求進(jìn)行修改。如果 RDBMS 將自動(dòng)探測來自用戶的需求并相應(yīng)地重新分布內(nèi)存分配,那不是很好嗎?
?
??? Oracle 數(shù)據(jù)庫 10g 中的自動(dòng)共享內(nèi)存管理特性正好能夠?qū)崿F(xiàn)這一目的。您可以決定 SGA 的總大小,然后設(shè)置一個(gè)名稱為 SGA_TARGET 的參數(shù),這個(gè)參數(shù)決定 SGA 的總大小。SGA 內(nèi)部的各個(gè)池將根據(jù)工作負(fù)載動(dòng)態(tài)地進(jìn)行配置。實(shí)現(xiàn)自動(dòng)內(nèi)存分配僅僅需要 SGA_TARGET 參數(shù)的一個(gè)非零值。
?
?
設(shè)置自動(dòng)共享內(nèi)存管理
?
??? 讓我們看看該特性是如何工作的。首先,確定 SGA 的總大小。您可以通過確定現(xiàn)在分配了多少內(nèi)存來估計(jì)這個(gè)值。
?
SQL> select sum(value)/1024/1024 from v$sga;
?
SUM(VALUE)/1024/1024
--------------------
???????????????? 500
--------------------
???????????????? 500
?
??? 此時(shí) SGA 的當(dāng)前總大小近似為 500MB,并且這個(gè)值將變?yōu)?SGA_TARGET 的值。接下來,執(zhí)行語句:
?
alter system set sga_target = 500M scope=both;
?
??? 這種方法不需要為各個(gè)池設(shè)置不同值;因而,您將需要在參數(shù)文件中使它們的值為零或全部刪除它們。
?
shared_pool_size = 0
large_pool_size = 0
java_pool_size = 0
db_cache_size = 0????
large_pool_size = 0
java_pool_size = 0
db_cache_size = 0????
?
??? 再循環(huán)數(shù)據(jù)庫,使這些值生效。
?
??? 這個(gè)人工過程還可以通過 Enterprise Manager 10g 實(shí)施。從數(shù)據(jù)庫主頁中,選擇 "Administration" 選項(xiàng)卡,然后選擇 "Memory Parameters"。對(duì)于人工配置的內(nèi)存參數(shù),將顯示標(biāo)記為 "Enable" 的按鈕,以及所有人工配置的池的值。單擊 "Enable" 按鈕,啟用自動(dòng)共享內(nèi)存管理特性。企業(yè)管理器將完成剩下的工作。
?
??? 在配置了自動(dòng)內(nèi)存分配之后,您可以利用以下命令檢查它們的大小:
?
SQL> select current_size from v$buffer_pool;
?
CURRENT_SIZE
------------
???????? 340
------------
???????? 340
?
SQL> select pool, sum(bytes)/1024/1024 Mbytes from v$sgastat group by pool;
?
POOL???????????? MBYTES
------------ ----------
java pool???????????? 4
large pool??????????? 4
shared pool???????? 148
------------ ----------
java pool???????????? 4
large pool??????????? 4
shared pool???????? 148
?
??? 正如您所看到的,所有的池都從 500MB 的總目標(biāo)大小中自動(dòng)進(jìn)行分配。(參見圖 1。)緩沖高速緩存大小是 340MB,Java 池是 4MB,大型池是 4MB,共享池是 148MB。它們合起來總的大小為 (340+4+4+148=) 496MB,近似與 500MB 的目標(biāo) SGA 的大小相同。
?
圖 1:池的初始分配
?
??? 現(xiàn)在假定提供給 Oracle 的主機(jī)內(nèi)存從 500MB 減少為 300MB,這意味著我們必須減少總 SGA 的大小。我們可以通過減小目標(biāo) SGA 大小來反映這種變化。
?
alter system set sga_target = 300M scope=both;
?
??? 現(xiàn)在查看各個(gè)池,我們可以看到:
?
SQL> select current_size from v$buffer_pool;
?
CURRENT_SIZE
------------
???????? 244
------------
???????? 244
?
SQL> select pool, sum(bytes)/1024/1024 Mbytes from v$sgastat group by pool;
?
POOL???????????? MBYTES
------------ ----------
java pool???????????? 4
large pool??????????? 4
shared pool????????? 44
------------ ----------
java pool???????????? 4
large pool??????????? 4
shared pool????????? 44
?
??? 占用的總大小是 240+4+4+44 = 296MB,接近于目標(biāo)的 300MB。注意如圖 2 所示,當(dāng) SGA_TARGET 改變時(shí),如何自動(dòng)重新分配池。
?
圖 2:在將 SGA 大小減少到 300MB 之后重新分配池
?
??? 這些池的大小是動(dòng)態(tài)的。池將根據(jù)工作負(fù)載擴(kuò)展,以容納需求的增長,或縮小以容納另一個(gè)池的擴(kuò)展。這種擴(kuò)展或縮小自動(dòng)發(fā)生,無需 DBA 的干預(yù),這與本文開頭的示例不同。讓我們暫時(shí)返回到那個(gè)場景,假定在初始分配后,RMAN 作業(yè)啟動(dòng),指示需要一個(gè)更大的大型池,大型池將從 4MB 擴(kuò)展到 40MB,以容納需求。這個(gè)額外的 36MB 將從數(shù)據(jù)庫緩沖中劃出,數(shù)據(jù)庫塊緩沖將縮小,如圖 3 所示。
?
圖 3:在對(duì)大型池的需求增長之后經(jīng)過重新分配的池
?
??? 池的大小變化基于系統(tǒng)上的工作負(fù)載,因此不需要為最壞的情況調(diào)整池的大小 — 它們將根據(jù)需求的增長自動(dòng)調(diào)整。此外,SGA 的總大小始終在由 SGA_TARGET 指定的最大值之內(nèi),因此不存在使內(nèi)存需求的增長比例失調(diào)(這將導(dǎo)致分頁和交換)的風(fēng)險(xiǎn)。您可以動(dòng)態(tài)地將 SGA_TARGET 增加至絕對(duì)最大值,這個(gè)絕對(duì)最大值是通過調(diào)整參數(shù) SGA_MAX_SIZE 指定的。
?
哪些池不受影響?
?
??? SGA 中的一些池不受動(dòng)態(tài)大小調(diào)整的影響,但是必須顯式指定這些池。其中值得注意的是非標(biāo)準(zhǔn)塊大小的緩沖池,以及 KEEP 池或 RECYCLE 池的非默認(rèn)塊大小。如果您的數(shù)據(jù)庫有一個(gè)塊大小為 8K,而您想要配置 2K、4K、16K 和 32K 塊大小的池,那么您必須手動(dòng)設(shè)置它們。它們的大小將保持不變;它們將不會(huì)根據(jù)負(fù)載縮小或擴(kuò)展。當(dāng)使用多種大小的緩沖池、KEEP 池和 RECYCLE 池時(shí),您應(yīng)當(dāng)考慮這個(gè)因素。此外,日志緩沖不受內(nèi)存調(diào)整的影響 — 不管工作負(fù)載如何,在參數(shù) log_buffer 中設(shè)定的值是不變的。( 在 10g 中,還可以在 SGA 中定義一種新的池:流池 (stream pool),它用參數(shù) streams_pool_size 進(jìn)行設(shè)置。該池也不受自動(dòng)內(nèi)存調(diào)整的影響。)
?
??? 這就產(chǎn)生了一個(gè)有趣的問題。如果您需要一個(gè)非默認(rèn)塊大小的池,而且想自動(dòng)管理其它的池,那么該怎么辦?
?
??? 如果您指定了這些非自動(dòng)調(diào)整的參數(shù)中的任意一個(gè)(如 db_2k_cache_size),那么它們的總大小將從 SGA_TARGET 值中減去,以計(jì)算自動(dòng)調(diào)整的參數(shù)值,以使 SGA 的總大小保持不變。例如,假設(shè)值看起來像這樣:
?
sga_target = 500M
db_2k_cache_size = 50M
db_2k_cache_size = 50M
?
??? 其余的池參數(shù)未設(shè)置。50MB 的 2KB 緩沖池為自動(dòng)調(diào)整的池(如默認(rèn)塊大小緩沖池 (db_cache_size)、共享池、Java 池和大型池)保留了 450MB。當(dāng)以一種方法動(dòng)態(tài)地調(diào)整不可自動(dòng)調(diào)整的參數(shù)(如 2KB 塊大小池)——這種方法將影響到可自動(dòng)調(diào)整部分的大小,可自動(dòng)調(diào)整的部分將重新調(diào)整。例如,將 db_2k_cache_size 的值從 50MB 提高到 100MB 只為可自動(dòng)調(diào)整的參數(shù)剩余 400MB。因此,如圖 4 所示,可調(diào)整的池(如共享池、大型池、Java 池和默認(rèn)緩沖池)自動(dòng)縮小,以將它們的總大小從 450MB 減少到 400MB。
?
圖 4:配置非自動(dòng)緩沖參數(shù)的效果
??? 但如果您有足夠的可用內(nèi)存,或者上述風(fēng)險(xiǎn)可能不是那么明顯,那應(yīng)該怎么辦?如果這樣的話,您可以通過不指定參數(shù)文件中的參數(shù) SGA_TARGET、通過在文件中將其設(shè)為 0,或者通過使用 ALTER SYSTEM 動(dòng)態(tài)地將其修改為 0 來關(guān)閉自動(dòng)大小調(diào)整。當(dāng) SGA_TARGET 被設(shè)為 0 時(shí),池的當(dāng)前值被自動(dòng)設(shè)為它們的參數(shù)。
?
使用 Enterprise Manager
??? 您還可以使用 Enterprise Manager 10g 來處理這些參數(shù)。從數(shù)據(jù)庫主頁中單擊超鏈接 "Memory Parameters",這將顯示一個(gè)類似于圖 5 中的屏幕。
?
圖 5:在 Enterprise Manager 中調(diào)整自動(dòng)共享內(nèi)存管理
?
??? 注意紅圈中的項(xiàng)目:數(shù)據(jù)庫在 Automatic Shared Memory Management 模式下運(yùn)行,總大小為 564MB — 與在參數(shù) SGA_TARGET 中指定的值相同。您可以在此修改它,然后單擊 Apply 按鈕接受這些值;可調(diào)整的參數(shù)將自動(dòng)調(diào)整。
?
為每個(gè)池指定一個(gè)最小值
?
??? 假定您將 SGA_TARGET 設(shè)為 600MB,并且各個(gè)池已自動(dòng)分配:
?
????
池??? 大小(MB)?
??? 緩沖池 ?? 404
??? Java池 ??? 4
??? 大型池 ???? 4
??? 共享池 ?? 148
??? 緩沖池 ?? 404
??? Java池 ??? 4
??? 大型池 ???? 4
??? 共享池 ?? 148
?
??? 看看上述值,您可能推斷 4MB 的 Java 池和大型池可能有點(diǎn)不足;這個(gè)值在運(yùn)行時(shí)無疑需要增加。因此,您可能想確保這些池至少在最初時(shí)具有更高的值,比如說,分別為 8MB 和 16MB。您可以通過在參數(shù)文件中顯式地指定這些池的值或動(dòng)態(tài)使用 ALTER SYSTEM 來實(shí)現(xiàn)這一目的(如下所示)。
?
alter system set large_pool_size = 16M;
alter system set java_pool_size = 8M;
alter system set java_pool_size = 8M;
?
??? 現(xiàn)在查看這些池,您可以看到:
?
SQL> select pool, sum(bytes)/1024/1024 Mbytes from v$sgastat group by pool;
?
POOL???????????? MBYTES
------------ ----------
java pool???????????? 8
large pool?????????? 16
shared pool???????? 148
------------ ----------
java pool???????????? 8
large pool?????????? 16
shared pool???????? 148
?
SQL> select current_size from v$buffer_pool;
?
CURRENT_SIZE
------------
???????? 388
------------
???????? 388
?
??? 池的重新分配顯示如下:
?
????
池???? 大小(MB)?
??? 緩沖池 ??? 388
??? Java池 ????? 8
??? 大型池 ???? 16
??? 共享池 ??? 148
??? 緩沖池 ??? 388
??? Java池 ????? 8
??? 大型池 ???? 16
??? 共享池 ??? 148
?
??? 注意 Java 池和大型池是如何分別被重新配置為 8MB 和 16MB,并且注意為了使總的 SGA 保持在 600MB 以下,緩沖池已從 404MB 減少為 388MB。當(dāng)然,這些池仍然由自動(dòng)共享內(nèi)存管理控制 — 它們的大小將根據(jù)需求縮小或擴(kuò)展。您顯式指定的值為池的大小設(shè)定了一個(gè)下限;它們將永遠(yuǎn)不會(huì)縮小到低于這個(gè)界限。
?
?
結(jié)論
?
??? Oracle SGA 中的各種池的內(nèi)存需求不是靜態(tài)的 — 相反,它們根據(jù)系統(tǒng)上的需求而變化。Oracle 數(shù)據(jù)庫 10g 中的自動(dòng)共享內(nèi)存管理特性通過動(dòng)態(tài)地將資源重新分配到最需要它們的地方同時(shí)施加一個(gè)指定的最大值以防止分頁和交換,使得 DBA 能夠更有效地管理系統(tǒng)內(nèi)存。更有效的內(nèi)存管理還帶來了更少的內(nèi)存需求,這使得更精簡的硬件更加可行。
?
?
?
有關(guān)自動(dòng)共享內(nèi)存管理特性的更多信息,請(qǐng)參見 Oracle 數(shù)據(jù)庫性能調(diào)整指南 的第 7 章。
?
?
?
?
?