程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> DB2數據庫 >> DB2教程 >> 分析 DB2 for Linux, UNIX, and Windows 中的鎖等待情形

分析 DB2 for Linux, UNIX, and Windows 中的鎖等待情形

編輯:DB2教程

用於鎖監視的 db2pd 選項

db2pd 是用於監視各種 DB2 數據庫活動以及故障排除的實用程序。它是從 DB2 V8.2 開始隨 DB2 引擎發布的一個獨立的實用程序,其外觀和功能類似於 Informix onstat 實用程序。db2pd 是從命令行以一種可選的交互模式執行的。該實用程序運行得非常快,因為它不需要獲取任何鎖,並且在引擎資源以外運行(這意味著它甚至能在一個掛起的引擎上工作)。通過快照監視還可以收集 db2pd 提供的很多監視器數據,但是 db2pd 和快照監視的輸出格式卻有很大不同。這使 DBA 可以選擇更符合用戶需求的監視替代方法。本文關注用於鎖監視的 db2pd 選項。

下面的圖展示了用於鎖監視的 db2pd 選項:

圖 1. 用於鎖監視的 db2pd 選項

分析 DB2 for Linux, UNIX, and Windows 中的鎖等待情形

TranHdl:用於指定事務句柄,以便只監視由特定事務持有的鎖。

showlocks:這個子選項將鎖名稱擴展成有意義的解釋。對於一個行鎖,該選項顯示以下信息:表空間 ID、表 ID、分區 ID、頁和槽。通過使用編目視圖 SYSCAT.TABLES 上的一個查詢,很容易將表空間 ID 和表 ID 映射到相應的表名:

清單 1. 將表空間 ID、表 ID 映射到表模式、表名

SELECT TABSCHEMA, TABNAME
FROM SYSCAT.TABLES
WHERE TBSPACEID = tbspaceid AND TABLEID = tableid

wait:如果指定 wait 子選項,則 db2pd 只顯示事務當前正在等待的鎖,以及對等待情形負責的鎖。這個子選項大大簡化了鎖等待分析,因為它將輸出限制為參與鎖等待情形的鎖。

db2pd database 和 file 選項不是特定於鎖監視的,但是適用於(幾乎)所有 db2pd 調用。database 選項將 db2pd 返回的監視器數據限制為某個數據庫的監視器數據。而 file 選項則允許定義一個文件,以便將 db2pd 輸出寫到該文件。

鎖等待分析場景

接下來,我們開始使用前面介紹的 db2pd 選項來分析一個示例鎖等待情形。為此,我們創建 DB2 SAMPLE 數據庫:

清單 2. 創建 SAMPLE 數據庫

db2sampl

用戶 A 執行事務 A,以根據每個經理的薪水為他們提供 10% 的獎金:

清單 3. 事務 A 執行的更新操作

UPDATE EMPLOYEE
SET BONUS = SALARY * 0.1
WHERE JOB = 'MANAGER'

當事務 A 仍然在運行(因為用戶 A 還沒有使用 COMMIT 或 ROLLBACK 終止該事務)時,用戶 B 執行事務 B,以將每個雇員的薪水提高 2%:

清單 4. 事務 B 執行的更新操作

UPDATE EMPLOYEE
SET SALARY = SALARY * 0.02

由於事務 B 沒有完成,用戶 B 請求 DBA 確定問題的原因。於是,DBA 調用 db2pd,看是否存在鎖等待情形:

清單 5. 檢查鎖等待情形

db2pd -db sample -locks wait showlocks
Database Partition 0 -- Database SAMPLE -- Active -- Up 3 days 08:33:05
Locks:
Address  TranHdl  Lockname          Type    Mode Sts Owner   Dur
0x050A0240 6     02000600050040010000000052 Row    ..X W  2     1 
0x050A0DB0 2     02000600050040010000000052 Row    ..X G  2     1 
HoldCount Att ReleaseFlg
0     0x00 0x40000000  TbspaceID 2 TableID 6 PartitionID 0 Page 320 Slot 5
0     0x00 0x40000000  TbspaceID 2 TableID 6 PartitionID 0 Page 320 Slot 5

db2pd 報告 ID 為 2 的表空間中一個 ID 為 6 的表上有一個行鎖存在鎖等待情形。通過檢查 SYSCAT.TABLES,DBA 斷定表 EMPLOYEE 上的確存在鎖等待。

清單 6. 確定鎖等待情形所涉及的表

SELECT TABSCHEMA, TABNAME
FROM SYSCAT.TABLES
WHERE TBSPACEID = 2 AND TABLEID = 6
TABSCHEMA                TABNAME
--------------------------------------------------------------------------------
FECHNER                 EMPLOYEE
 1 record(s) selected.

對於事務 2(列 TranHdl),db2pd -locks 輸出的 status 列(Sts)顯示一個 “G”。G 代表 “granted”,意即事務句柄為 2 的事務擁有行鎖。此外,列 Mode 表明,事務 2 持有的是一個 X 鎖。等待的事務(列 Sts 中顯示 “W”(“wait”)的事務)是句柄為 6 的事務。該事務正在與事務 2 請求同一個行上的 X 鎖。通過查看 Owner 列(顯示事務 2 是鎖的所有者)和比較 Lockname(對於 db2pd -locks 中的兩個條目是相同的),可以看到這一點。

接下來,DBA 將事務句柄映射到應用程序。這可以使用另一個 db2pd 選項 -transactions 來完成:

清單 7. 將事務句柄映射到應用程序

db2pd -db sample -transactions
Database Partition 0 -- Database SAMPLE -- Active -- Up 3 days 08:34:47
Transactions:
Address  AppHandl [nod-index] TranHdl  Locks   State  Tflag   Tflag2
0x05141880 30    [000-00030] 2     9     WRITE  0x00000000 0x00000
0x05144880 34    [000-00034] 6     5     WRITE  0x00000000 0x00000

這個 db2pd 調用的輸出表明,事務 2(列 TranHdl)是由應用程序 30(列 AppHandl)執行的,而事務 6 是由應用程序 34 執行的。這兩個事務都正在對數據庫執行寫更改(列 State = WRITE)。所以 DBA 現在知道,應用程序 30 正持有應用程序 34 所等待的鎖。

要獲得關於鎖等待情形涉及的應用程序的更多信息,可使用 -agents 選項調用 db2pd。該選項打印代表應用程序運行的代理的信息。注意,-agents 是一個實例級選項,這意味著不需要指定一個數據庫(實際上,當指定一個數據庫時,db2pd 打印出一條警告,並忽略 database 選項)。

清單 8. 獲得關於應用程序和相應代理的信息

db2pd -agents
Database Partition 0 -- Active -- Up 3 days 08:35:42
Agents:
Current agents:   2
Idle agents:     0
Active coord agents: 2
Active agents total: 2
Pooled coord agents: 0
Pooled agents total: 0
Address  AppHandl [nod-index] AgentTid  Priority  Type   State
0x04449BC0 34    [000-00034] 3392    0     Coord  Inst-Active
0x04449240 30    [000-00030] 2576    0     Coord  Inst-Active
ClientPid Userid  ClIEntNm Rowsread  Rowswrtn  LkTmOt DBName
3916    USER_B  db2bp.ex 43     43     NotSet SAMPLE
2524    USER_A  db2bp.ex 153    14     NotSet SAMPLE

在 db2pd -agents 輸出中,DBA 可以看到使用應用程序 30 和 34 的用戶的 ID(列 Userid):應用程序 30 是由 USER_A 執行的,而應用程序 34 是由 USER_B 執行的。只有當每個用戶都有一個單獨的數據庫授權 ID 時,才可能出現那樣的應用程序與用戶 ID 之間的映射。通常,這對於在應用服務器上運行的應用程序是不可能的,因為這些應用程序使用連接池,連接不是個人化的。

關於每個應用程序的更多信息則由 db2pd 選項 -applications 提供:

清單 9. 獲得關於應用程序的更多信息

db2pd -db sample -applications
Database Partition 0 -- Database SAMPLE -- Active -- Up 3 days 08:36:14
Applications:
Address  AppHandl [nod-index] NumAgents CoorTid  Status         
0x04AF8080 34    [000-00024] 1     3940    Lock-wait       
0x03841960 30    [000-00020] 1     2548    UOW-Waiting      
C-AnchID C-StmtUID L-AnchID L-StmtUID Appid
195   1     0    0     *LOCAL.DB2.061122195637
0    0     60    1     *LOCAL.DB2.061122195609

Status 列確認了 DBA 已經知道的一些東西:應用程序 34 處在鎖等待狀態。但是這並不新鮮,於是 DBA 將注意力集中在列 C-AnchID/C-StmtUID 和 L-AnchID/L-StmtUID 上。“C” 代表當前(current),“L” 代表最近(last)的錨 ID/語句 UID。這些 ID 可用於標識應用程序最近執行的 SQL 語句和應用程序當前執行的語句。為此,可以用 -dynamic 選項調用 db2pd。該選項顯示數據庫動態語句緩存的內容:

清單 10. 檢查動態語句緩存的內容

db2pd -db sample -dynamic
Database Partition 0 -- Database SAMPLE -- Active -- Up 3 days 08:37:39
Dynamic Cache:
Current Memory Used      187188
Total Heap Size        1271398
Cache Overflow Flag      0
Number of References     2
Number of Statement Inserts  3
Number of Statement Deletes  0
Number of Variation Inserts  2
Number of Statements     3
Dynamic SQL Statements:
Address  AnchID StmtUID  NumEnv   NumVar   NumRef   NumExe  
0x056CEBD0 60   1     1     1     1     1     
0x056CE850 180  1     0     0     0     0     
0x056CFEA0 195  1     1     1     1     1     
Text
UPDATE EMPLOYEE SET BONUS = SALARY * 0.1 WHERE JOB = 'MANAGER'
SET CURRENT LOCALE LC_CTYPE = 'de_DE'
UPDATE EMPLOYEE SET SALARY = SALARY * 0.02
Dynamic SQL Environments:
Address  AnchID StmtUID  EnvID Iso QOpt Blk
0x056CECD0 60   1     1   CS 5  B
0x056D30A0 195  1     1   CS 5  B
Dynamic SQL Variations:
Address  AnchID StmtUID  EnvID VarID   NumRef   Typ
0x056CEEB0 60   1     1   1     1     4 
0x056D3220 195  1     1   1     1     4 
Lockname
010000000100000001003C0056
01000000010000000100C30056

-applications 輸出與 -dynamic 輸出之間的映射很簡單:

應用程序 34(處於鎖等待狀態)當前正在執行當前錨 ID 195 和當前語句 ID 1 所標識的 SQL 語句。在 db2pd -dynamic 輸出的 Dynamic SQL Statements 部分中,那些 ID 可以映射到以下 SQL 語句:

清單 11. 應用程序 34 執行的 SQL 語句

UPDATE EMPLOYEE SET SALARY = SALARY * 0.02

持有鎖的應用程序 30 最近執行的 SQL 語句是最近錨 ID 60 和最近語句 ID 1 所標識的 SQL 語句。那些 ID 可以映射到以下 SQL 語句:

清單 12. 應用程序 30 執行的 SQL 語句

UPDATE EMPLOYEE SET BONUS = SALARY * 0.1 WHERE JOB = 'MANAGER'

注意,db2pd -dynamic 輸出包含另一個通常難以發現的有趣信息:Dynamic SQL Environments 部分的列 Iso 中顯示了被執行的動態 SQL 語句的隔離級別(UR = Uncommitted Read,CS = Cursor Stability,RS = Read Stability,RR = Repeatable Read)。

我們來總結一下 DBA 就用戶 B 的應用程序被掛起的原因有什麼發現:

掛起是由表 EMPLOYEE 上一個獨占式的行鎖導致的。

持有鎖的事務屬於用戶 A 執行的一個應用程序。而用戶 B 的事務正在等待那個鎖。

兩條有沖突的語句都是表 EMPLOYEE 上的 UPDATE 語句。

有了這些信息,DBA 可以開始采取一些必要的步驟來解決鎖等待狀況,例如建議用戶 A 終止事務,或者強制關閉用戶 A 的應用程序。此外,可以采取措施避免將來出現那樣的狀況,例如配置 DB2 控制器(governor),使之自動終止運行時間過長的事務。

在這個示例場景中,db2pd 被連續執行數次,每次使用一個單獨的選項。現實中不會出現這樣的情況。相反,db2pd 只被調用一次,調用時同時使用前面介紹的所有選項:

清單 13. 分析鎖等待情形所需的帶有所有選項的單個 db2pd 調用

db2pd -db sample -locks wait showlocks -transactions -agents -applications -dynamic
   -file db2pd.out -repeat 15 40

產生的輸出由針對每個選項的輸出組成,各部分輸出之間的順序與各選項在 db2pd 調用中的順序一致。而且,請注意 db2pd 調用最後的 2 個附加選項:

-file 表明 db2pd 輸出應該被寫到一個文件。在示例調用中,輸出被寫到文件 db2pd.out 中。

-repeat 表明 db2pd 應該每隔 15 秒執行一次,共執行 40 次(即每隔 15 秒執行一次,共執行 10 分鐘)。每次執行的輸出被附加到 -file 選項指定的文件後面。

-file 和 -repeat 選項對於在一段時間內監視數據庫活動比較有用。對於鎖等待分析,這兩個選項可以幫助捕捉只存在一小段時間的鎖等待情形。例如,如果數據庫參數 LOCKWAIT 被設置為 20 秒,一個等待鎖的事務在過了 20 秒的等待時間後被回滾。為了捕捉那樣的鎖等待情形,db2pd 的時間間隔必須設置為比 20 秒更短的時間間隔,例如例子中的 15 秒。

捕捉罕見的鎖超時

有時候,鎖等待情形會導致鎖超時,而鎖超時又會導致事務被回滾。鎖等待導致鎖超時所需的時間段由數據庫配置參數 LOCKTIMEOUT 指定。鎖超時分析最大的問題是,不知道下一次的鎖超時何時發生。為了捕捉死鎖,可以創建一個死鎖事件監視器。每當出現死鎖時,這個死鎖事件監視器便寫一個條目。但是,對於鎖超時就沒有類似的事件監視器。所以到 DB2 9® 為止,捕捉鎖超時的惟一方法還是連續的 db2pd 或快照監視(對於 db2pd,和前面解釋的一樣,-file 和 -repeat 選項可用於連續的鎖監視)。

DB2 9 包含了一種新的機制,用於在數據庫出現故障或發生事件時收集監視器數據:db2cos 腳本。為了捕捉鎖超時事件,可以配置數據庫,使之每當出現鎖超時時啟動 db2cos 腳本。在 db2cos 腳本中,和前面討論的一樣,可以以相同的選項調用 db2pd。我們來看一個示例場景,該場景演示了如何用 db2cos 腳本捕捉鎖超時。

對於這個場景,假設 DBA 將數據庫鎖超時值設為 10 秒:

清單 14. 更新鎖超時設置

UPDATE DB CFG FOR SAMPLE USING LOCKTIMEOUT 10

為了每當出現鎖超時時啟動 db2cos 腳本,DBA 調用 db2pdcfg 實用程序,如下所示:

清單 15. 使用 db2pdcfg 配置 db2cos 腳本的調用

db2pdcfg -catch locktimeout count=1

-catch 選項指定應該自動導致調用 db2cos 腳本的故障或事件。對於鎖超時事件,可以指定字符串 locktimeout。或者,可以指定與鎖超時相應的 SQL 錯誤碼和原因碼:

清單 16. 用於捕捉鎖超時的另一種 db2pdcfg 調用

db2pdcfg -catch 911,68 count=1

除了一些字符串值和 SQL 代碼之外,db2pdcfg 還接受內部 DB2 錯誤碼。所以,用這種方式可以捕捉很多數據庫故障和事件。鎖超時事件只是使用 db2pdcfg 和 db2cos 的一個例子。

如果 count 子選項的值為 1,則表明當出現鎖超時事件時應該執行 db2cos 腳本。

db2pdcfg 通過以下輸出確認錯誤捕捉的設置:

清單 17. db2pdcfg 對錯誤捕捉設置的確認

Error Catch #1
  Sqlcode:    0
  ReasonCode:   0
  ZRC:      -2146435004
  ECF:      0
  Component ID:  0
  LockName:    Not Set
  LockType:    Not Set
  Current Count: 0
  Max Count:   1
  Bitmap:     0x4A1
  Action:     Error code catch flag enabled
  Action:     Execute sqllib/db2cos callout script
  Action:     Produce stack trace in db2diag.log

db2diag.log 報告中也包括錯誤捕捉設置。可以使用 db2diag 實用程序(用於檢查 db2diag.log 內容的一個有用的實用程序)過濾 db2diag.log 文件,而不必在一個文本編輯器中打開它:

清單 18. 在 db2diag.log 中確認錯誤捕捉設置

db2diag -g funcname:=pdErrorCatch
2006-12-18-13.37.25.177000+060 I727480H285    LEVEL: Event
PID   : 4648         TID : 3948    PROC : db2syscs.exe
INSTANCE: DB2         NODE : 000
FUNCTION: DB2 UDB, RAS/PD component, pdErrorCatch, probe:30
START  : Error catch set for ZRC -2146435004

ZRC -2146435004 是用於鎖超時的 DB2 內部錯誤碼。可以通過下面的 db2diag 調用查看這些錯誤碼:

清單 19. 使用 db2diag 查看 DB2 內部錯誤碼的含義

db2diag -rc -2146435004

通過使用 db2pdcfg,數據庫引擎現在被配置為每當出現鎖超時時調用 db2cos 腳本。db2cos 腳本收集判別鎖超時原因所需的所有監視器信息。為此,DBA 必須修改 db2cos 腳本,以便用已知的選項調用 db2pd。可以在下面的子目錄中找到 db2cos 腳本:

Windows:DB2 install directoryBINdb2cos.bat,例如 C:Program FilesIBMSQLLIBBINdb2cos.bat

UNIX/Linux:Instance owner home/sqllib/bin/db2cos

在 Microsoft Windows® 上,默認的 db2cos.bat 腳本看上去如下所示:

清單 20. Windows 上默認 db2cos.bat 的內容

setlocal
:iterargs
if %0. == . goto iterdone
  if /i %0. == INSTANCE. set INSTANCE=%1
  if /i %0. == DATABASE. set DATABASE=%1
  if /i %0. == TIMESTAMP. set TIMESTAMP=%1
  if /i %0. == APPID. set APPID=%1
  if /i %0. == PID. set PID=%1
  if /i %0. == TID. set TID=%1
  if /i %0. == DBPART. set DBPART=%1
  if /i %0. == PROBE. set PROBE=%1
  if /i %0. == FUNCTION. set FUNCTION=%1
  if /i %0. == REASON. set REASON=%1
  if /i %0. == DESCRIPTION. set DESCRIPTION=%1
  if /i %0. == DiAGPATH. set DIAGPATH=%1
  shift
goto iterargs
:iterdone
if %DATABASE%. == . goto no_database
  db2pd -db %DATABASE% -inst >> %DIAGPATH%db2cos%PID%%TID%.%DBPART%
  goto exit
:no_database
  db2pd -inst >> %DIAGPATH%db2cos%PID%%TID%.%DBPART%
:exit

對於數據庫級的事件或故障,默認的 db2cos 腳本用 -db 和 -inst 選項調用 db2pd。DBA 用一個 db2pd 調用替換相應的行,該調用收集鎖超時分析所需的監視器數據:

清單 21. 更改 db2cos 腳本,以收集用於鎖超時分析的數據

if %DATABASE%. == . goto no_database
  db2pd -db %DATABASE% -locks wait -transactions -agents -applications -dynamic
     >> %DIAGPATH%db2cos%PID%%TID%.%DBPART%
  goto exit

現在,db2cos 腳本已准備好,DBA 可以坐等下一次鎖超時事件的發生。

假設像之前描述的那樣,用戶 A 與 B 之間發生相同的鎖情形。但是,這一次設置了 LOCKTIMEOUT,因此過了 10 秒(LOCKTIMEOUT = 10)之後用戶 B 的事務被回滾。用戶 B 通知 DBA 回滾自己的事務,並且收到 SQL 錯誤消息 -911 和原因碼 68(SQL code -911 / reason code 68 = locktimeout)。於是,DBA 檢查通過自動調用 db2cos 腳本收集到的監視器數據。

首先,DBA 用鎖超時內部錯誤碼調用 db2diag,以確定鎖超時發生的確切時間:

清單 22. 在 db2diag.log 中檢查鎖超時事件的時間點

db2diag -g data:=-2146435004
2006-12-18-14.27.24.656000+060 I6857H409     LEVEL: Event
PID   : 2968         TID : 2932    PROC : db2syscs.exe
INSTANCE: DB2         NODE : 000     DB  : SAMPLE
APPHDL : 0-21         APPID: *LOCAL.DB2.061226132544
AUTHID : FECHNER
FUNCTION: DB2 UDB, lock manager, sqlplnfd, probe:999
DATA #1 : <preformatted>
Caught rc -2146435004. Dumping stack trace.

db2diag.log 條目顯示,在 2006-12-18-14.27.24.656000 時發生了一次鎖超時。由於 db2cos 腳本將它的輸出寫到 %DIAGPATH% 中的 db2cos%PID%%TID%.%DBPART% 文件中,DBA 有望在實例的診斷路徑中找到一個 db2cos29682932.0 文件:

%DIAGPATH% = instance's diagnostic path = on Windows by default C:Program FilesIBMSQLLIBDB2

%PID% = process ID = 2968(如 db2diag.log 條目中所示)

%TID% = thread ID = 2932(也顯示在 db2diag.log 條目中)

%DBPART% = database partition = 0(在一個非分區數據庫環境中)

那個文件的內容很像本文第一部分中逐步考察的那個 db2pd 監視器輸出,DBA 可以通過它來識別鎖超時的原因。

捕捉到鎖超時後,DBA 可以通過 -catch clear 選項調用 db2pdcfg 來禁用 db2cos 腳本:

清單 23. 再次使用 db2pdcfg 清除錯誤捕捉設置

db2pdcfg -catch clear
All error catch flag settings cleared.

結束語

本文演示了如何使用 db2pd 實用程序進行鎖等待監視。本文借助一個示例場景展示了 DBA 如何通過檢查不同 db2pd 選項的輸出來識別並發問題的原因。從 DB2 9 開始,可以將 db2pd 與新的 db2cos 腳本一起使用,以便在出現鎖超時事件時捕捉它們。您學習了如何配置出現鎖超時事件時 db2cos 腳本的自動調用。本文還介紹了 db2diag 實用程序 —— 這是用於檢查 db2diag.log 內容的一個有用的工具。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved