前回Db2のネイティブ暗号化の構築覚書に続いて、暗号化したDBをHADR(High Availability Disaster Recovery)構成にするところまでの覚書。
HADRはいわゆるRDBMSのレプリケーション機能で、OracleならData Guard、MySQLならそのまんまレプリケーション(名前ないのかな?)、HiRDBならData Replicatorに相当する機能。
完成後はこのような構成になる。PRIMARYのDB01はDb2ネイティブ暗号化による暗号化済み。
項目 | PRIMARY | STANDBY |
---|---|---|
ホスト名 | db1 | db2 |
インスタンス名 | dbinst | dbinst |
DB名 | DB01 | DB01 |
HADRポート1 | db2_hadr(55555/tcp) | db2_hadr(55555/tcp) |
PRIMARY、STANDBYのホスト名はそれぞれ"db1"と"db2"で、それぞれインスタンス名(インスタンスユーザ名)は"dbinst"。
HADR構成の要件としては、インスタンス名は必ずしも同じでなくてよいものの、DB名は同じでなければならない。
物理パスは同じでなくても動作するが、初期構築時にPRIMARYからSTANDBYへDBをリストアするので、同じ方が簡単(物理パスが異なるとリストアが面倒になる)。つまり一旦、同じ構成のDBがSTANDBY側にもできて、そこからSTANDBY側固有の設定をすることになる。
また、ログはアーカイブモードが必須(循環ログはNG)。
同様に、プライマリで暗号化している場合は、同じ暗号化キー(DBの暗号化鍵を暗号化するマスターキーを含むキーストア)をスタンバイにも登録する必要がある。
前提環境
項目 | 値 |
---|---|
OS | RHEL7.3 |
Db2 | v11.1.3.3 |
DB PATH | /db/db01/database |
Storage | /db/db01/tbsp1,/db/db01/tbsp2 |
Log | /db/db01/log1 |
Mirror Log | /db/db01/log2 |
Log ArchMeth1 | DISK:/db/db01/logarch |
※VMware Fusion上の仮想マシンとして構築
DB作成
DBディレクトリ作成(PRIMARY/STANDBYそれぞれ)
mkdir /db/db01
cd /db/db01; pwd
mkdir database tbsp1 tbsp2 log1 log2 logarch
DB作成(PRIMARYのみ)
db2 "CREATE DB DB01
AUTOMATIC STORAGE YES
ON /db/db01/tbsp1,/db/db01/tbsp2
DBPATH ON /db/db01/database
USING CODESET UTF-8 TERRITORY JP
COLLATE USING IDENTITY
PAGESIZE 4 K
ENCRYPT CIPHER AES KEY LENGTH 256 MASTER KEY LABEL MasterKey"
DB設定更新(PRIMARYのみ)
db2 "UPDATE DB CFG FOR DB01 USING NEWLOGPATH /db/db01/log1"
db2 "UPDATE DB CFG FOR DB01 USING MIRRORLOGPATH /db/db01/log2"
db2 "UPDATE DB CFG FOR DB01 USING LOGARCHMETH1 DISK:/db/db01/logarch"
db2 "UPDATE DB CFG FOR DB01 USING LOGINDEXBUILD ON"
HADR構成
PRIMARYでバックアップ取得
NFSでPRIMARY、STANDBYからアクセス可能な領域に出力。NFSが使えなければSCPなりHULFTなりでSTANDBYへ転送。
db2 "BACKUP DB DB01 TO /nfs/db01"
STANDBYにリストア
db2 "RESTORE DB DB01 FROM /nfs/db01 ENCRYPT"
暗号化しているのでENCRYPT
オプション必須。
ただし、先にSTANDBYでもCREATE DATABASEをENCRYPTつきで実行済みならENCRYPT不要(つけるとエラー)。BACKUP DBのバックアップデータはデフォルト暗号化されない点には一応注意。
PRIMARY・STANDBYでHADRポート番号追加
echo "db2_hadr 55555/tcp" >>/etc/services
ローカルHADR設定(PRIMARY)
db2 "UPDATE DB CFG FOR DB01 USING
HADR_LOCAL_HOST db1
HADR_LOCAL_SVC db2_hadr
HADR_SYNCMODE ASYNC
"
ローカルHADR設定(STANDBY)
db2 "UPDATE DB CFG FOR DB01 USING
HADR_LOCAL_HOST db2
HADR_LOCAL_SVC db2_hadr
HADR_SYNCMODE ASYNC
"
リモートHADR設定(PRIMARY)
db2 "UPDATE DB CFG FOR DB01 USING
HADR_REMOTE_HOST db2
HADR_REMOTE_SVC db2_hadr
HADR_REMOTE_INST dbinst
"
リモートHADR設定(STANDBY)
db2 "UPDATE DB CFG FOR DB01 USING
HADR_REMOTE_HOST db1
HADR_REMOTE_SVC db2_hadr
HADR_REMOTE_INST dbinst
"
スタンバイでHADR開始
db2 "START HADR ON DB DB01 AS STANDBY"
db2pd -hadr -db DB01
プライマリでHADR開始
db2 "START HADR ON DB DB01 AS PRIMARY"
db2pd -hadr -db DB01
状態確認
db2pd -hadr -db DB01
HADR_ROLE = STANDBY
HADR_STATE = PEER
HADR_CONNECT_STATUS = CONNECTED
以下を確認する。
- HADR_ROLEがそれぞれPRIMARY、STANDBYになっていること
- HADR_STATEがPEERになっていること
- HADR_CONNECT_STATUSがCONNECTEDになっていること
同期確認
PRIMARYでテーブル作成
db2 "CONNECT TO DB01"
db2 "CREATE TABLE Hogetbl(hoge INTEGER PRIMARY KEY NOT NULL, geho VARCHAR(16))"
db2 "INSERT INTO Hogetbl VALUES (1,'hogehoge')"
STANDBYで確認
STANDBYをPRIMARYに昇格(PRIMARYはSTANDBYへ降格)
db2 "TAKEOVER HADR ON DB DB01"
db2pd -hadr -db DB01
通常、STANDBYであるうちはCONNECTできないが、レジストリ変数(DB2_HADR_ROS)を設定することでアクセス可能。
SELECTしてみる
db2 "CONNECT TO DB01"
db2 "SELECT * FROM Hogetbl"
無事に旧PRIMARYのデータが引継がれた。
元に戻す
db2 "TAKEOVER HADR ON DB DB01"
db2pd -hadr -db DB01
起動と停止
停止
停止するときは、PRIMARYからSTANDBYの順。
db2 "DEACTIVATE DB DB01"
db2stop
db2 "DEACTIVATE DB DB01"
db2stop
起動
起動は逆にSTANDBYからPRIMARYの順。
db2start
db2 "ACTIVATE DB DB01"
db2start
db2 "ACTIVATE DB DB01"
HADR構成の破棄(PRIMARY、STANDBYそれぞれ実施)
db2 "DEACTIVATE DB DB01"
db2 "STOP HADR ON DB DB01"
これをやるとHADR環境は作り直しが必要になる可能性がある(トランザクションがPRIMARY側で大量に発生して、PRIMARY/STANDBY間の整合性が取れなくなるなど)。
なにも更新がなければ再度START HADR ON DB DB01 AS PRIMARY/STANDBY
で再開始可能。
いろいろ実験
バックアップとリストア
バックアップはPRIMARY側で実行する(STANDBYでは取得不可)。オフライン・オンラインいずれも可能。
リストアして障害発生直前までロールフォワード
db2 "DEACTIVATE DB DB01"
db2 "BACKUP DB DB01 TO /db/db01/backup"
ここでDBを更新してみる。
db2 "ACTIVATE DB DB01"
db2 "CONNECT TO DB01"
db2 "INSERT INTO Hogetbl VALUES(2, 'gehogeho')"
db2 "TERMINATE"
ここで障害が発生したと想定し、リストア&ロールフォワードしてから、HADRのPRIMARYとして再始動する。
db2 "DEACTIVATE DB DB01"
db2 "RESTORE DB DB01 FROM /db/db01/backup TAKEN AT 20181028114425"
db2 "ROLLFORWARD DB DB01 TO END OF LOGS AND STOP"
db2 "ACTIVATE DB DB01"
db2 "CONNECT TO DB01"
db2 "SELECT * FROM Hogetbl"
db2 "START HADR ON DB DB01 AS PRIMARY"
db2 "db2pd -hadr -db DB01"
しばらくHADR_STATE = REMOTE_CATCHUP_PENDINGになっていたがPEERに戻った。
壊してみるその1(中途半端にリストア)
ログから最後までロールフォワードせず、バックアップ時点までしかもどさなかった(戻らなかった)場合。
まずは先ほどと同様にバックアップ取得。
db2 "DEACTIVATE DB DB01"
db2 "BACKUP DB DB01 TO /db/db01/backup"
DBを更新する。
db2 "ACTIVATE DB DB01"
db2 "CONNECT TO DB01"
db2 "INSERT INTO Hogetbl VALUES(3, 'hogehogehoge')"
db2 "TERMINATE"
障害発生!リストアする。
db2 "DEACTIVATE DB DB01"
db2 "RESTORE DB DB01 FROM /db/db01/backup TAKEN AT 20181028115805"
db2 "ROLLFORWARD DB DB01 TO END OF BACKUP AND STOP"
db2 "ACTIVATE DB DB01"
db2 "CONNECT TO DB01"
db2 "SELECT * FROM Hogetbl"
当然、3個目のレコードはない。ここでHADRを再開しようとすると、、、
db2 "START HADR ON DB DB01"
SQL1768N Unable to start HADR. Reason code = "7".
db2 "? SQL1768N"
で調べると、Reason code 7はSTANDBYとの通信タイムアウト。DB構成パラメタ上もSTANDARDになっている。
db2 "GET DB CFG FOR DB01" | grep -i hadr
HADR database role = STANDARD
STANDBY側を調査する。
db2pd -hadr -db DB01
Database DB01 not activated on database member 0 or this database name cannot be found in the local database directory.
HADRが落ちているのでdb2diagで調べると。
db2diag -l Severe
MESSAGE : ZRC=0x8610000D=-2045771763=SQLP_BADLOG "Log File cannot be used"
DIA8414C Logging can not continue due to an error.
SQL1034C The database was damaged, so all applications processing
the database were stopped.
あたりまえだが、PRIMARYとSTANDBYとでログの状態が変わったので、これ以上HADRはできないということで、STANDBY側のHADRが異常終了した。
これを修復するには再度PRIMARYでバックアップを取得し、これをSTANDBYへリストアするしかない(HADR初期構成)。
Directoryサーバのレプリケーションではオンライン初期化ができるのに、、、
復旧
db2 "BACKUP DB DB01 TO /nfs/db01"
db2 "STOP HADR ON DB DB01"
db2 "DROP DB DB01" # すでに存在するDBをドロップ
db2 "RESTORE DB DB01 FROM /nfs/db01 ENCRYPT" # 最新バックアップからリストア
# HADR関連パラメタ変更
db2 "UPDATE DB CFG FOR DB01 USING
HADR_LOCAL_HOST db2
HADR_LOCAL_SVC db2_hadr
HADR_REMOTE_HOST db1
HADR_REMOTE_SVC db2_hadr
"
db2 "START HADR ON DB DB01 AS STANDBY"
db2 "START HADR ON DB DB01 AS PRIMARY"
db2pd -hadr -db DB01
といわけで超面倒。ログの不整合が起きると大変なので気をつけましょう。
壊してみるその2(STANDBYが計画停止)
STANDBYが計画停止している間にPRIMARYのログが全部切り替わってしまった状況を想定(PRIMARYのアーカイブログを使ってSTANDBYをPEERまで持っていってくれるかどうかの検証)。
db2 "DEACTIVATE DB DB01"
db2stop
# 現在のアクティブログを確認
db2 "GET DB CFG FOR DB01" | grep "First active"
# ついでにログ設定も確認
db2 "GET DB CFG FOR DB01" | grep -e "LOGPRIMARY" -e "LOGSECOND"
# 更新とログアーカイブの繰り返し
for i in $(seq 5 50); do
db2 "CONNECT TO DB01"
db2 "INSERT INTO Hogetbl VALUES(${i}, 'hogehoge')"
db2 "TERMINATE"
db2 "ARCHIVE LOG FOR DB DB01"
done
# ログとHADR状況確認
find /db/db01/log1/NODE0000 -name "*.LOG"
db2pd -hadr -db DB01 | grep _LOG_FILE
PRIMARY_LOG_FILE,PAGE,POS = S0000160.LOG, 0, 741864654
STANDBY_LOG_FILE,PAGE,POS = S0000110.LOG, 2, 533182206
STANDBY_REPLAY_LOG_FILE,PAGE,POS = S0000110.LOG, 2, 533182206
この時点でのログの状態は以下の通りだった。
項目 | 状況 |
---|---|
PRIMARYのFirst active log | S0000160.LOG |
PRIMARYのアクティブログ保持状況 | S0000159.LOG〜S0000171.LOG(LOGPRIMARY=13) |
STANDBYのFirst active log相当 | S0000110.LOG |
つまり、STANDBY側はPRIMARYのアクティブログからは追いつけない状況になっている。
db2start
db2 "ACTIVATE DB DB01"
db2pd -hadr -db DB01
"HADR_STATE"は"REMOTE_CATCHUP"からしばらくして"PEER"になった。
このことから、PRIMARYのアーカイブログも使って、STANDBY側のDBに追いつきをかけてくれると想定される。
-
マニュアルには「個別の」ポートが必要と記載があるが、同じポート番号が不可とは明記されていない。 ↩