🔀

Db2 HADRの「テイクオーバーが失敗する・終わらない」を切り分ける ― SQL1770Nの理由コードとログギャップ

に公開

HADRのテイクオーバーを試したら SQL1770N で失敗する。あるいは応答がなかなか返ってこない——。「HADRの構成が悪いのか」「切り替え運用は信用できない」と考えてしまいがちですが、テイクオーバーの失敗は理由コードとHADRの状態を見れば機械的に切り分けられます

この記事では、SQL1770N の代表的な理由コード、計画切替(通常テイクオーバー)と緊急切替(BY FORCE)の使い分け、そして「そもそもテイクオーバーできる状態か」を事前に判断するための peer状態・ログギャップ の見方を、実機での再現ログとともに整理します。

検証環境は2ノードHADR(db2node1=プライマリ / db2node2=スタンバイ、Db2 12.1.4 / NEARSYNC)です。

まず結論:失敗したら「理由コード」と「peer状態」を見る

テイクオーバーには2種類あります。

  • 計画切替(通常)TAKEOVER HADR ON DATABASE <db>スタンバイ側で実行。peer状態が前提で、ロールを入れ替える。
  • 緊急切替TAKEOVER ... BY FORCE。プライマリ障害時に、peerでなくてもスタンバイを昇格できる。ただしデータロストのリスクがある。

失敗したときは、メッセージの理由コードを見ます。

SQL1770N  Takeover HADR cannot complete. Reason code = "N".

実機でよく出るのは次の2つです。

理由コード 状況 対処
4 プライマリ側で通常テイクオーバーを実行した(撃つノードの間違い) スタンバイ側で実行する
1 スタンバイがpeer状態でない(プライマリ不達・カタチアップ中など) 状態を確認。プライマリ障害なら BY FORCE

以下、この2つと緊急切替を実機で再現します。

テイクオーバー前に必ず見る:peer状態とログギャップ

計画切替は「スタンバイがプライマリに追いついていて(peer)、接続している」ことが前提です。切り替える前に必ず確認します。

# ロールと状態を一発で確認
db2pd -db SAMPLE -hadr
-- peer状態・接続・ログギャップをまとめて確認
SELECT HADR_STATE, HADR_CONNECT_STATUS, HADR_LOG_GAP,
       LOG_HADR_WAIT_TIME, HADR_SYNCMODE
FROM TABLE(MON_GET_HADR(NULL)) AS T;

健全なら次のように見えます。

HADR_STATE   HADR_CONNECT_STATUS  HADR_LOG_GAP  LOG_HADR_WAIT_TIME  HADR_SYNCMODE
-----------  -------------------  ------------  ------------------  -------------
PEER         CONNECTED                       0                   6  NEARSYNC
  • HADR_STATE = PEER かつ HADR_CONNECT_STATUS = CONNECTED … 計画切替が可能な状態。
  • HADR_LOG_GAP(バイト)… プライマリとスタンバイのログ差。大きいほどスタンバイが遅れている。切り替え直後の性能や、BY FORCE 時のデータロスト量に直結する。
  • LOG_HADR_WAIT_TIME(ミリ秒)が増え続けるなら、CPUやメモリより先にネットワーク帯域を疑う。

HADR_STATEPEER 以外(REMOTE_CATCHUP など)のときに計画切替を撃つと、後述の理由コード1で弾かれます。

失敗例①:撃つノードを間違える(プライマリで通常テイクオーバー)

通常テイクオーバーはスタンバイ側で実行します。プライマリ側で撃つと失敗します。

# db2node1(プライマリ)で誤って実行
db2 "TAKEOVER HADR ON DATABASE SAMPLE"
SQL1770N  Takeover HADR cannot complete. Reason code = "4".

理由コード4は「このデータベースは既にプライマリ」という意味です。撃った後もロールは変わりません(HADR_ROLE = PRIMARY / HADR_STATE = PEER のまま)。害はないが1歩も進まないので、慌てているときほど「どのノードで実行しているか」を先に確認します。

失敗例②:peer状態でないのに通常テイクオーバー(プライマリ障害)

プライマリが落ちた状況を実機で作って再現します。まずプライマリを停止します。

# db2node1(プライマリ)を停止して障害を模擬
db2stop force

このときスタンバイ(db2node2)から状態を見ると、peerが崩れています。

db2pd -db SAMPLE -hadr
HADR_ROLE           = STANDBY
HADR_STATE          = REMOTE_CATCHUP_PENDING
HADR_CONNECT_STATUS = DISCONNECTED

この状態で通常テイクオーバーを撃つと、理由コード1で失敗します。

# db2node2(スタンバイ)で通常テイクオーバーを試みる
db2 "TAKEOVER HADR ON DATABASE SAMPLE"
SQL1770N  Takeover HADR cannot complete. Reason code = "1".

理由コード1は「スタンバイがpeer状態でないため、計画切替はできない」という意味です。プライマリが生きていれば「まず追いつかせる(peerに戻す)」のが筋ですが、プライマリが本当に落ちているなら、次の緊急切替に進みます

緊急時:BY FORCE で昇格する(データロストに注意)

プライマリが復旧しない障害では、BY FORCE でスタンバイを強制昇格します。

# db2node2(スタンバイ)で緊急テイクオーバー
db2 "TAKEOVER HADR ON DATABASE SAMPLE BY FORCE"
DB20000I  The TAKEOVER HADR ON DATABASE command completed successfully.

昇格後の状態です。旧プライマリが不在なので DISCONNECTED ですが、新プライマリとして接続を受け付けられるようになります。

HADR_ROLE           = PRIMARY
HADR_STATE          = DISCONNECTED
HADR_CONNECT_STATUS = DISCONNECTED
→ 新プライマリ(db2node2)へ接続 OK。業務を再開できる。

BY FORCE の後始末:旧プライマリをスタンバイに戻す

BY FORCE の後は、旧プライマリを新プライマリのスタンバイとして再統合します。旧プライマリを起動し、スタンバイとして起動し直します。

# 旧プライマリ db2node1 で
db2start
db2 "START HADR ON DATABASE SAMPLE AS STANDBY"
SQL1063N  DB2START processing was successful.
DB20000I  The START HADR ON DATABASE command completed successfully.
→ db2node1: HADR_ROLE=STANDBY / HADR_STATE=PEER / CONNECTED
→ db2node2: HADR_ROLE=PRIMARY  / HADR_STATE=PEER / CONNECTED

今回は切り替え時のログギャップが0だったため、スタンバイとしてそのまま PEER に復帰できました。

計画切替は健全なpeerで(正常系の確認)

比較のために、健全なpeer状態での計画切替も載せます。スタンバイ側で実行すると、ロールが入れ替わります。

# 昇格させたい側(現スタンバイ)で実行
db2 "TAKEOVER HADR ON DATABASE SAMPLE"
DB20000I  The TAKEOVER HADR ON DATABASE command completed successfully.
→ 実行した側: HADR_ROLE=PRIMARY / HADR_STATE=PEER
→ 相手側    : HADR_ROLE=STANDBY / HADR_STATE=PEER

計画メンテナンスでの切り替えはこれで済みます。失敗するのは「peerでない」か「撃つノードが違う」かのどちらかです。

テイクオーバーが失敗したときのチェックリスト

  1. メッセージの理由コードを見る(SQL1770N ... Reason code = "N"
  2. 4 なら撃つノードが違う。スタンバイ側で実行し直す
  3. 1 ならpeer状態でないdb2pd -hadrHADR_STATEHADR_CONNECT_STATUS を確認
  4. プライマリが生きているなら、まず追いつかせて PEER に戻す(ネットワーク/ログギャップを確認)
  5. プライマリが本当に落ちているなら、HADR_LOG_GAP を確認のうえ BY FORCE
  6. BY FORCE 後は旧プライマリをスタンバイとして再統合(分岐していたら作り直す)

補足:テイクオーバー後、アプリ側で SQL30108N が出るのは正常

テイクオーバーが成功すると、ACR(自動クライアントリルート)を設定したアプリには SQL30108N が返ります。これはエラーではなく「新プライマリへ再接続した」通知です。ここをエラー扱いすると、切り替えは成功しているのにアプリが止まります。アプリ側の扱いは別記事にまとめました。

https://zenn.dev/firese/articles/db2-sql30108n-acr

📕 もっと深く:Db2運用を12章で体系化した本を書きました

この記事で扱ったテイクオーバーの切り分けは、HADR運用の一部です。

Db2はRDBMS市場でシェア数%。情報が少なく、頼れるのは膨大な公式マニュアルだけ——そんな現状を変えたくて、「なぜこの値にするのか」「この障害のとき次に何を見るのか」という、マニュアルに載っていない現場の文脈を1冊にしました。実機で検証した内容と、Db2の設計上そうなる理由をまとめました。

アーキテクチャ/構成パラメーター選定/セキュリティ/バックアップ・リカバリ/HADR(本記事の深掘り版:構築・状態確認・テイクオーバー・pureScale+HADRの落とし穴・ACR)/pureScale/日常点検の自動化/メモリ・ロック競合/SQLチューニング/RUNSTATS・REORG/MON_GET監視/現場の難題集まで、全12章+運用シェルスクリプト集です。

https://zenn.dev/firese/books/db2-practical-bible

HADRの切り替えで踏んだ地雷や、扱ってほしいテーマがあれば、ぜひコメントで教えてください。次の記事のネタにさせてもらいます。

Discussion