原文:https://www.ibm.com/developerworks/cn/analytics/library/ba-lo-backup-restore-performance-issue-judge-optimize/index.html
Db2 備份/恢復線程模型
Db2 備份線程模型
首先看一下 Db2 backup 操作的線程模型,如圖 1 所示(圖片來源見參考資料):
圖 1. Backup 線程模型
它主要包括 db2bm, db2med, db2agent 三類 EDU,以及 db2vend 進程,在參考資料 Maximizing Performance of IBM DB2 Backups 一文中有更詳細的解釋,這里簡單說一下:
- db2agent EDU:負責 backup 開始階段的工作,包括計算並創建最優數量的 db2bm/db2med EDU、分配最佳大小的 backup buffer、通過向 db2bm 和 db2med 發送控制信息以協調備份工作。
- db2bm EDU:從 empty queue 里獲取一個 backup buffer,然后從其對應的表空間里讀取數據到 buffer 里,然后把寫滿的 buffer 放到 full queue 里。簡單來講,就是從磁盤上讀數據到內存中。
- db2med EDU:從 full queue 里獲取一個 backup buffer,然后寫到 backup 設備上。如果 backup 設備是磁盤,那么它直接負責處理 I/O 操作;如果 backup 設備是存儲管理器(storage manager),比如 TSM、NBU,它會把這個 buffer 交給 db2vend 進程。簡單來講,就是把內存中的數據寫到磁盤上或者交給存儲管理器。
- db2vend 進程:如果使用了存儲管理器,db2med 就會另外創建一個獨立的 db2vend 進程,它負責從 db2med 接收數據並調用 vendor API 將數據發送給存儲管理器。
restore 線程模型
restore 操作的線程模型如圖 2 所示(圖片來源見參考資料):
圖 2. Restore 線程模型
和 backup 線程模型類似,restore 操作同樣包括 db2bm, db2med, db2agent 三類 EDU,以及 db2vend 進程:
- db2agent EDU:和 backup 操作中的 db2agent EDU 功能類似,不再贅述。
- db2med EDU:從 empty queue 里獲取一個 buffer,從備份鏡像里讀取數據到 buffer 里,然后將 buffer 放到 full queue 里。簡單來講,就是從磁盤上讀取備份數據到內存中。另外,無論備份文件有幾個,都只有一個 db2med EDU。
- db2bm EDU:從 full queue 里獲取一個 buffer,然后將里面的內容寫到對應的表空間容器上,如果表空間有多個容器,I/O 操作會由多個 db2pfchr EDU 並行寫入。簡單來講,就是將內存中的數據寫到容器上。
- db2vend 進程:如果使用了存儲管理器,就會產生一個 db2vend 進程,它負責調用 vendor API 從備份中讀取數據,並將讀取的數據交給 db2med EDU。
Db2 backup/restore 命令中影響性能的參數
這一章主要介紹 db2 backup/restore 命令本身影響性能的參數。
INCREMENTAL
增量備份中只包含上次備份以來修改過的數據,備份出的文件會比較小,但並不意味着需要的時間也很短:如果表空間沒有被修改過,那么增量備份的時候就會跳過這個表空間;但只要表空間中的任一頁做過修改,增量備份就會掃描這個表空間中的所有頁,並通過 page header 中的內容判斷該頁是否需要備份,這個過程甚至會導致增量備份花的時間比全備還要長。另外需要注意的一點是,如果表空間修改過的頁數過少,導致 db2med EDU 長時間拿不到數據,存儲管理器可能會認為 db2 已經 hang 住,從而中斷與 db2vend 的連接,導致備份失敗,對應的解決方案是將存儲管理器的 timeout 參數調大。
COMPRESS/ENCRYPT
如果備份啟用了壓縮或者加密,Db2 需要花額外的時間運行壓縮算法或者加密算法,會造成備份/恢復速度的下降。
BUFFER
BUFFER 的大小和數量會影響備份/恢復性能,Db2 會自動調優 buffer 的數量和大小,其總大小受限於數據庫配置參數 util_heap_sz。對於離線備份而言,backup buffer 總大小的理想值為 util_heap_sz 的 90%,對於在線備份而言,backup buffer 總大小理想值為 util_heap_sz 的 50%。buffer 的數量取決於 db2bm 和 db2med EDU 的數量。如果想人為設定數量和大小,可以在 backup/restore 命令中指定參數:'WITH num-buffers BUFFERS' 和 'BUFFER buffer-size'
PARALLELISM
開始備份時,每個 db2bm EDU 都會被分配給一個單獨的表空間。表空間是按照從大到小順序備份的,db2bm
份完一個表空間之后,就會檢查是否還有未備份的表空間,如果有的話就從里面選擇一個最大的進行備份,如果沒有的話就會保持空閑直到整個備份結束。db2bm EDU 的數量取決於 CPU 的數量,如果想要人為修改,則可以在 backup/restore 命令中指定 PARALLELISM 參數。
OPEN SESSIONS
如果是備份到磁盤上,backup 命令的 TO 選項指定了多少個路徑,就會有多少個 db2med EDU,每個 db2med 把數據寫到自己對應的路徑;如果是備份到存儲管理器, db2med 的數量取決於參數 'OPEN <N> SESSIONS'。對於恢復操作,只有一個 db2med EDU。
如果設置了 DB2_BACKUP_USE_DIO 為 ON,那么備份的時候,備份文件不會經過操作系統層面的緩存,而是直接寫到磁盤上。這個會對備份的性能造成一定影響,具體是提高性能還是降低性能,與具體的場景有關,在實際中需要做測試。
在線備份兼容性
如果是在線備份,則很多操作都會與之不兼容,根據表空間類型和操作的不同,在線備份可能會暫掛以等待其他操作完成,也可能失敗。因此,在線備份應該盡量辟開這些操作。具體的兼容性列表可以參考附錄
表空間高水位線以下空閑 extent
備份的時候,正常情況下會讀取高水位線以下連續的、已經使用的 extent,直到讀滿一個 backup buffer,算一次讀取操作。如果有 free extent,遇到 free extent 時讀取就會中斷,那么原本只需要一次讀取的操作就會被分為多次,導致備份的速度降低,這一點對在線備份的影響尤其明顯。
預取
上面已經說過,如果表空間有多個容器,備份的時候不是由 db2bm EDU 直接讀取數據,而是由多個預取線程 db2pfchr 來並行讀取的,並行 I/O 可以加快讀取速度從而減少備份時間。
目標設備的個數
如果可能,指定多個目標設置有助於加快備份速度。
備份/恢復進度監控
可以使用 db2 list utilities show detail
或者 db2pd -utilities
命令來查看備份/恢復操作的進度,下面的清單 1 是一個監控備份操作的示例:
清單 1. 監控備份操作進度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$ db2 list utilities show detail
ID = 81
Type = BACKUP
Database Name = SAMPLE
Member Number = 0
Description = offline db
Start Time = 02/28/2018 16:20:08.523339
State = Executing
Invocation Type = User
Throttling:
Priority = Unthrottled
Progress Monitoring:
Estimated Percentage Complete = 28
Total Work = 1187160686 bytes
Completed Work = 337194070 bytes
Start Time = 02/28/2018 16:20:08.523349
|
從示例中可以看到總的工作量估計值大約為 1187160686 bytes,已經完成的工作量為 337194070 bytes, 完成百分比為 28%,可以根據 Start Time 和已經完成百分比預估結束時間。
備份/恢復性能問題數據收集
當備份/恢復出現性能問題,或者需要調優的時候,首先需要收集足夠的數據來找出性能問題的瓶頸,需要收集的數據主要包括 Db2
份/恢復性能統計信息、Stack 數據、db2 trace 以及操作系統層面的一些數據
備份/恢復性能統計信息
自從 Db2 10.1FP2 開始,每次 backup/restore 完成后,db2diag.log 中就會記錄一條類似清單 2 中的消息,列出了詳細性能統計信息:
清單 2. 備份/恢復性能統計信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
2018-02-28-06.47.20.921681-480 E548681E1520 LEVEL: Info
PID : 2590 TID : 140213653333760 PROC : db2sysc 0
INSTANCE: inst105 NODE : 000 DB : SAMPLE
APPHDL : 0-152 APPID: *LOCAL.inst105.180228144458
AUTHID : INST105 HOSTNAME: db2a
EDUID : 216 EDUNAME: db2agent (SAMPLE) 0
FUNCTION: DB2 UDB, database utilities, sqluxLogDataStats, probe:395
MESSAGE : Performance statistics
DATA #1 : String, 1016 bytes
Parallelism = 4
Number of buffers = 4
Buffer size = 16388096 (4001 4kB pages)
BM# Total I/O MsgQ WaitQ Buffers kBytes
--- -------- -------- -------- -------- -------- --------
000 140.23 11.29 0.02 128.72 10 119264
001 140.22 139.54 0.00 0.18 178 2837632
002 140.22 0.42 0.00 139.79 1 1904
003 140.22 0.38 0.00 139.83 1 1920
--- -------- -------- -------- -------- -------- --------
TOT 560.91 151.65 0.02 408.54 190 2960720
MC# Total I/O MsgQ WaitQ Buffers kBytes
--- -------- -------- -------- -------- -------- --------
000 140.94 11.64 128.58 0.01 191 3024788
--- -------- -------- -------- -------- -------- --------
TOT 140.94 11.64 128.58 0.01 191 3024788
|
含義如下:
- BM. db2bm ID
- Total. EDU 存在的時間,單位為秒
- I/O. EDU 讀寫 I/O 的時間,如果此項占比高,說明瓶頸很可能在 I/O
- MsgQ. EDU 等待 I/O buffer 的時間,如果 db2bm 的此項占比高,說明 free buffer 少,可以增加備份時的 buffer 的數量。
- WaitQ. 等待控制信息的時間,如果 db2bm 這一項比較高,說明 db2bm EDU 比較空閑
- Buffers. 處理的 I/O buffers 數量
- Kbytes. 處理的數據量
- MC. db2med ID
- Compr. 壓縮操作占用的時間,僅壓縮備份中會出現
- Compr Bytes. 壓縮的數據,僅壓縮備份中會出現
db2pd –stack
stack 是針對性能問題的一項很有用的數據,如果是在線備份並且應用不多,建議收集所有 EDU 的 stack,即 db2pd -stack all 命令。否則,建議至少收集備份/恢復應用的 stack。清單 3 是某次備份作業時 db2pd -edu 命令的輸出,以其為例,db2bm EDU name 為 db2bm.17686.x,其中 17686 即為備份作業對應的 EDU ID:
清單3. 根據db2bm名找到db2agent EDU
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
$ db2pd -edu
Database Member 0 -- Active -- Up 1 days 19:26:08 -- Date 2018-02-28-11.06.04.936264
List of all EDUs for database member 0
db2sysc PID: 12910796
db2wdog PID: 11403362
db2acd PID: 8585382
EDU ID TID Kernel TID EDU Name
=============================================================================
19228 19228 128516107 db2med.17686.0 (SAMPLE) 0
18971 18971 16187529 db2bm.17686.4 (SAMPLE) 0
18714 18714 124846105 db2bm.17686.3 (SAMPLE) 0
18457 18457 127795435 db2bm.17686.2 (SAMPLE) 0
18200 18200 121700431 db2bm.17686.1 (SAMPLE) 0
17943 17943 125304835 db2bm.17686.0 (SAMPLE) 0
17686 17686 21233761 db2agent (SAMPLE) 0
...
|
然后再根據清單 4 中 db2pd -agent 的輸出,找到 17686 對應的 Application handle 為 1473:
清單 4. 根據 db2agent 找到 application handle
1
2
3
4
5
6
7
|
$ db2pd -agent
Database Member 0 -- Active -- Up 1 days 19:26:09 -- Date 2018-02-28-11.06.05.114288
Address AppHandl [nod-index] AgentEDUID Priority Type State
...
0x078000000334BE80 1473 [000-01473] 17686 0 Coord Inst-Active
|
最后針對 application handle 為 1473 的應用收集 stack,命令為 db2pd -stack apphdl=1473 -rep 60 2
,
表示只針對 1473 收集 stack,重復兩次,間隔為 60 秒。
db2 trace
某些性能問題可能還要收集 db2 trace,類似地,可以在收集 db2 trace 的時候指定 apphdl,以上一節的 application handle 為例,可以執行清單 5 中的命令來收集 trace:
清單 5 針對 application 收集 trace
1
2
3
4
5
6
7
|
$ db2trc on -l 512m -t -apphdl 1473
$ db2trc dmp trcBackup.dmp.1
$ sleep 60
$ db2trc dmp trcBackup.dmp.2
$ sleep 60
$ db2trc dmp trcBackup.dmp.3
$ db2trc off
|
除了上面提到的 Db2 層面的數據之外,操作系統層面的數據也是必不可少的,例如 vmstat、iostat 等。
備份/恢復性能問題實例
這一部分舉幾個備份/恢復性能問題的具體例子
表空間數據分布不均勻導致的備份性能問題
首先來看一個表空間數據分布不均勻導致的備份性能問題,某數據庫的備份性能統計信息如清單 6 所示:
清單 6. 某次備份的性能統計信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
2018-02-28-06.47.20.921681-480 E548681E1520 LEVEL: Info
PID : 2590 TID : 140213653333760 PROC : db2sysc 0
INSTANCE: inst105 NODE : 000 DB : SAMPLE
APPHDL : 0-152 APPID: *LOCAL.inst105.180228144458
AUTHID : INST105 HOSTNAME: db2a
EDUID : 216 EDUNAME: db2agent (SAMPLE) 0
FUNCTION: DB2 UDB, database utilities, sqluxLogDataStats, probe:395
MESSAGE : Performance statistics
DATA #1 : String, 1016 bytes
Parallelism = 4
Number of buffers = 4
Buffer size = 16388096 (4001 4kB pages)
BM# Total I/O MsgQ WaitQ Buffers kBytes
--- -------- -------- -------- -------- -------- --------
000 140.23 11.29 0.02 128.72 10 119264
001 140.22 139.54 0.00 0.18 178 2837632
002 140.22 0.42 0.00 139.79 1 1904
003 140.22 0.38 0.00 139.83 1 1920
--- -------- -------- -------- -------- -------- --------
TOT 560.91 151.65 0.02 408.54 190 2960720
MC# Total I/O MsgQ WaitQ Buffers kBytes
--- -------- -------- -------- -------- -------- --------
000 140.94 11.64 128.58 0.01 191 3024788
--- -------- -------- -------- -------- -------- --------
TOT 140.94 11.64 128.58 0.01 191 3024788
|
可以看到所有 db2bm EDU 花費了 560.91 秒,僅 WaitQ 就占用了 408.54 秒,占比高達 72.8%。說明大部分 db2bm EDU 都在等着做事,比較空閑,只有 db2bm001 比較忙。導致這種現象的原因就是表空間的數據分布不均勻,有一個表空間比較大,其他的都比較小,從 BM#部分最后一列的 KBytes 也能看出來:db2bm001 處理的數據量明顯比其他 db2bm EDU 多。
對應的解決方案是使數據盡可能均勻地分布在不同的表空間,使每個 db2bm EDU 的工作量都基本一致,不會有空閑的 db2bm EDU。這樣能提高性能的前提是 CPU、內存、I/O 沒有瓶頸,否則反而可能降低備份性能,例如如果表空間容器都在同一塊磁盤上,則同時備份多個表空間可能會引起 I/O 爭用。
過多 Free extent 導致的備份性能問題
再來看一個由於表空間高水位以下太多空閑 extent 導致的備份性能問題,具體現象為刪除了約一半無用的表,之后備份的數據量大約為原來的 54%,但備份的時間卻只降低為原來的 77%。刪除表前后的備份性能統計信息分別如清單 7 和清單 8 所示:
清單 7. 刪表之前備份性能統計信息
1
2
3
4
5
6
7
8
9
10
11
12
13
|
BM# Total I/O MsgQ WaitQ Buffers kBytes
--- -------- -------- -------- -------- -------- --------
000 167.46 166.95 0.00 0.01 319 5178992
001 167.45 0.45 0.03 166.96 1 608
002 167.45 4.61 0.00 162.83 7 112768
--- -------- -------- -------- -------- -------- --------
TOT 502.37 172.02 0.03 329.81 327 5292368
MC# Total I/O MsgQ WaitQ Buffers kBytes
--- -------- -------- -------- -------- -------- --------
000 169.78 14.93 152.52 0.00 328 5342520
--- -------- -------- -------- -------- -------- --------
TOT 169.78 14.93 152.52 0.00 328 5342520
|
清單 8. 刪表之后備份性能統計信息
1
2
3
4
5
6
7
8
9
10
11
12
13
|
BM# Total I/O MsgQ WaitQ Buffers kBytes
--- -------- -------- -------- -------- -------- --------
000 129.61 0.22 0.01 129.36 3 608
001 129.60 2.30 0.00 127.28 7 112768
002 129.60 128.72 0.00 0.02 168 2589664
--- -------- -------- -------- -------- -------- --------
TOT 388.81 131.25 0.01 256.67 178 2703040
MC# Total I/O MsgQ WaitQ Buffers kBytes
--- -------- -------- -------- -------- -------- --------
000 131.29 7.44 122.15 0.00 179 2900708
--- -------- -------- -------- -------- -------- --------
TOT 131.29 7.44 122.15 0.00 179 2900708
|
對比前后的性能統計信息,發現刪表之前備份讀取速率為大約為 30MB 每秒,計算方法為 BM#的 kBytes 除以 I/O 時間:5292368kBytes/172.02=30MB/S,刪表之后備份時讀取速率為 2703040kBytes/131.25=20MB/S。聯想到刪表之后會有一些空閑的 extents,於是使用 db2dart 的 DHWM 選項看了一下對應的表空間高水位狀況,如清單 9 所示,可以看到有很多 EMPTY 的 extent:
清單 9. db2dart /DHWM 檢查表空間結果:
1
2
3
4
5
6
7
|
...<略>...
[15992] 5 0x00 [15993] == EMPTY == [15994] 5 0x00 [15995] == EMPTY ==
[15996] 5 0x00 [15997] == EMPTY == [15998] 5 0x00 [15999] == EMPTY ==
[16000] 65534 0x0e [16001] 5 0x00 [16002] == EMPTY == [16003] 5 0x00
[16004] == EMPTY == [16005] 5 0x00 [16006] == EMPTY == [16007] 5 0x00
[16008] == EMPTY == [16009] 5 0x00 [16010] == EMPTY == [16011] 5 0x00
...<略>...
|
以上面結果為例,如果沒有 EMPTY 的 extent,那么從 15992 到 16011 的這些 extent 都可以在一次讀操作讀完。有了 EMPTY extent 之后,讀操作遇到 EMPTY extent 就會中斷,於是 15992、15994、15996、15998 等都需要一次單獨的讀操作,導致讀取的速率降低,從而影響了備份的性能。使用 db2 list tablespaces show detail
也可以看到該表空間狀況如清單 10 所示:
清單 10. 表空間使狀況
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Tablespace ID = 3
Name = USERSPACE1
Type = Database managed space
Contents = All permanent data. Large table space.
State = 0x0000
Detailed explanation:
Normal
Total pages = 2621440
Useable pages = 2621438
Used pages = 647416
Free pages = 1974022
High water mark (pages) = 1294746
Page size (bytes) = 4096
Extent size (pages) = 2
Prefetch size (pages) = 2
Number of containers = 1
Minimum recovery time = 2018-03-05-02.47.06.000000
|
可以從清單 10 中看到高水位為 1294746,但 Used Pages 只有 647416。對應的解決方案是使用 db2 alter tablespace <tbsname> lower high water mark
命令降低表空間的高水位,降高水位之后再次測試備份只用了 93.36 秒,降低為最初始 169.78 秒的 55%,達到預期效果。
Linux 文件系統預分配導致的恢復性能問題
再來看一個恢復時遇到的問題,客戶反饋說在做 Db2 恢復測試的時候,通過 db2pd -uti
或者 db2 list utilities show detail
監控到恢復操作很長時間沒有任何進展(HANG 住),但文件系統可用空間卻越來越少。這一現象只在 Linux 上發現,在 AIX 上無此現象。於是收集了一些數據,首先看一下,恢復表現正常時,db2med 和 db2bm 的 stack,如清單 11 所示,可以看到 db2med 在從 FileDevice 讀數據,db2bm 在寫數據:
清單 11:正常恢復時 db2med 和 db2bm 的 stack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
db2med:
<
StackTrace
>
------FUNCTION------
read
sqloread
sqloreadEx
sqluReadFromFileDevice
sqluMCReadFromDevice
sqluMCReadFromDev4Restore
sqluMCContinueRestore
sqluMCProcessRestoreStatesP
sqluMCStartRestoreMediaControllerPcj
...
</
StackTrace
>
db2bm
<
StackTrace
>
------FUNCTION------
pwrite
sqloseekwrite64
sqloWriteBlocks
sqlbDMSMapAndWrite
sqlbDMSDirectWrite
sqlbDirectWrite
sqluWriteDMS
sqludBMCont
sqludbufPcj
...
</
StackTrace
>
|
再來看一下,"HANG"住的時候,db2med 和 db2bm 的 stack,如清單 12 所示,db2med 並沒有在讀數據; db2bm 確實在寫,但並不是寫備份的數據,里面比較關鍵的函數: RestoreContainers -> DMSAddContainerRequest -> SetFileSize -> sqlowrite,從這幾個函數來看,db2bm 正在做的事情是處理添加容器請求(DMSAddContainerRequest), 設置容器大小(SetFileSize),之后調用 sqlowrite 實現容器空間的預分配。
清單 12. HANG 住時 db2med 和 db2bm 的 stack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
db2med:
<
StackTrace
>
------FUNCTION------
msgrcv
sqlorqueInternal
sqlorque2
sqluReadBufferFromQueue
sqluMCContinueRestore
sqluMCProcessRestoreStatesP
sqluMCStartRestoreMediaControllerPcj
...
</
StackTrace
>
db2bm:
<
StackTrace
>
------FUNCTION------
write
sqlowrite
sqloSetFileSize
sqlbServiceAddDMSContainerRequest
sqlbDMSAddContainerRequest
sqlbDoDMSAddContainerRequests
sqlbASSetPoolContsForDMS
sqlbASDefineContainersForDMS
sqlbRestoreASContainers
sqlbRestoreContainers
sqlbRestorePoolDef
sqludProcessSPCS
sqludBMInit
sqludbufPcj
sqloEDUEntry
...
</
StackTrace
>
|
至此,問題比較明確:數據庫 restore 操作並非真正 HANG 住,而是 db2 正在進行 DMS 表空間容器的預分配,等容器分配完成之后,才能繼續恢復數據。在檢查了文件系統之后,發現是 EXT3 格式, EXT3 格式的文件系統不支持 fast-allocation,創建文件的操作會非常慢,創建數據庫、 恢復數據庫、創建容器等操作都會受到影響。 解決的方案就是使用支持 fast-allocation 的文件系統,比如 GPFS、 JFS2(AIX), 如果是 LINUX 系統,可以考慮將 EXT3 升級成 EXT4。
結束語
優化的前提是對背后原理的深入了解,所以本文從 Db2 backup/restore 的線程模型開始講起,之后詳細介紹了影響 backup/restore 性能的內部和外部原因,最后通過幾個實例講解了針對 backup/restore 性能問題的數據收集與分析方法。由於篇幅限制,本文所講知識點不可能面面俱到,有興趣的讀者可以進一步閱讀參考資料中的文檔,遇到問題時也可收集數據提交至 IBM 技術中心獲取幫助。