db2 記憶體結構

imlihj2007發表於2011-04-03

DB2 記憶體結構概述

圖 1中說明了 DB2 記憶體結構。這種記憶體結構在所有平臺上都是一致的。 注意:在多分割槽環境中,下面的圖適用於多分割槽例項中的每個分割槽。

圖 1 - DB2 記憶體結構


db2 記憶體結構

DB2 在 4 種不同的記憶體集(memory set)內拆分和管理記憶體。這 4 種記憶體集分別是:

例項共享記憶體(instance shared memory)
資料庫共享記憶體(database shared memory)
應用程式組共享記憶體(application group shared memory)
代理私有記憶體(agent private memory)
每種記憶體集由各種不同的記憶體池(亦稱堆)組成。圖 1 也給出了各記憶體池的名稱。例如, locklist是屬於資料庫共享記憶體集的一個記憶體池。 sortheap是屬於代理私有記憶體集的一個記憶體池。

我們將詳細討論每一種記憶體集。

例項共享記憶體

每個 DB2 例項都有一個例項共享記憶體。例項共享記憶體是在資料庫管理器啟動(db2start)時分配的,並隨著資料庫管理器的停止(db2stop)而釋放。這種記憶體集用於例項級的任務,例如監控、審計和節點間通訊。下面的資料庫管理器配置(dbm cfg)引數控制著對例項共享記憶體以及其中個別記憶體池的限制:

例項記憶體( instance_memory)。
監視器堆( mon_heap_sz):用於監控。
Audit Buffer( audit_buf_sz):用於 db2audit 實用程式。
Fast Communication buffers ( fcm_num_buffers):用於分割槽之間的節點間通訊。僅適用於分割槽的例項。
instance_memory引數指定為例項管理預留的記憶體數量。預設值是 AUTOMATIC。這意味著 DB2 將根據監視器堆審計緩衝區和 FCM 緩衝區的大小計算當前配置所需的例項記憶體數量。此外,DB2 還將分配一些額外的記憶體,作為溢位緩衝區。每當某個堆超出了其配置的大小時,便可以使用溢位緩衝區來滿足例項共享記憶體區內任何堆的峰值需求。在這種情況下,個別堆的設定是 軟限制的,它們可以在記憶體使用的峰值期間進一步增長。

如果 instance_memory被設定為某一個數字,則採用 instance_memory與 mon_heap_sz、 audit_buf_sz和 fcm_num_buffers的和之間的較大者。這時,對例項記憶體就施加了一個硬性的限制,而不是軟限制。當達到這個限制時,就會收到記憶體分配錯誤。出於這個原因,建議將 instance_memory的設定保留為 AUTOMATIC。

如果 instance_memory被設為 AUTOMATIC,則可以使用下面的命令來確定它的值
db2 attach to instance_name(其中 instance_name是例項的名稱)
db2 get dbm cfg show detail
下面的輸出表明有 42 MB 的記憶體被預留給例項共享記憶體集(10313 頁 * 4096 位元組/頁):

Size of instance shared memory (4KB) (INSTANCE_MEMORY) = AUTOMATIC(10313) AUTOMATIC(10313)
instance_memory引數只是設定了例項共享記憶體的限制。它並沒有說出當前使用了多少記憶體。要查明一個例項的記憶體使用情況,可以使用 DB2 記憶體跟蹤器工具 db2mtrk。例如,

db2start
db2mtrk -i -v
Memory for instance
FCMBP Heap is of size 17432576 bytes
Database Monitor Heap is of size 180224 bytes
Other Memory is of size 3686400 bytes
Total: 21299200 bytes
上面的例子表明,雖然預留給例項共享記憶體集的記憶體有 42 MB,但在 db2mtrk執行時只用到了大約 21 MB。注意:在某些情況下,db2mtrk 顯示的大小會大於指定給配置引數的值。在這種情況下,賦予配置引數的值被作為一種軟限制,記憶體池實際使用的記憶體可能會增長,從而超出配置的大小。

資料庫共享記憶體

每個資料庫有一個資料庫共享記憶體集。資料庫共享記憶體是在資料庫被啟用或者第一次被連線上的時候分配的。該記憶體集將在資料庫處於非啟用狀態時釋放(如果資料庫先前是處於啟用狀態)或者最後一個連線被斷開的時候釋放。這種記憶體用於資料庫級的任務,例如備份/恢復、鎖定和 SQL 的執行。

圖2展示了資料庫共享記憶體集內的各種記憶體池。括號中顯示了控制這些記憶體池大小的配置引數。

圖 2 - DB2 資料庫共享記憶體


db2 記憶體結構

完整的綠色方框意味著,在資料庫啟動的時候,該記憶體池是完全分配的,否則,就只分配部分的記憶體。例如,當一個資料庫第一次啟動時,不管 util_heap_sz的值是多少,只有大約 16 KB 的記憶體被分配給實用程式堆。當一個資料庫實用程式(例如備份、恢復、匯出、匯入和裝載)啟動時,才會按 util_heap_sz指定的大小分配全額的記憶體。

主緩衝池
資料庫緩衝池通常是資料庫共享記憶體中最大的一塊記憶體。DB2 在其中操縱所有常規資料和索引資料。一個資料庫必須至少有一個緩衝池,並且可以有多個緩衝池,這要視工作負載的特徵、資料庫中使用的資料庫頁面大小等因素而定。例如,頁面大小為 8KB 的表空間只能使用頁面大小為 8KB 的緩衝池。

可以透過 CREATE BUFFERPOOL 語句中的 EXTENDED STORAGE 選項“擴充套件”緩衝池。擴充套件的儲存(ESTORE)充當的是從緩衝池中被逐出的頁的輔助快取,這樣可以減少 I/O。ESTORE 的大小由 num_estore_segs 和 estore_seg_sz 這兩個資料庫配置引數來控制。如果使用 ESTORE,那麼就要從資料庫共享記憶體中拿出一定的記憶體,用於管理 ESTORE,這意味著用於其他記憶體池的記憶體將更少。

這時您可能要問,為什麼要這麼麻煩去使用 ESTORE?為什麼不分配一個更大的緩衝池呢?答案跟可定址記憶體(而不是實體記憶體)的限制有關,我們在後面會加以討論。

隱藏的緩衝池

當資料庫啟動時,要分配 4 個頁寬分別為 4K、8K、16K 和 32K 的小型緩衝池。這些緩衝池是“隱藏”的,因為在系統編目中看不到它們(透過 SELECT * FROM SYSCAT.BUFFERPOOLS 顯示不出)。

如果主緩衝池配置得太大,則可能出現主緩衝池不適合可定址記憶體空間的情況。(我們在後面會談到可定址記憶體。)這意味著 DB2 無法啟動資料庫,因為一個資料庫至少必須有一個緩衝池。如果資料庫沒有啟動,那麼就不能連線到資料庫,也就不能更改緩衝池的大小。由於這個原因,DB2 預先分配了 4 個這樣的小型緩衝池。這樣,一旦主緩衝池無法啟動,DB2 還可以使用這些小型的緩衝池來啟動資料庫。(在此情況下,使用者將收到一條警告(SQLSTATE 01626))。這時,應該連線到資料庫,並減少主緩衝池的大小。

如果沒有索引滿足所取的行的要求順序,或者最佳化器斷定排序的代價低於索引掃描,那麼就需要進行排序。DB2 中有兩種排序,一種是私有排序,一種是共享排序。私有排序發生在代理的私有代理記憶體(在下一節討論)中,而共享排序發生在資料庫的資料庫共享記憶體中。

對於私有排序,資料庫管理器配置引數 sheapthres指定了私有排序在任何時刻可以消耗的記憶體總量在例項範圍內的 軟限制。如果一個例項總共消耗的私有排序記憶體達到了這一限制,那麼為額外傳入的私有排序請求所分配的記憶體將大大減少。這樣就會在 db2diag.log 中看到如下訊息:

"Not enough memory available for a (private) sort heap of size size of sortheap. Trying smaller size..."

如果啟用了內部分割槽並行性(intra-partition parallelism)或者集中器(concentrator),那麼當 DB2 斷定共享排序比私有排序更有效時,DB2 就會選擇執行共享排序。如果執行共享排序,那麼就會在資料庫共享記憶體中分配用於這種排序的排序堆。用於共享排序的最大記憶體量是由 sheapthres_shr資料庫引數指定的。這是對共享排序在任何時刻可以消耗的記憶體總量在資料庫範圍內的 硬限制。當達到這個限制時,請求排序的應用程式將收到錯誤 SQL0955 (rc2)。之後,在共享記憶體總消耗量回落到低於由 sheapthres_shr指定的限制之前,任何共享排序記憶體的請求都得不到允許。

下面的公式可以計算出資料庫共享記憶體集大致需要多少記憶體:資料庫共享記憶體 = (主緩衝池 + 4 個隱藏的緩衝池 + 資料庫堆 +實用程式堆 + locklist + 包快取 + 編目快取) + (estore 的頁數 * 100 位元組) + 大約 10% 的開銷

對於啟用了 intra_parallel 或集中器情況下的資料庫,共享排序記憶體必須作為資料庫共享記憶體的一部分預先分配,因而上述公式變為:資料庫共享記憶體 = (主緩衝池 + 4 個隱藏的緩衝池 + 資料庫堆 +實用程式堆 + locklist + 包快取 + 編目快取 + sheapthres_shr) + (estore 的頁數 * 100 位元組) + 大約 10% 的開銷

提示: 為了發現分配給主緩衝池的記憶體有多少,可以發出:

SELECT * FROM SYSCAT.BUFFERPOOLS

雖然大多數記憶體池的大小是由它們的配置引數預先確定的,但下面兩種記憶體池的大小在預設情況下卻是動態的:

包快取: pckcachesz = maxappls * 8
編目快取: catalogcache_sz = maxappls * 4
活動應用程式的最大數量: maxappls = AUTOMATIC
將 maxappls設為 AUTOMATIC的效果是,允許任意數量的連線資料庫的應用程式。DB2 將動態地分配所需資源,以支援新的應用程式。因此,包快取和編目的大小可以隨著 maxappls的值而變化。

除了上述引數以外,還有一個引數也會影響資料庫共享記憶體的數量。這個引數就是 database_memory。該引數的預設值是 AUTOMATIC。這意味著 DB2 將根據以上列出的各記憶體池的大小來計算當前配置所需的資料庫記憶體量。此外,DB2 還將為溢位緩衝區分配一些額外的記憶體。每當某個堆超出了其配置的大小時,便可以使用溢位緩衝區來滿足例項共享記憶體區內任何堆的峰值需求。

如果 database_memory被設為某個數字,則採用 database_memory與各記憶體池之和這兩者之間的較大者。

如果 database_memory被設為 AUTOMATIC,則可以使用以下命令來顯示它的值:

db2 connect to dbnameuser useridusing pwd
db2 get db cfg for dbnameshow detail
使用 db2mtrk 工具顯示當前使用的記憶體量: db2mtrk -i -d -v (在 Windows 中,-i 必須指定。在 UNIX 中,-i 是可選的。)


Memory for database: SAMPLE
Backup/Restore/Util Heap is of size 16384 bytes
Package Cache is of size 81920 bytes
Catalog Cache Heap is of size 65536 bytes
Buffer Pool Heap is of size 4341760 bytes
Buffer Pool Heap is of size 655360 bytes
Buffer Pool Heap is of size 393216 bytes
Buffer Pool Heap is of size 262144 bytes
Buffer Pool Heap is of size 196608 bytes
Lock Manager Heap is of size 491520 bytes
Database Heap is of size 3637248 bytes
Other Memory is of size 16384 bytes
Application Control Heap is of size 327680 bytes
Application Group Shared Heap is of size 57344000 bytes
Total: 67829760 bytes


應用程式組共享記憶體

這種共享記憶體集僅適用於以下環境。(對於其他環境,這種記憶體集不存在。)

多分割槽(multi-partitioned)資料庫。
啟用了內部並行(intra-parallel)處理的未分割槽(non-partitioned)資料庫。
支援連線集中器的資料庫。
注意:當 max_connections的值大於 max_coordagents的值時,連線集中器便被啟用。這兩個引數可以在資料庫管理器配置中找到。(使用 GET DBM CFG 顯示資料庫管理器配置。)

在以上環境中,應用程式通常需要不止一個的代理來執行其任務。允許這些代理之間能夠彼此通訊(相互傳送/接收資料)很有必要。為了實現這一點,我們將這些代理放入到一個稱作 應用程式組的組中。屬於相同應用程式組的所有 DB2 代理都使用 應用程式組共享記憶體進行通訊。

應用程式組記憶體集是從資料庫共享記憶體集中分配的。其大小由 appgroup_mem_sz資料庫配置引數決定。

多個應用程式可以指派給同一個應用程式組。一個應用程式組內可以容納的應用程式數可以這樣計算: appgroup_mem_sz / app_ctl_heap_sz

在應用程式組內,每個應用程式都有其自己的 應用程式控制堆。此外,應用程式組共享記憶體中有一部分要預留給應用程式組共享堆。如下圖所示:

圖 3 - DB2 應用程式組共享記憶體

db2 記憶體結構


例 1 考慮以下資料庫配置:

最大應用程式記憶體集大小 (4KB) (APPGROUP_MEM_SZ) = 40000
最大應用程式控制堆大小 (4KB) (APP_CTL_HEAP_SZ) = 512
用於應用程式組堆的記憶體所佔百分比 (GROUPHEAP_RATIO) = 70
可以計算出下面的值:



應用程式組共享記憶體集是: 40000 頁 * 4K/頁 = 160 MB
應用程式組共享堆的大小是: 40000 * 70% = 28000 4K 頁 = 114MB
該應用程式組內可容納的應用程式數為: 40000/512 = 78
用於每個應用程式的應用程式控制堆為: (100-70)% * 512 = 153 4K 頁 = 0.6MB
不要被 app_ctrl_heap_sz 引數迷惑。這個引數不是一個應用程式組內用於每個應用程式的各應用程式控制堆的大小。它只是在計算這個應用程式組內可容納多少應用程式時用到的一個值。每個應用程式的實際應用程式控制堆大小都是透過 圖 3中給出的公式計算的,這個公式就是 ((100 - groupheap_ratio)% * app_ctrl_heap_sz)。

因此,groupheap_ratio 越高,應用程式組共享堆就越大,從而用於每個應用程式的應用程式控制堆就越小。

例 2 假設在一天中最忙的時間裡,有 200 個應用程式連線到例 1 中所描述的資料庫上。由於每個應用程式組可以容納 78 個應用程式,因此我們需要 200/78 = 3 個應用程式組來容納總共 200 個應用程式。這裡應確保系統有足夠多的 RAM 來支援這一配置。否則就會發生 SQL10003N 錯誤。

代理私有記憶體

每個 DB2 代理程式都需要獲得記憶體,以執行其任務。代理程式將代表應用程式使用記憶體來最佳化、構建和執行訪問計劃,執行排序,記錄遊標資訊(例如位置和狀態),收集統計資訊,等等。為響應並行環境中的一個連線請求或一個新的 SQL 請求,要為一個 DB2 代理分配代理私有記憶體。

代理的數量受下面兩者中的較低者限制:

所有活動資料庫的資料庫配置引數 maxappls 的總和,這指定了允許的活動應用程式的最大數量。
資料庫管理器配置引數 maxagents 的值,這指定了允許的最大代理數。
代理私有記憶體集由以下記憶體池組成。這些記憶體池的大小由括號中的資料庫配置引數指定:

Application Heap ( applheapsz)
Sort Heap ( sortheap)
Statement Heap ( stmtheap)
Statistics Heap ( stat_heap_sz)
Query Heap ( query_heap_sz)
Java Interpreter Heap ( java_heap_sz)
Agent Stack Size ( agent_stack_sz) (僅適用於 Windows)

共享記憶體與私有記憶體

至此,我們已經討論了例項共享記憶體、資料庫共享記憶體和應用程式組共享記憶體以及代理私有記憶體。但是共享記憶體和私有記憶體的意義是什麼呢?

為了理解共享記憶體與私有記憶體之間的不同之處,首先讓我們透過快速閱讀 DB2 程式 model來了解一下 DB2 代理程式。在 DB2 中,所有資料庫請求都是由 DB2 代理或子代理來服務的。例如,當一個應用程式連線到一個資料庫時,就有一個 DB2 代理指派給它。當該應用程式發出任何資料庫請求(例如一個 SQL 查詢)時,該代理就會出來執行完成這個查詢所需的所有任務 —— 它代表該應用程式工作。(如果資料庫是分割槽的,或者啟用了 intra-parallel,那麼可以分配不止一個的代理來代表應用程式工作。這些代理叫做 子代理。)

每個代理或子代理都被當作一個 DB2 程式,它獲得一定數量的記憶體來執行工作。這種記憶體被稱作 代理私有記憶體—— 它不能與其他任何代理共享。之前我們曾提到過,代理私有記憶體包括一些記憶體池,例如應用程式堆大小、排序堆大小和語句堆大小。(參見 圖 1)

除了私有記憶體(代理在其中使用 排序堆執行“私有”任務,例如私有排序)外,代理還需要資料庫級的資源,例如緩衝池、 locklist和日誌緩衝區。這些資源在資料庫共享記憶體中(參見 圖 1)。 DB2 的工作方式是,資料庫共享記憶體中的所有資源都由連線到相同資料庫的所有代理或子代理共享。因此,該記憶體集被稱作共享記憶體,而不是私有記憶體。例如,連線到資料庫 A 的代理 x 使用資料庫 A 的資料庫共享記憶體中的資源。現在又有一個代理,即代理 y 也連線到資料庫 A。那麼代理 y 將與代理 x 共享資料庫 A 的資料庫記憶體。(當然,代理 x 和代理 y 都有其自己的代理私有記憶體,這些代理私有記憶體不是共享的。)

這樣的邏輯同樣適用於例項共享記憶體和應用程式組共享記憶體。

下圖展示了當兩個 DB2 代理(代理 x 和代理 y)連線到資料庫 A 時分配的 DB2 記憶體集。假設:
資料庫 A 屬於例項 db2inst1。
資料庫 A 為應用程式組 1 啟用了 intra-parallel。
代理 x 和 代理 y 都屬於應用程式組 1。
圖 5 - DB2 代理程式記憶體地址空間

db2 記憶體結構


回覆於:2006-12-31 12:59:40

圖 5 展示了在 RAM 中分配的以下記憶體集:

用於例項 db2inst1 的例項共享記憶體集。
用於 資料庫 A 的資料庫共享記憶體集。
用於 應用程式組 1 的應用程式組共享記憶體。
用於代理 x 的代理私有記憶體集。
用於代理 y 的代理私有記憶體集。
為核心和庫之類的東西預留的記憶體。
代理 x 和代理 y 共享相同的例項記憶體、資料庫記憶體和應用程式組記憶體,因為它們屬於相同的例項、相同的資料庫和相同的應用程式組。此外,它們有其自己的代理私有記憶體。

每個 DB2 代理程式都有其自己的記憶體地址空間。在記憶體空間中的記憶體地址允許代理訪問物理 RAM 中的記憶體。我們可以把這些地址看作指向 RAM 的指標,如 圖 5所示。對於任何 DB2 程式,這個地址空間必須能夠容納上述所有 4 種記憶體集。

前面已提到,ESTORE 是用於擴充套件緩衝池的大小。那麼您可能要問,為什麼不建立一個更大的緩衝池呢。答案是:因為地址空間受到限制,地址空間可能容不下一個更大的緩衝池!在此情況下,需要定義一個較小的地址空間能夠容納的緩衝池。如果有過量的實體記憶體,那麼可以用該記憶體來配置 ESTORE。

那麼,我們怎麼知道一個 DB2 代理的地址空間是多大呢?地址空間的大小取決於當前的例項是 32 位的例項還是 64 位的例項。我們將在下一節對此進行解釋。

32 位體系結構與 64 位體系結構中的可定址記憶體

如果有一個 64 位的 DB2 例項,則意味著 DB2 使用的是 64 位的記憶體體系結構。在這種體系結構中,對於所有平臺,每個程式的地址空間都是 2 的 64 次方,或者 18,446,744,073 GB。這是一個相當巨大的記憶體。將所有 DB2 記憶體集放入這個地址空間應該沒有問題。

另一方面,如果有一個 32 位 DB2 例項,則對於所有平臺,地址空間只有 2 的 32 次方,或者 4 GB(Linux/390 平臺除外,在此平臺下地址空間實際上只有 2 的 31 次方。不過,在本文中我們不討論 Linux/390 中的 DB2)。所以,不管物理 RAM 有多大,要使一個 DB2 程式能夠訪問它所需的所有資源,包括例項共享記憶體、資料庫共享記憶體、應用程式組共享記憶體、它自己的代理私有記憶體以及用於核心的記憶體等,所有這些資源必須能放入到 4GB 的地址空間內。

這就導致了兩個非常重要的問題:

應該為例項記憶體、資料庫記憶體和應用程式共享記憶體分配多少的記憶體,以使它們能放入到 4GB 的可定址空間?
應該如何配置 圖 1中列出的每個引數,以最有效地利用可用的記憶體?
雖然 4GB 的地址空間限制適用於所有平臺,但是對於上述問題的回答卻與平臺有關。例如,在 AIX 系統上可以分配給 DB2 資料庫的最大資料庫記憶體數就與 Solaris 系統上的資料庫不同。接下來的幾節將討論不同的平臺對 DB2 中的記憶體配置有何影響。注意:本文的後續部分只針對 32 位記憶體體系結構。我們即將討論的問題不適用於 64 位的體系結構。

32 位 AIX 中的 DB2 記憶體配置

在 32 位的 AIX 上,4GB 的可定址記憶體空間被拆分為 16 個段,每段 256MB。 圖 6展示了用於一個 DB2 代理程式的 32位 記憶體地址空間。(假設 DB2_MMAP_READ 和 DB2_MMA_WRITE 這兩個 DB2 登錄檔變數都被設為 NO。如果這兩個變數沒有設為 NO,則表示方法會有點不同。我們將在後面解釋。)

圖 6 - AIX 中的 DB2 32 位記憶體地址空間


db2 記憶體結構

段 0 - 預留給 AIX 核心。

段 1 - 預留給 db2sysc 程式。

段 2 - 預留給代理私有記憶體。

段 3 - 預留給例項共享記憶體。

段 4 到段 B - 資料庫共享記憶體始於段 4,這些段必須緊挨在一起。所有這 8 個段(2GB)可能都被用於資料庫共享記憶體。但是,下面的每種配置都會從資料庫共享記憶體中拿出一個段(256MB)。

注意: 對於下面的每種配置,DB2 將從資料庫共享記憶體中拿出一個段,這個段始於段 B。

如果資料庫是分割槽的,或者啟用了 intra-parallel 或連線集中器,那麼資料庫共享記憶體中有一個段被預留給應用程式組共享記憶體。
Fast Communication Manager (FCM):FCM 用於系統物理節點上不同分割槽之間的通訊。預設情況下,這種通訊是透過 UNIX socket 進行的。如果 DB2_FORCE_FCM_BP 被設為 YES,那麼 FCM 通訊發生在共享記憶體內。這意味著資料庫共享記憶體中有一個段被預留給 FCM 通訊。雖然 FCM 通訊變得更快,但是它也令資料庫共享記憶體減少了一個段。
fenced UDF 和儲存過程:如果資料庫上執行著一個 fenced 函式或過程,那麼資料庫共享記憶體中有一個段要預留給 fenced 模式的通訊。
如果資料庫允許任何本地連線,那麼資料庫共享記憶體中有一個段要預留給代理/本地應用程式通訊。如果將所有本地連線配置為 loopback 連線,那麼就可以為這些連線使用 TCP/IP,而不需要共享記憶體(即使資料庫就在伺服器本地)。這樣就有效地為資料庫共享記憶體空出一個段來。 然而,如果您不想使用 loopback 解決方案,還有一種方法可以迫使 DB2 選擇段 E 來用於代理/本地應用程式通訊,這樣資料庫共享記憶體就不受影響(即不會減少)。請參閱後面的解釋。
如果啟用了 ESTORE,那麼還要從資料庫共享記憶體中拿出另一個段。因此,如果啟用 ESTORE,則應確保它至少是 256MB,否則就不起作用,因為要從資料庫共享記憶體中拿出一個 256 MB 的段來僅用於管理這個 ESTORE。建議將 estore 段的大小( estore_seg_sz)設為 256MB,然後根據可用的記憶體更改段的數目( num_estore_segs)。
段 C - 預留給 DB2 跟蹤使用程式。

段 D 和 F- 預留給 DB2 共享庫

段 E - 在預設情況下,這個段是不用的。不過,如果設定 DB2_MMAP_READ=NO 和 DB2_MMAP_WRITE=NO,那麼該段用於 DB2 代理以及本地應用程式之間的通訊(如 圖 6所示)。這將有效地為資料庫共享記憶體一個段。

注意: 為了最大化資料庫共享記憶體的空間,應使用以下注冊表變數設定:DB2_FORCE_FCM_BP=NO (該值是預設值),DB2_MMAP_READ=NO,DB2_MMAP_WRITE=NO。

需要從這種結構中瞭解到的最重要的事情是:

對於禁用了 intra-parallel 的單分割槽系統,我們可以得到至多 2GB 的空間用於資料庫共享記憶體(段 4 到段 B)。
下面每種配置都將資料庫共享記憶體減少了一個段(256MB):帶 fenced UDF 或儲存過程的資料庫、帶本地連線的資料庫、DB2_FORCE_FCM_BP=YES 情況下的資料庫、支援 intra_parallel、或支援集中器以及分割槽的資料庫,以及啟用了 ESTORE 的資料庫。
如果允許與資料庫進行本地連線,那麼應該將 DB2_MMAP_READ 和 DB2_MMAP_WRITE 都設定成 NO,以便使用段 E。否則,任何本地連線都要從資料庫共享記憶體中拿走一個段。
這些限制規定了我們該如何配置資料庫共享記憶體集中的每個記憶體池。可以使用前面給出的公式來計算資料庫共享記憶體。得到的總和不能超過這個限制。

注意:記憶體可以分配,釋放,也可以當資料庫正在執行時在不同區域之間交換。例如,您可以減少 locklist 而增加相同數量的任何一個給定的緩衝池。

使用 svmon 監控 AIX 上的記憶體使用情況

在 AIX 上,除了 db2mtrk 工具外,還可以使用 svmon 工具來監控 DB2 代理程式的記憶體消耗情況(需要 root 許可權)。這個命令是: "svmon -P PID",其中 PID是 DB2 代理(db2agent 或 db2agentp)的程式 ID。

圖 7 展示了 svmon 對於一個名為 db2agent 的程式的示例輸出。與這個 db2agent 程式相關的資料庫有如下特徵:

db2 記憶體結構
資料庫名是 TEST。
INTRAP_PARALLEL = YES (get dbm cfg)
DB2_FORCE_FCM_BP = YES (db2set -all)
DB2_MMAP_READ=NO, DB2_MMAP_WRITE=NO (db2set -all)
圖 7 - svmon 對於一個 DB2 代理程式 (svmon -P 11649046) 的輸出



從 圖 7中觀察到的一些情況:

程式 ID 是 11649046,程式名為 db2agent(左上角)。這個代理被連線到資料庫 TEST(資料庫的名稱在 svmon 輸出中已經被截斷,只顯示了 'TES')。
Esid 列顯示已經分配的記憶體段:
段 4 (綠色)被分配給資料庫共享記憶體。
段 2 (橙色)被分配給代理私有記憶體。
段 3 (藍色)被分配給例項共享記憶體。
段 B (紫色)被分配給應用程式組共享記憶體,因為資料庫支援 intra_parallel。
段 A (粉紅色)被分配給 FCM,因為 DB2_FORCE_FCM_BP=YES。
本地連線段被移到段 E(紅色)。這是因為 DB2_MMAP_READ 和 DB2_MMAP_WRITE 都被設為 NO。否則,就必須將段 8 用於代理和本地連線通訊,因為段 A 和段 B 都已經被佔用,而段 9 被預留給 fenced 模式的通訊。
觀察到的這些情況與 圖 6中說明的相匹配。

設定 32 位 AIX 系統上資料和堆疊的 ulimit

我們早先說過, 圖 6中的段 #2 是用於代理私有記憶體的。實際上,並非完全如此。

確切地說,段 #2 被預留給資料和堆疊。資料包含使用者資料(即代理私有記憶體)。而堆疊則包含要執行的指令。在這個 256M 的段中,資料是從地址 0x20000000 向下增長的。而堆疊是從地址 0x2FFFFFFF 向上增長的。為了不讓資料和堆疊有衝突,設定它們的限制就十分重要。如果資料和堆疊真的有衝突,那麼例項就會崩潰,併產生訊號 4 或訊號 11。

圖 8 - 資料段和堆疊段


db2 記憶體結構

資料和堆疊的限制是在 ulimits(/etc/security/limits)中設定的。使用 SMIT 將它們設定成如下值:

Data = 491519, Stack = 32767 (512 位元組)

上述值以 512 位元組為單位,其中對於資料是 240MB,對於堆疊是 16MB。當使用 "ulimit -a" 顯示這兩個限制時,顯示的值以 1K 位元組為單位,而不是以 512 位元組為單位。因此這兩個值變為:

Data = 245760, Stack = 16384

注意: /etc/security/limits 包含了以 512 位元組為單位的限制,而不是以 1 KB 為單位的限制。

32 位 AIX 上與分配資料庫共享記憶體有關的常見問題

初始化資料庫共享記憶體失敗可能產生如下問題:

在資料庫啟動時(啟用資料庫或第一次連線資料庫) - SQL1478W, SQL0987C, SQL1084C。
在執行時 - SQL10003N, SQL1042C。
下面的例子展示了會導致問題的不恰當配置。

例 1 考慮以下配置:(所有頁的大小為 4KB)

單分割槽,禁用集中器,INTRA_PARALLEL OFF,DB2_MMAP_READ=NO,DB2_MMAP_WRITE=NO,無 fenced 函式或過程
IBMDEFAULTBP 450,000 頁
UTILHEAP 17,500 頁
DBHEAP 10,000 頁
LOCKLIST 1000 頁
PCKCACHE 5000 頁
CATALOGCACHE 2500 頁
限制:在此配置中,對於資料庫共享記憶體的限制是 2GB 或 8 個段。

計算:使用公式計算資料庫共享記憶體,我們得到:

資料庫共享記憶體 = (486,000 頁 x 4KB/頁的總數) x 1.1 (考慮到 10% 的開銷) = ~2.1GB = 9 個段

注意:我們會將 4 個隱藏緩衝池排除在計算之外,因為它們太小了,不會產生明顯的不同。

問題:這超出了 2GB 的限制。當啟用資料庫或第一次連線到資料庫時,您將收到如下警告:

SQL1478W The defined buffer pools could not be started. Instead, one small buffer pool for each page size supported by DB2 has been started. SQLSTATE=01626

在 db2diag.log 中,您將看到有訊息說 DB2 將利用隱藏緩衝池啟動。要解決這個問題,可以減少主緩衝池的大小。

例 2 考慮如下配置: (所有頁的大小都是 4K)

單分割槽,無 fenced 函式或過程,INTRA_PARALLEL=ON
IBMDEFAULTBP 300,000 頁
UTILHEAP 17,500 頁
DBHEAP 10,000 頁
SHEAPTHRES_SHR 50,000 頁
LOCKLIST 1000 頁
PCKCACHE 5000 頁
CATALOGCACHE 2500 頁
限制: 1.5GB (6 個段)。一個段用於應用程式組記憶體,因為 INTRA_PARALLEL 是 ON。另一個段用於本地連線,因為 DB2_MMAP_READ 和 DB2_MMAP_WRITE 都被設為 YES (該值是預設值)。

計算:資料庫共享記憶體 = (386,000 頁 x 4KB/頁的總數) x 1.1 = ~1.67GB = 7 個段

問題:這超出了 1.5GB 的限制。當嘗試啟用資料庫或第一次連線到資料庫時,您將得到以下錯誤訊息:

SQL1042C An unexpected system error occurred. SQLSTATE=58004

要解決這一問題:

使用 db2set 將 DB2_MMAP_READ 和 DB2_MMAP_WRITE 設為 NO。這樣便迫使 DB2 將段 E 用於本地連線,從而為資料庫共享記憶體空出一個段。
例 3 考慮如下配置: (所有頁的大小都為 4K)
IBMDEFAULTBP 250,000 頁
INTRA_PARALLEL=ON
UTILHEAP 17,500 頁
DBHEAP 10,000 頁
SHEAPTHRES_SHR 20,000 頁
LOCKLIST 1000 頁
PCKCACHE 5000 頁
CATALOGCACHE 2500 頁
存在 Fenced UDF
限制: 以下各佔一個段:Intra-parallel ON,本地連線,以及 fenced UDFB。這樣還剩下 5 個段,或者 1.25G 給資料庫共享記憶體。

計算:

資料庫共享記憶體 = (306,000 頁 x 4KB/頁的總數) x 1.1% = ~1.35GB = 6 個段

問題: 引用了 fenced UDF 的查詢就會失敗,並返回錯誤 sql10003C。要解決這個問題,可以在 unfenced 模式下執行 UDF,或者將資料庫共享記憶體減少至不多於 5 個段。

32-位 Sun Solaris Version 2.6 及及其更高版本中的 DB2 記憶體配置

在 AIX 中,每個段的大小都是 256MB,而在 Solaris 中則有所不同,其記憶體段的大小不是固定的。32 位 Solaris 可定址記憶體結構如 圖 9所示。

圖 9 - 32 位 Sun SolarisDB2 中的 32 位記憶體地址空間


db2 記憶體結構

從 0x0 到 0x00010000 之間的地址不能使用。第一個段始於 0x00010000,這個段被預留給 db2sysc 可執行程式和代理私有記憶體。在預設情況下,這個段結束於 0x10000000,因而這個段總共是 256MB。(我們可以透過設定 DB2DBMSADDR DB2 登錄檔變數使這個段更大一些,見後面)。在這個段內,db2sysc 可執行程式只佔用很小的一片記憶體,剩下的用於代理私有記憶體(200MB+)。

在預設情況下,例項共享記憶體的起始地址固定於 0x10000000。不過,也可以將其改為一個更高的地址,以便有更多的空間留給代理私有記憶體。例如,如果例項共享記憶體始於 0x12000000,而不是 0x10000000,那麼就有 0x12000000 減去 0x10000000 即 32MB 的額外記憶體被用於代理私有記憶體。要做到這一點,可以將 DB2DBMSADDR DB2 登錄檔變數設為如下值:

db2set DB2DBMSADDR=0x12000000

注意: DB2DBMSADDR 值的範圍是從 0x10000000 到 0x10FFFFFF,每次遞增 0x10000。

例項共享記憶體的結束地址是不固定的。這意味著例項共享記憶體可能會很大。緊接著例項共享記憶體的是資料庫共享記憶體。因為例項共享記憶體的結束地址不固定,所以資料庫共享記憶體的起始地址也是不固定的。

在資料庫共享記憶體之後的是用於 DB2 跟蹤、共享庫和堆疊(即將執行的指令)的記憶體。在 AIX 中,堆疊和代理私有記憶體共享相同的記憶體段,而在 Solaris 中則有所不同,其中代理私有記憶體和堆疊分別使用不同的記憶體段。因此,這裡不存在兩者之間發生衝突的風險。

由於這些記憶體段的大小不是固定的,我們只能估計例項共享記憶體和資料庫共享記憶體的大小為:

4GB - 代理私有記憶體 - DB2 跟蹤 - DB2 共享庫 - 堆疊

注意這個數量同時還包括例項共享記憶體和資料庫共享記憶體,並且它們的記憶體段必須是鄰接的。為了看一看實際中如何使用記憶體,可以對 db2sysc 或 db2agent 程式的 ID 執行 /usr/proc/bin/pmap 命令(以 root 的身份)。

注意:在 Solaris 中,當使用 "pe -ef | grep instance_name" 命令顯示 DB2 程式時,所有程式都作為 db2sysc 程式顯示。可以使用 db2ptree命令來以“真實”名稱顯示 DB2 程式。 圖 9展示了 pmap 命令的一個示例輸出。


回覆於:2006-12-31 13:05:06

圖 10 - pmap 命令對於 db2sysc 程式的示例輸出(/usr/proc/bin/pmap -x 15444)

db2 記憶體結構


從 圖 10 中可以觀察到下面一些情況:

從 0x00010000 到 0x023F8000 這一部分被預留給 db2sysc 可執行程式(~36MB)。
橙色的那部分(堆),即從 0x023F8000 到 0x10000000,被用於代理私有記憶體(~220MB)。
例項共享記憶體,即綠色那部分,始於預設地址 0x10000000。這意味著沒有設定 DB2DBMSADDR。
所有 3 個綠色的段被用於共享記憶體,包括例項共享記憶體和資料庫共享記憶體。pmap 輸出並沒有說出哪一個段是例項共享記憶體,哪一個段是資料庫共享記憶體。我們只知道,資料庫共享記憶體在 0xFE002000 結束,因為從這個地址開始的是一個用於匿名記憶體的段。因此,例項共享記憶體和資料庫共享記憶體總共的大小是 0xFE002000 - 0x10000000 = 3,992,985,600 位元組 = ~3.7 GB。
從 0xFFBC0000 到 0xFFFFFFFF 是用於堆疊的記憶體段(~4MB)。
注意:在 32 位 Solaris 中,我們通常將 DB2 資料庫共享記憶體限制在大約 3.5 GB。

如果設定了 DB2DBMSADDR 登錄檔變數,那麼例項共享記憶體將從該變數指定的地址開始。下面的例子展示了這一點是如何實現的。

例子 設定 DB2DBMSADDR 登錄檔變數:

db2set DB2DBMSADDR = 0x12000000
db2stop
db2start (需要重新啟動例項,以使更改生效)。
獲得 db2sys 程式的程式 ID

ps -ef | grep sylviaq ('sylviaq' 是例項名)。
-ef | grep sylviaq
sylviaq 13166 1 0 13:09:12 pts/2 0:00 /export/home/sylviaq/sqllib/bin/db2bp 13049C11221 5
sylviaq 13263 13256 0 13:11:02 ? 0:00 db2sysc
sylviaq 13265 13256 0 13:11:03 ? 0:00 db2sysc
sylviaq 13257 13254 0 13:10:59 pts/3 0:00 -ksh
sylviaq 13256 13253 0 13:10:59 ? 0:00 db2sysc
sylviaq 13262 13256 0 13:11:00 ? 0:00 db2sysc
sylviaq 13360 13049 0 13:11:41 pts/2 0:00 grep sylviaq
sylviaq 13264 13256 0 13:11:02 ? 0:00 db2sysc
sylviaq 13266 13261 0 13:11:03 ? 0:00 db2sysc
以 root 的身份 cd 到 /usr/proc/pmap,並對任何 db2sysc 程式執行 pmap:

./pmap -x 13263

pmap 輸出:

13263: db2sysc
Address Kbytes Resident Shared Private Permissions Mapped File
00010000 35808 4064 1608 2456 read/exec db2sysc
02316000 896 168 48 120 read/write/exec db2sysc
023F6000 744 264 8 256 read/write/exec [ heap ]
12000000 243472 243472 - 243472 read/write/exec/shared [shmid=0xbc3]
21000000 22512 22512 - 22512 read/write/exec/shared [shmid=0xbc4]
FCC00000 8328 8328 - 8328 read/write/exec/shared [shmid=0xa96]
FE002000 8 - - - read/write/exec [ anon ]
注意,例項共享記憶體現在從 0x12000000 開始,而不是從預設地址 0x10000000 開始。代理私有記憶體的大小(由 'heap' 標出)從 220MB ( 圖 10)增加到了 252 MB。(0x12000000 - 0x023F6000 = 0xFC0A000 = 264282112 (十進位制) = ~252MB)

您可能注意到, 圖 9中給出的 4GB 地址空間沒有包括任何核心記憶體。這就對了,在 Solaris 中,核心有其自己的地址空間,該地址空間與程式的地址空間是分開的。這樣就將更多的空間留給了其他記憶體集,例如資料庫共享記憶體。

雖然與 AIX 相比,在 Solaris 中我們有更大的地址空間用於資料庫共享記憶體(在 AIX 上是 2GB),但是在 Solaris 上所有共享記憶體都是固定在物理 RAM 中。如果 RAM 比較小,那麼對於可以併發執行的資料庫數目就有很大的影響。請參閱 “Sun Solaris 中與分配資料庫共享記憶體有關的常見問題”一節中的例 2。

需要從這種結構中瞭解到的最重要的事情是:

與 AIX 不同,Solaris 的記憶體段其大小不是固定的。我們可以透過設定 DB2DBMSADDR DB2 登錄檔變數,將例項共享記憶體移到更高的地址,從而增加代理私有記憶體。
資料庫共享記憶體的限制大約是 3.5GB。
功能記憶體與 RAM 固定,因而不能交換出去。
32 位 Sun Solaris 中與分配資料庫共享記憶體有關的常見問題

沒有充分配置核心引數以及初始化資料庫共享記憶體失敗可能導致如下失敗:

在資料庫啟動時(啟用資料庫或第一次連線到資料庫) - SQL1478W, SQL1084C, hang condition
在執行時 - SQL2043N, 掛起條件
在 Solaris 系統中,DB2 提供了一個叫做 db2osconf的工具。該工具根據系統的大小對核心引數的值給出建議。對於一個給定的系統,建議的值要足夠高,以便能夠容納最合理的工作負載。

最常見的未能正確設定的核心引數是 shmmax。該引數按位元組指定系統中可以分配的共享記憶體段的最大大小。如果把 DB2 配置成建立大於這個值的資料庫共享記憶體,那麼請求就會失敗。其他要知道的核心引數是 shmseg和 shmmni。

Solaris 中另一個與分配資料庫共享記憶體有關的常見問題是由於這樣的一個事實導致的,即共享記憶體段的所有頁都是固定在物理 RAM 中的。如果在 RAM 中沒有足夠的空閒頁可用,或者沒有足夠的可以被 OS 為滿足資料庫段而調出的其他頁,那麼啟動資料庫的請求就會遭到失敗。

下面的例子展示了會導致問題的不恰當配置。

例 1 考慮如下配置: (所有頁的大小都為 4K)

伺服器:

伺服器上的物理 RAM 16GB
shmsys:shminfo_shmmax = 2097152 (2GB)
資料庫:

IBMDEFAULTBP 400,000 頁
UTILHEAP 17,500 頁
DBHEAP 30,000 頁
LOCKLIST 1000 頁
PCKCACHE 5000 頁
CATALOGCACHE 2500 頁
限制: DB2 發出的任何建立大於 shmmax 值(這裡是 2GB)的資料庫共享記憶體集的請求都將失敗,並返回一個 out of memory type 錯誤。

計算:

資料庫共享記憶體 = (456,000 頁 x 4KB/頁) x 1.1 = ~2.0GB

問題: 可能仍然可以啟用資料庫或者連線到資料庫。但是,嘗試執行一個應用程式時可能返回如下錯誤訊息:

SQL1224N A database agent could not be started to service request, or was terminated as a result of a database system shutdown or a force command. SQLSTATE=55032

這是 DB2 經常返回的一個錯誤。不過,如果不是在 AIX 伺服器上,而是在 UNIX 伺服器上,那麼這就很可能與記憶體資源問題有關。特別地,可能是核心引數沒有進行適當的調優。

為解決這個問題,可以適當地配置核心引數。設定:

shmsys:shminfo_shmmax = 15099494 (~90% of 16GB)

例 2 考慮如下配置: (所有頁的大小都為 4K)

伺服器上的物理 RAM 是 1 GB。

資料庫 A:

IBMDEFAULTBP 137,500 頁
INTRA_PARALLEL ON
UTILHEAP 10,000 頁
DBHEAP 10,000 頁
SHEAPTHRES_SHR 20,000 頁
LOCKLIST 1000 頁
PCKCACHE 5000 頁
CATALOGCACHE 2500 頁
APPGROUP_MEM_SZ 20,000 頁
資料庫 B:

IBMDEFAULTBP 92,500 頁
INTRA_PARALLEL ON
UTILHEAP 5,000 頁
DBHEAP 10,000 頁
SHEAPTHRES_SHR 15,000 頁
LOCKLIST 1000 頁
PCKCACHE 5000 頁
CATALOGCACHE 2500 頁
APPGROUP_MEM_SZ 20,000 頁
限制: 因為共享記憶體是固定到物理 RAM 的,所以這種記憶體不會被換出。因此,我們只能分配最多 1GB (可用的物理 RAM)的共享記憶體給資料庫使用。

計算:

資料庫 A 共享記憶體 = (186,000 頁 x 4KB/頁) x 1.1% = ~818MB
資料庫 A 應用程式組記憶體 = 20,000 頁 x 4KB/頁 = 80MB
資料庫 B 共享記憶體 = (131,000 頁 x 4KB/頁) x 1.1% = ~576MB
資料庫 B 應用程式組記憶體 = 20,000 頁 x 4KB/頁 = 80MB
為了啟動資料庫 A,要求: 818MB + 80MB = ~898MB
為了啟動資料庫 B,要求: 576MB + 80MB = ~656MB
問題: 假設資料庫 A 是啟用的。至少有 898MB 的共享記憶體固定在物理 RAM 中。當嘗試啟用資料庫 B 時,就會碰到如下錯誤訊息:

SQL1084C Shared memory segments cannot be allocated. SQLSTATE=57019

如果同時啟動資料庫 A 和資料庫 B,我們將請求至少 1.55GB (898MB + 656MB) 的可用物理 RAM,以便同樣地將共享記憶體固定在 RAM 中。顯然,1GB 的 RAM 不夠。為解決這一問題:

嘗試減少這兩個資料庫的緩衝池大小。或者
嘗試減少應用程式組記憶體。或者
更可能的是,增加更多的物理 RAM。在這種情況下,您將需要至少 1.55GB 的物理 RAM,才能同時啟動這兩個資料庫。
在這種情況下,按照上面的資料庫配置引數,在任何時刻啟動某一個資料庫(資料庫 A 或資料庫 B)是可行的,但是不能同時啟動兩個資料庫。這是必須增加更多的物理 RAM。

這個問題在 AIX 中不會出現,因為在 AIX 中共享記憶體沒有固定在物理 RAM 中。在這種場景中,可以啟動資料庫 B。但是,這意味著資料庫 A 的資料庫記憶體必須調出。當一個應用程式訪問資料庫 A 時,又得將資料庫 B 的資料庫記憶體調出。您可以想象未來要發生的調頁次數有多少。

例 3 考慮如下配置: (所有頁的大小都是 4K)
伺服器:

伺服器上的物理 RAM 16GB
shmsys:shminfo_shmmax = 15099494 (16GB 的 ~90%)
資料庫:

IBMDEFAULTBP 350,000 頁
UTILHEAP 17,500 頁
DBHEAP 10,000 頁
LOCKLIST 1000 頁
PCKCACHE 5000 頁
CATALOGCACHE 2500 頁
ESTORE_SEG_SZ = 400000 頁
NUM_ESTORE_SEGS = 1
計算:

資料庫共享記憶體 = (386,000 頁 x 4KB/頁 + 400,000 頁的 estore * 100 位元組) x 1.1 = ~1.66GB
ESTORE memory = 400000 x 4KB = 1.6GB
問題: 資料庫共享記憶體是 1.66GB。這個數小於 3.35GB 的資料庫共享記憶體限制。shmmax 引數設定得比較恰當。但是在啟動資料庫時可能返回下面的錯誤訊息!您可以在 db2diag.log 中看到如下錯誤訊息:

2003-12-04-10.10.13.362027 Instance:db2inst1 Node:000
PID:18327(db2agent (SAMPLE) 0) TID:1 Appid:*LOCAL.sample.047844091013
oper system services sqloVLMAttachVLMSegment Probe:20 Database:SAMPLE
sqloVLMAttachVLMSegment - shmat failed
0xFFBE833C : 0x0000000C
shmat 是一個 UNIX 函式,它將與 shmid(另一個 Solaris 函式)所標識的共享記憶體相關的共享記憶體段附加到呼叫程式的資料段上。shmat 失敗於 0x000000C,即 ENOMEM 或可用資料空間不足以容納共享記憶體段。

換句話說,不能啟用資料庫或連線到資料庫,因為沒有足夠的共享記憶體來滿足請求。

那麼該怎麼辦呢?答案在於我們分配 ESTORE 的方式。每個 ESTORE 段必須是一個連續的塊。在我們的例子中,我們試圖為 ESTORE 分配很大的一塊(連續的)記憶體(1.6GB)。即使有 16GB 的 RAM,它也可能會被分段,從而沒有一塊連續的 1.6GB 的記憶體。

為解決這個問題,在資料庫配置檔案中像下面這樣設定 ESTORE 的值:

ESTORE_SEG_SZ = 40000 頁
NUM_ESTORE_SEGS = 10
透過設定上面的 ESTORE 值,實際上我們仍然試圖為 ESTORE 分配總共 1.6 GB 的記憶體。然而,我們將嘗試為 ESTORE 分配 10 塊 160MB 的記憶體。這樣分配的連續空間就要小得多,因此最有可能解決問題

[@more@]

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

相關文章