クラッシュ・リカバリーまたは HADR テークオーバーのバックワード・フェーズ中のデータベースのアクセス可能性

すべてのトランザクション (または作業単位) がコミットされる前に、または、コミットされたトランザクションに関連する変更がディスクに完全に書き込まれる前に、データベースで予期しない障害が発生した場合、データベースは不整合な状態になります。 データベースの再始動を実行すると、それらのトランザクションが、クラッシュ・リカバリーというプロセスで修正されます。 クラッシュ・リカバリーでは、まず、それらのトランザクションに関連する変更がトランザクション・ログから適用されます (これをクラッシュ・リカバリーの FORWARD フェーズまたは REDO フェーズと呼ぶことがあります)。 次に、データベースの障害発生時にまだコミットされていなかったトランザクションがロールバックされます (これをクラッシュ・リカバリーの BACKWARD フェーズまたは UNDO フェーズと呼ぶことがあります)。 TAKEOVER HADR 操作でも BACKWARD フェーズを実行して、操作時にまだコミットされていなかった変更をロールバックできます。

v11.1.2.2 より前のリリースでは、クラッシュ・リカバリーまたは HADR テークオーバーが完全に終わるまで、データベースにはアクセスできません。 これは理想的ではありません。非常に大きなトランザクションがある場合、BACKWARD フェーズに時間がかかり、完了するまでデータベース全体がアクセス不能になるからです。

v11.1.2.2 以降では、クラッシュ・リカバリーの BACKWARD フェーズ中の接続を許可するようにデータベースを構成できます。 この動作は、次のデータベース・レジストリー変数を使用して有効にできます。
db2set DB2_ONLINERECOVERY=YES
このレジストリー変数はクラッシュ・リカバリーの開始時に読み込まれるため、クラッシュ・リカバリーがアクティブに実行されている間に有効または無効にすることはできません。
BACKWARD フェーズ中のどの時点でデータベースが接続可能になるかは、ワークロードの特性によって異なります。 次のワークロード操作を含むコミットされていないトランザクションは、データベース・アクセスが許可されず、BACKWARD フェーズ中に取り消されます。
  • SQL データ定義言語 (DDL) ステートメント。
  • データベース・カタログを変更する操作。
  • カラム・オーガナイズ表に対する操作。
  • まだサポートされていないその他のログ・レコードを生成するワークロード。
これを、BACKWARD フェーズの同期部分と呼びます。 そのため、これらのサポートされない操作の最初の時点までは、BACKWARD フェーズ中のデータベースにはアクセスできません。
注: コミットされていない最も古いトランザクションにこれらのサポートされていない操作が含まれている場合、BACKWARD フェーズの大部分は、使用可能なデータベース・アクセスなしで同期的に実行される可能性があります。

BACKWARD フェーズの同期部分が完了した後に、データベース・アクセスは許可されます。 これを、BACKWARD フェーズの非同期部分と呼びます。

BACKWARD フェーズの非同期部分の間は、データベース・アクセスは次のように許可されます。
  1. 未コミットのトランザクションに関係しない表、索引、またはオブジェクトは、非同期 BACKWARD フェーズ中は完全にアクセス可能です。
  2. コミットされていないトランザクションに関連付けられている表、索引、またはオブジェクトは、 DB2_ONLINERECOVERY_WITH_UR_ACCESS=YESの場合は排他 (X) ロックによって保護され、 DB2_ONLINERECOVERY_WITH_UR_ACCESS=NOの場合は超排他 (Z) ロックによって保護されます。 BACKWARD フェーズで未コミットのトランザクションが補正されるため、その表/オブジェクトを参照している未コミットのトランザクションが他に存在しなければ、このロックは解放されます。 したがって、これらのロックが解放される前は、これらの表/オブジェクトは、 DB2_ONLINERECOVERY_WITH_UR_ACCESS=YES,の場合は UR 分離レベルを使用する照会にしかアクセスできず、 DB2_ONLINERECOVERY_WITH_UR_ACCESS=NO.の場合は完全にアクセスできません。

    またこれらの表に LONG フィールドまたは LOB フィールドが含まれている場合、または、これらの表が MDC または ITC によって編成されている場合、必ず超排他 (Z) ロックによって保護されます。 非同期 BACKWARD フェーズ中に、これらのオブジェクトがアクセス可能になることはありません。

    注: これらのトランザクションを元に戻すには、本質的に超排他 (Z) ロックが必要になる場合があります。 例えば、LOAD などのユーティリティー操作を元に戻すと、 DB2_ONLINERECOVERY_WITH_UR_ACCESS=YES. の場合は常に非同期部分で獲得された排他的 (X) ロックが置き換えられます。

RESTART DATABASE コマンドまたは TAKEOVER HADR コマンドは、データベースが接続可能になる非同期 BACKWARD フェーズが開始すると戻ります。

クラッシュ・リカバリー操作の実行中に、 DEACTIVATE DB 操作が SQL1495W 警告/エラーを返します。 db2stop 操作は、SQL1025N エラーを返します。 FORCE APPLICATION 0 を使用してクラッシュ・リカバリー・アプリケーション・エージェントを強制しようとすると、SQL0104N エラーが返ります。 db2stop force 操作は許可され、クラッシュ・リカバリーが中断されます。 TAKEOVER HADR 操作も、クラッシュ・リカバリーのすべてのフェーズで許可されます。

INDEXREC構成パラメーターがデータベース再始動時に索引を再作成するように構成されている場合、索引は非同期バックワード・フェーズの完了後に再作成されます。

注: pureScale インスタンスの場合、メンバー・クラッシュ・リカバリーのバックワード・フェーズは、データベースが他のメンバー上で接続可能なままであるため、そのメンバーのデータベース・アクセス可能性なしで同期的に引き続き実行されます。 同様に、グループ・クラッシュ・リカバリーの場合も、データベースにアクセスできない状態で BACKWARD フェーズが引き続き同期実行されます。

クラッシュ・リカバリーの進行状況のモニター:

クラッシュ・リカバリーの進行状況は、「db2pd -recovery」オプション、 LIST UTILITIES SHOW DETAIL CLP コマンド、SNAPUTIL管理ビュー、またはSNAP_GET_UTIL表関数のいずれかを使用して、どのフェーズでもモニターできます。 非同期バックワード・フェーズでは、 MON_GET_UTILITY表関数および CHANGE HISTORY イベント・モニターも使用できます。

$ db2pd -db mydb1 -recovery
Recovery:
Recovery Status		7400010F40000000
Current Log		S0000031.LOG
Current LSN		000000000006114D
Current LRI		000000000000000100000000000026E8000000000006114D
Current LSO		80969655
Job Type		CRASH RECOVERY
Job ID			1
Job Start Time		(1479058883) Sun Nov 13 12:41:23 2016
Job Description		Crash Recovery
Invoker Type		User
Total Phases		2
Current Phase		2
Progress:
Address		PhaseNum	Description		StartTime			CompletedWork				TotalWork
0x078... 	1		Forward			Sun Nov 13 12:41:231290045	4 bytes					12900454 bytes
0x078... 	2		Backward		Sun Nov 13 12:49:27		0 bytes					12900454 bytes

クラッシュ・リカバリーの FORWARD フェーズ (トランザクションがトランザクション・ログから適用されるフェーズ) が最初のフェーズとして表示され、その進行状況を「合計作業 (CompletedWork)」と「完了作業 (TotalWork)」の値の経時変化としてモニターできます。

最初のフェーズが完了すると、クラッシュ・リカバリーの BACKWARD フェーズ (未コミットのトランザクションがロールバックまたは取り消されるフェーズ) が表示されます。 その進行状況も、「合計作業」と「完了作業」の値の経時変化を観察してモニターできます。

例えば、 CompletedWork値が10mins離れていることが観測され、この期間中のCompletedWork値の差が 123,456 bytesである場合、残りの作業を完了するための時間を簡単に推定できます。
ObservationTime_inMins =	10mins
WorkDone_inBytes =		123,456bytes    
RemainingWork_inBytes = 	TotalWork – CompletedWork;   
TimeToCompletion_inMins = 	(RemaingWork_inBytes / WorkDone_inBytes) * ObservationTime_inMins.
BACKWARD フェーズの同期部分の進行中に BACKWARD フェーズの非同期部分が開始されるタイミングを推定することはできません。 同期部分が完了すると、ADM1505Iメッセージが管理通知ログに出力され (「ADM1505I Crash recovery has completed synchronous processing」)、以下のメッセージが db2diag.log: に表示されます。
2016-11-12-50.03.33.674725-300		I269681A541 			LEVEL: Info
PID : 63373472 				TID : 2058 			KTID : 131596723
PROC : db2sysc 							
INSTANCE: db2inst1 			NODE : 000 			DB : MYDB1
APPHDL : 0-7 				APPID: *LOCAL.dsciaraf.161114020311
AUTHID : DB2INST1 			HOSTNAME: hotelaix2
EDUID : 2058 				EDUNAME: db2agent (X)
FUNCTION: Db2 UDB, recovery manager, sqlpresr, probe:3170
DATA #1 : <preformatted>
Crash recovery synchronous phase completed. Next LSN is 000000000006113C.

クラッシュ・リカバリーのバックワード・フェーズで非同期部分が実行された場合、MON_GET_UTILITY表関数では、接続のためにデータベースが開いた後、「ONLINERECOVERY」の項目でUTILITY_TYPE値が表示されます。

以下に例を示します。
$ db2 “ SELECT COORD_MEMBER, APPLICATION_HANDLE AS APPHDL, SUBSTR(APPLICATION_NAME, 1, 30) AS APPNAME, 
SUBSTR(SESSION_AUTH_ID, 1, 10) AS USER, UTILITY_TYPE, UTILITY_INVOKER_TYPE, SUBSTR(UTILITY_DETAIL, 1, 50) AS CMD FROM TABLE(MON_GET_UTILITY(-2)) AS T ”
COORD_MEMBER APPHDL    APPNAME    		USER       UTILITY_TYPE     UTILITY_INVOKER_TYPE 			CMD                                           
------------------------------------------------------------------------------------------------------------------------------------
0                   	21 db2undo_trans     	-		ONLINERECOVERY   	AUTO   				RESTART DATABASE MYDB1
1 record(s) selected.

CHANGE HISTORYイベント・モニターは、 ONLINERECOVERYというイベント制御タイプを使用して、クラッシュ・リカバリーのバックワード・フェーズの非同期部分の開始と終了を記録することもできます。

クラッシュ・リカバリーの BACKWARD フェーズ中のアプリケーションのモニター

クラッシュ・リカバリーの BACKWARD フェーズ中にデータベース・アクセスが許可された後、従来の方法を使用してアプリケーションのモニターを実行する必要があります。その際、以下の点を考慮してください。

クラッシュ・リカバリーの BACKWARD フェーズに含まれている未コミットのトランザクションのアプリケーション・ハンドル (AppHandl) はすべてゼロ (0) です。 またこれらのトランザクションのトランザクション状態は「ABORT」で、Tflag2 ビットは 0x00000001 に設定されます。

以下に例を示します。
$ db2pd -db MYDB1 -transactions
Transactions:
Address AppHandl ... TranHdl ... State 	Tflag 		Tflag2 ... 	LogSpace ...
0x... 	0 ... 		3 ... 	ABORT 	0x00000000 	0x00000001 ... 	780 ...
0x... 	0 ... 		4 ... 	ABORT 	0x00000000 	0x00000001 ... 	9465875 ...
0x... 	7 ... 		5 ... 	READ 	0x00000000 	0x00000000 ... 	0 ...
0x... 	8 ... 		6 ... 	READ 	0x00000000 	0x00000000 ... 	0 ...
未コミットのトランザクションに関係する表、索引、またはオブジェクトは、クラッシュ・リカバリーの BACKWARD フェーズ中に排他 (X) ロックまたは超排他 (Z) ロックによって保護されます。 つまり、クラッシュ・リカバリーの BACKWARD フェーズ中にこれらのオブジェクトにアクセスしようとしたアプリケーションはロック待機状態になります。
ロック - 待ち状態は、MON_GET_APPL_LOCKWAIT表関数または db2pd -wlock オプションを使用してモニターできます。 以下に例を示します。
$ db2 "select LOCK_OBJECT_TYPE as TYPE, LOCK_NAME, LOCK_MODE as MODE,
LOCK_MODE_REQUESTED as MODE_REQ, LOCK_STATUS as STATUS,
HLD_APPLICATION_HANDLE as HL
D_APPHANDL, REQ_APPLICATION_HANDLE as REQ_APPHANDL
from TABLE (MON_GET_APPL_LOCKWAIT(NULL, -2))"
TYPE 	LOCK_NAME 			MODE 		MODE_REQ 	STATUS 		HLD_APPHANDL 	REQ_APPHANDL
----------------------------------------------------------------------------------------------------------
TABLE 	02000500000000000000000054 	X	 	IS		 W		 0		 7
1 record(s) selected.

この例の場合、アプリケーション・ハンドル 7 が表に対するインテント共有 (IS) モード・ロックを要求していますが、その表は既にアプリケーション・ハンドル 0 (クラッシュ・リカバリーに含まれている未コミットのトランザクション) が排他 (X) モードでロックしています。

追加のロック詳細は、 MON_FORMAT_LOCK_NAME表関数を使用して確認できます。 以下に例を示します。

$ db2 "SELECT SUBSTR(TABNAME,1,20) AS TABNAME, SUBSTR(VALUE,1,50) AS
VALUE FROM TABLE(MON_FORMAT_LOCK_NAME('02000500000000000000000054')) as LOCK"
NAME 					VALUE
------------------------------------------------------
LOCK_OBJECT_TYPE 			TABLE
TBSP_NAME 				TSPA
TABSCHEMA 				MYSCHEM
A1TABNAME 				MYTABLE3
4 record(s) selected.

この例では、ロック待ち状態は、表スペース TSPA の表MYSCHEMA1.MYTABLE3に対する表ロックに関連しています。

ロック - 待ち状態のアプリケーションに関する詳細は、 WLM_GET_WORKLOAD_OCCURRENCE_ACTIVITIES表関数を使用して取得できます。

db2 "SELECT APPLICATION_HANDLE as APPHNDL,
LOCK_WAIT_TIME, SUBSTR(STMT_TEXT,1,45) AS STMT_TEXT
FROM TABLE(WLM_GET_WORKLOAD_OCCURRENCE_ACTIVITIES(NULL,-1)) AS T"
APPHNDL			LOCAL_START_TIME			LOCK_WAIT_TIME 		STMT_TEXT
-----------------------------------------------------------------------------------------
10			2016-11-13-12.55.35.821373 		0 			SELECT APPHNDL,LOCK_WAIT_TIME
7 			2016-11-13-12.53.33.777571 		27 			select count(*) from t2
2 record(s) selected.