🔌

Db2の「SQL30081N 通信エラー」はメッセージを正しく読めば9割切り分けられる

に公開

アプリからDb2に繋がらない。ログに出ているのは SQL30081N「通信エラーが検出されました」——。ネットワーク担当は「経路は問題ない」と言い、DB担当は「Db2は上がっている」と言い、原因がチーム間を行ったり来たりする。SQL30081N は、そんな押し付け合いを生みやすいエラーです。

しかし SQL30081N は、メッセージ本文に切り分けに必要な情報がほぼ全部載っています。多くの現場が「通信エラー」という見出しだけ見て中身を読み飛ばすせいで、当てずっぽうの調査になっているだけです。この記事では、SQL30081N のメッセージのどこを読めば、サーバー・ネットワーク・クライアントのどこで詰まっているかが分かるかを解説します。

まず結論:SQL30081N は「メッセージの3項目」で切り分ける

SQL30081N のSQLSTATEは 08001(接続確立の失敗)。メッセージ本文は長いですが、切り分けに効くのは次の3項目です。

SQL30081N  A communication error has been detected.
           Communication protocol being used: "TCP/IP".
           Communication API being used: "SOCKETS".
           Location where the error was detected: "192.168.0.11".
           Communication function detecting the error: "connect".   ← ①どの段階で失敗したか
           Protocol specific error code(s): "111", "*", "*".        ← ②OSレベルの理由(errno)
           ...  SQLSTATE=08001

見るべきは次の3つです。

  1. Communication function(失敗した通信関数)connect なら「接続を張る段階」、recvsend なら「一度繋がった後に切れた」。ここでサーバー到達前か後かが分かる
  2. Protocol specific error code(s)(プロトコル固有エラーコード) … Linuxでは先頭がOSの errno。ここで理由が分かる
  3. Location(エラー検出箇所) … 詰まっている接続先のIP。宛先が想定どおりか確認する。

errno の代表値だけ覚えておけば、大半は即断できます。

function errno 意味 詰まっている場所
connect 111(ECONNREFUSED) 接続拒否。ホストには届いたが、そのポートで誰も待ち受けていない サーバー側(Db2停止/ポート違い)
connect 110(ETIMEDOUT) 接続タイムアウト。そもそもホストに届かない ネットワーク(FW/経路/ホスト断)
recv 104(ECONNRESET) 接続リセット。一度繋がった後にセッションが切られた 途中で切断(アイドル切断/FORCE/異常終了)

connect+111 なら真っ先にサーバー側、connect+110 ならネットワーク、recv+104 なら「繋がった後に何が切ったか」、と最初の一手が変わります。ここを読まずに全部を「通信エラー」でひとくくりにするから、調査が空回りします。

connect + 111(接続拒否):まずサーバー側を疑う

いちばん多いのがこれです。「ホストには到達しているが、そのポートでDb2が待ち受けていない」状態。原因はほぼ次の3つです。

① Db2のTCPリスナーが上がっていない(DB2COMM)

Db2は DB2COMM レジストリ変数に TCPIP が入っていないと、そもそもTCPで待ち受けません。インスタンス再起動後にこれが外れていて全クライアントが繋がらない、というのは定番の事故です。

# TCPリスナーが有効か(TCPIP が入っているか)
db2set -all | grep -i DB2COMM
# 例: [i] DB2COMM=TCPIP,SSL

# 入っていなければ設定し、インスタンスを再起動して反映
db2set DB2COMM=TCPIP,SSL
db2stop
db2start

② 待ち受けポートが想定と違う(SVCENAME)

Db2が待ち受けるポートは、DBM構成の SVCENAME で決まります。SVCENAME にはポート番号そのものか、/etc/services に定義したサービス名を書けます。サービス名で書いている場合、/etc/services のポート定義とセットで初めてポートが確定します。

# Db2が待ち受けるサービス名/ポートを確認
db2 "GET DBM CFG" | grep -iE "SVCENAME"
# 例: TCP/IP Service name (SVCENAME) = db2c_db2inst1

# サービス名なら /etc/services で実ポートを確認
grep db2c_db2inst1 /etc/services
# 例: db2c_db2inst1   50000/tcp

③ 本当にポートで待ち受けているかをOS側で確認する

Db2の設定が正しく見えても、実際にリスニングしているかはOSで直接確認するのが確実です。

# Db2プロセス(db2sysc)が目的のポートでLISTENしているか
ss -ltnp | grep db2sysc
# 例: LISTEN 0 4096 0.0.0.0:50000 ... users:(("db2sysc",pid=3631,...))

ここに目的のポート(例では 50000)が出ていれば、サーバー側は正常です。出ていなければ①②に戻ります。出ているのにクライアントから繋がらないなら、次のネットワークへ進みます。

connect + 110(タイムアウト):ネットワークを疑う

connect110(ETIMEDOUT)なら、パケットがホストに届いていません。サーバー側の設定を見ても意味がないので、経路とファイアウォールを確認します。

# クライアント → サーバーのポート疎通を単体で確認(Db2を介さない)
nc -zv 192.168.0.11 50000
# または
telnet 192.168.0.11 50000

# サーバー側のファイアウォールでポートが開いているか(firewalld)
firewall-cmd --list-ports
firewall-cmd --add-port=50000/tcp --permanent && firewall-cmd --reload

nctelnet が通らなければDb2以前の問題です。ここでネットワーク担当と話すときは、「SQL30081N が出た」ではなく「50000/tcp への connect110 でタイムアウトする。nc でも届かない」と伝えると、話が一段速くなります。

recv + 104(接続リセット):繋がった後に「何が切ったか」

connect は成功していて recvsend で失敗(104 ECONNRESET など)なら、一度は接続できたということです。切り分けの向きが変わり、「繋がらない」ではなく「繋がった後に誰かが切った」を追います。これがいちばん厄介で、再現しづらいパターンです。

代表的な原因は次のとおりです。

  • ファイアウォール/ロードバランサのアイドルタイムアウト:一定時間無通信のコネクションを経路上の機器が黙って切る。接続プールで「たまに最初の1回だけ失敗する」典型。
  • サーバー側の FORCE APPLICATION や異常終了:DB側で接続が切られた。db2diag.log に痕跡が残る。
  • クライアント/サーバーのクラッシュ・再起動

まずDb2側にサーバー起因の切断が記録されていないかを見ます。

# 発生時刻付近の通信・接続関連イベントを抽出
db2diag -g "level:=Error" -H 1d | grep -iE "communication|sqlcc|recv|reset"

TCPキープアライブはDb2のレジストリ変数でも調整できます。

# アイドル接続へのキープアライブ送出間隔(秒)を短くする
db2set DB2TCPKEEPALIVE=60
db2stop
db2start

SQL30081N と SQL30108N は別物

混同されがちですが、SQL30081N(SQLSTATE=08001)と SQL30108N(SQLSTATE=08506)は意味が正反対です。

SQL30081N(08001)= 通信の確立・継続に失敗した「本当のエラー」
SQL30108N(08506)= 接続が切れたが自動再接続に成功した「通知」(ACR成功)

ACR(自動クライアントリルート)を構成している環境では、切断が起きても代替サーバーへ繋ぎ直せれば SQL30108N(通知)が返り、**代替にも繋がらなかったときに初めて SQL30081N(本当のエラー)**が返ります。SQL30108N の扱い方は別記事で詳しく書いています。

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

SQL30081N が出たときのチェックリスト

メッセージを読むのが最初です。

  1. メッセージの Communication function を見る(connect=接続段階 / recvsend=接続後)
  2. Protocol specific error code(s) の先頭(errno)を見る(111=拒否 / 110=タイムアウト / 104=リセット)
  3. connect+111 … サーバー側。DB2COMMTCPIPSVCENAME/etc/services のポート、ss -ltnp でリスニング確認
  4. connect+110 … ネットワーク。nc -zv host port で疎通、firewall-cmd でポート開放確認
  5. recv+104 … 接続後の切断。db2diag.log にサーバー起因の記録があるか。無ければ経路のアイドル切断を疑い、キープアライブ/接続プール検証で対処
  6. SSL構成なら、平文ポートとSSLポートの取り違えを確認する
  7. ACR構成で SQL30108N と混同していないか確認する(08001=エラー / 08506=再接続成功)

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

この記事で扱った SQL30081N の切り分けは、Db2運用のほんの一部です。

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

アーキテクチャ/構成パラメーター選定/セキュリティ(TLS・ポート設計)/バックアップ・リカバリ/HADR/pureScale/日常点検の自動化(db2diag.logの読み方)/メモリ・ロック競合/SQLチューニング/RUNSTATS・REORG/MON_GET監視/現場の難題集まで、全12章+運用シェルスクリプト集です。

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

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

Discussion