1. 程式人生 > 資料庫 >分析DB2活動日誌滿的原因及解決DB2日誌滿方法與避免方案

分析DB2活動日誌滿的原因及解決DB2日誌滿方法與避免方案

日誌使用

下圖顯示了併發事務條件下,日誌使用的示意

有3個併發的程式Process 1、Process 2、Process 3。每一個程式都有兩個事務。藍塊代表SQL語句,紅塊代表commit操作,綠塊代表rollback操作。每一個向下的箭頭都代表日誌緩衝區的資料被重新整理到日誌磁碟上(預設是每一次提交操作都會導致日誌緩衝被重新整理到磁碟上)。

在T1時刻,事務A commit,日誌緩衝區被重新整理到磁碟上。
在T2時刻,事務B commit,日誌緩衝區被重新整理到磁碟上,此時日誌X使用完,但由於X中的事務C還沒有提交,所以X此時還是活動日誌。

在上圖中,如果事務C一直沒有提交操作,那麼日誌X將永遠是首個活動日誌(oldest transaction log),後續的日誌也是活動日誌,其他應用最終會導致日誌滿。

活動日誌

如果一個日誌中包含有未提交的事務,那麼這個日誌就是活動日誌(也有其他情況,比如雖然所有事務已經提交,但對應的更改還沒有持久化到磁碟上)。

首個活動日誌(First Active Log)

第一個活動日誌,首個活動日誌之後的日誌(也就是編號比首個活動日誌大的日誌)都是活動日誌,可以通過資料庫的snapshot檢視first active log,current active log,以及 last active log.

$ db2 get snapshot for db on sample | grep -i "File number"
File number of first active log      = 0
File number of last active log       = 2
File number of current active log     = 0
File number of log being archived     = Not applicable

日誌滿原因

DB2總的可用活動日誌的最大空間是有限制的,當達到限制之後,就會發生日誌滿的問題,限制為(LOGPRIMARY + LOGSECOND) * LOGFILSIZ * 4KB

日誌滿的原因無非兩種:

1.) 一個小事務hold住了首個活動日誌,一直沒有提交,導致首個活動日誌一直是活動狀態,不被釋放。這個跟堵車類似,一輛車因發動機故障(事務沒有提交)堵住路口(佔用首個活動日誌),即使後面的車都沒有問題(後續事務正常提交),也無法通過路口,且會越積越多,最終導致整個路都堵滿車(日誌滿)。

2.) 有個事務非常大,迅速用盡了所有的日誌。

日誌滿的表現:

首先應用會報出SQL0964C錯誤:

$ db2 "insert into test select * from test"
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0964C The transaction log for the database is full. SQLSTATE=57011

其次,db2diag.log中會有以下報錯

2017-03-09-17.24.50.315000+480 E3234873F644     LEVEL: Error
PID   : 8532         TID : 13028     PROC : db2syscs.exe
INSTANCE: DB2INST1       NODE : 000      DB  : SAMPLE
APPHDL : 0-453        APPID: *LOCAL.DB2INST1.170309092321
AUTHID : MIAOQINGSONG     HOSTNAME: ADMINIB-PR7US3I
EDUID  : 13028        EDUNAME: db2agent (SAMPLE)
FUNCTION: DB2 UDB,data protection services,sqlpgResSpace,probe:2860
MESSAGE : ADM1823E The active log is full and is held by application handle
     "0-441". Terminate this application by COMMIT,ROLLBACK or FORCE
     APPLICATION.

日誌滿的臨時處理:

1. 可以通過增加LOGSECOND來臨時增加可用的日誌大小(修改時需要加上immediate選項使之立即生效);增加LOGPRIMARY並沒有用,因為需要重啟資料庫才能生效。

2. force掉hold住首個活動日誌的的應用,在force之前,可以抓取snapshot,看一下這個應用的狀態:

$ db2 get snapshot for database on sample | grep -i oldest
Appl id holding the oldest transaction   = 441

$ db2 get snapshot for application agentid 441

      Application Snapshot

Application handle             = 441
Application status             = UOW Waiting         <<--應用狀態為UOW Waiting
Status change time             = 2017-03-09 17:23:15.068895
Application code page           = 1386
Application country/region code      = 86
DUOW correlation token           = *LOCAL.DB2INST1.170309092244
Application name              = db2bp.exe
Application ID               = *LOCAL.DB2INST1.170309092244

..

Connection request start timestamp     = 2017-03-09 17:22:44.963163 <<--應用連庫時間
Connect request completion timestamp    = 2017-03-09 17:22:45.961157
Application idle time           = 4 minutes 7 seconds

..

UOW log space used (Bytes)         = 664
Previous UOW completion timestamp     = 2017-03-09 17:22:45.961157
Elapsed time of last completed uow (sec.ms)= 0.000000
UOW start timestamp            = 2017-03-09 17:23:02.770477 <<--當前事務開始時間
UOW stop timestamp             =              <<--當前事務結束時間為空,說明還沒有commit
UOW completion status           =

..

Statement type               = Dynamic SQL Statement
Statement                 = Close
Section number               = 201
Application creator            = NULLID
Package name                = SQLC2K26
Consistency Token             =
Package Version ID             =
Cursor name                = SQLCUR201
Statement member number          = 0
Statement start timestamp         = 2017-03-09 17:23:15.067789
Statement stop timestamp          = 2017-03-09 17:23:15.068893 
Elapsed time of last completed stmt(sec.ms)= 0.000024
Total Statement user CPU time       = 0.000000
Total Statement system CPU time      = 0.000000
..
Dynamic SQL statement text:   
select * from t1

<<--一個事務中可能有多條SQL,這個只表示當前正在執行或者最後執行過的SQL,並不能表示就是這條SQL導致了日誌滿,這裡抓取到的是一條SELECT語句,SELECT語句不佔用日誌。

$ db2 "force application (441)"
DB20000I The FORCE APPLICATION command completed successfully.
DB21024I This command is asynchronous and may not be effective immediately.

日誌滿的避免:

1.)根據抓取到的應用的snapshot,找應用開發人員檢視為何不肯提交,這才是避免問題再次出現的根本辦法。
2.)從DB2管理層面,可以設定資料庫配置引數max_log和num_log_span
3.)可以寫指令碼,以固定的間隔抓取database snapshot中的Appl id holding the oldest transaction,如果長時間不發生變化(比如2天),就Force掉。

補充說明:

檢視每個應用使用的日誌大小:

$ db2 "select application_handle,UOW_LOG_SPACE_USED,UOW_START_TIME FROM TABLE(MON_GET_UNIT_OF_WORK(NULL,-1)) order by UOW_LOG_SPACE_USED" 

也可以通過db2pd -db <dbname> -transactions 檢視每個正在使用的日誌的情況

重點關注的引數有:

ApplHandl
The application handle of the transaction.
SpaceReserved
The amount of log space that is reserved for the transaction.
LogSpace
The total log space that is required for the transaction,including the used space and the reserved space for compensation log records.

通過對DB2活動日誌滿原因的分析我們就可以找到解決此問題的方法同時避免此問題的再次出現