WebSocketは接続が長時間続くため、HTTPのレスポンスコードだけでは正常性を十分に把握できません。現在の接続数、接続失敗、切断・再接続、メッセージ送受信数、heartbeat timeout、通信遅延などを継続的に観測する必要があります。全体傾向はメトリクスで把握し、個別の接続がなぜ切れたのかはログで追跡する、と役割を分けることで、WebSocket障害の原因を調べやすくなります。

1. WebSocketに監視が必要な理由
1-1. 長時間接続はHTTPリクエストとは見え方が違う
WebSocketでは、接続確立後に同じ通信路を長時間利用するため、HTTP APIと同じ指標だけでは状態を把握しにくくなります。最初のハンドシェイクが成功していても、その後の通信品質までは分かりません。
HTTP APIでは、リクエストごとのステータスコード、レスポンスタイム、エラー率などを確認できます。一方WebSocketでは、一度接続した後に数分、数時間と通信が継続することがあるため、「接続確立に成功したか」だけでは運用状況を判断できません。
例えばWebSocketのハンドシェイク成功率が正常でも、その後に大量の切断が発生している可能性があります。HTTP系の監視は引き続き必要ですが、それに加えてWebSocket固有の接続数、切断数、再接続数などを監視します。
1-2. 接続できていても品質が低下する場合がある
WebSocketは接続が残っていても、通信遅延やメッセージ処理の滞留によって品質が低下する場合があります。そのため「接続中かどうか」だけで正常性を判断するのは不十分です。
例えばネットワーク品質が悪化すると、heartbeatの応答が遅くなったり、メッセージの到着が遅延したりします。また、サーバー側のCPU負荷やイベントループ遅延が増えると、接続自体は維持されていてもアプリケーションの応答が遅くなることがあります。
そのため、接続数だけではなくheartbeat timeout、RTT、送信キュー、メッセージ処理時間なども合わせて確認します。接続数が多いこと自体は異常ではなく、「通常時と比べてどの指標がどう変化したか」を見ることが重要です。
1-3. 継続的に状態を観測する
WebSocketでは、接続開始から切断までの状態を継続的に観測できるようにします。瞬間的な値だけでなく、時間による変化を見ることが重要です。
例えば現在接続数が1万件だったとしても、その値だけでは正常か異常か判断できません。通常も同程度なら問題ないかもしれませんが、数分前まで2万件だったものが急に1万件へ減っていれば、大量切断が発生した可能性があります。
接続数、切断数、再接続数、heartbeat timeout、RTTなどを時系列で可視化すると、「いつから異常が始まったか」「複数指標が同時に変化しているか」を確認できます。監視では絶対値だけでなく変化量も重要です。
2. 最低限監視したいメトリクス
2-1. 現在の接続数と接続試行数
まず監視したいのは、現在のWebSocket接続数と接続試行数です。接続数はサーバーが現在どれだけの長時間接続を保持しているかを示します。
接続試行数も重要です。通常時より接続試行が急増している場合、大量の新規利用者が来ている可能性もあれば、既存クライアントが何度も再接続している可能性もあります。
例えば現在接続数が減少しながら接続試行数だけが急増している場合、クライアントが接続と切断を繰り返している可能性があります。接続数単体ではなく、接続成功数・失敗数と組み合わせて確認します。
2-2. 切断数と再接続数
切断数と再接続数は、WebSocketの安定性を把握する重要な指標です。通常より急激に増えた場合、ネットワーク障害やサーバー障害、ロードバランサー設定などを疑う材料になります。
ただし、切断そのものがすべて異常とは限りません。利用者が画面を閉じたときにも切断は発生しますし、デプロイ時に計画的な切断が発生する場合もあります。
そのため、切断数だけではなくClose Code、平均接続時間、再接続数などを組み合わせます。短時間の接続が大量に発生し、再接続数も増えているなら、接続が安定していない可能性が高くなります。
2-3. メッセージ送受信数とエラー数
WebSocketでは、送受信メッセージ数とエラー数も監視します。接続が維持されていても、メッセージ処理に問題があればリアルタイム機能は正常に動作しません。
受信数、送信数、処理失敗数を分けて計測すると、問題がどこで起きているかを判断しやすくなります。例えば受信数は正常なのに送信数が急減している場合、サーバー側の配信処理やメッセージブローカーで問題が発生している可能性があります。
最低限のメトリクスは、次のように整理できます。
| メトリクス | 見る目的 | 異常時に考えられる例 |
|---|---|---|
| 現在接続数 | 接続規模を把握する | 大量切断、急激な利用増加 |
| 接続試行数 | 接続要求の変化を見る | 再接続集中、新規アクセス増加 |
| 接続失敗数 | 接続確立時の異常を見る | 認証失敗、サーバー停止 |
| 切断数 | 接続安定性を見る | ネットワーク障害、タイムアウト |
| 再接続数 | 復旧試行の増加を見る | 大量切断後の再接続集中 |
| 送信メッセージ数 | 配信量を見る | 配信停止、急激な負荷増加 |
| 受信メッセージ数 | 入力量を見る | クライアント側異常、負荷増加 |
| メッセージ処理エラー数 | 処理失敗を見る | バリデーション・内部処理エラー |
| heartbeat timeout数 | 通信不能傾向を見る | 回線悪化、サーバー遅延 |
| heartbeat RTT | 往復遅延を見る | ネットワーク・処理遅延 |
| 接続時間 | 短時間切断を検知する | 接続ループ、設定不整合 |
| Close Code別切断数 | 切断理由を分類する | 正常終了・異常終了の傾向把握 |
3. heartbeatから通信状態を見る
3-1. timeout回数を記録する
heartbeatを実装している場合は、timeout回数をメトリクスとして記録します。接続オブジェクトが残っていても応答が返らない状態を検知できるからです。
heartbeat timeoutが増える原因には、ネットワーク断、サーバーの高負荷、イベントループ遅延、バックグラウンド状態によるタイマー遅延などがあります。そのためtimeoutだけで原因を断定せず、他の指標と組み合わせます。
例えば「heartbeat timeout増加」と同時に「CPU使用率上昇」が起きていれば、サーバー処理遅延を疑えます。一方、CPUは正常なのに特定地域のクライアントだけtimeoutが増えている場合は、ネットワーク側の問題も考えられます。
3-2. 往復時間RTTを測る
heartbeatの送信時刻と応答受信時刻を記録すると、RTT(Round Trip Time:往復時間)を測定できます。RTTは通信状態の変化を見る参考指標として利用できます。
計算方法は単純です。
RTT = heartbeat応答受信時刻 - heartbeat送信時刻
JavaScriptで計測するなら、次のような形です。
let heartbeatSentAt = null;
function sendHeartbeat(socket) {
heartbeatSentAt = performance.now();
socket.send(
JSON.stringify({
type: "heartbeat_ping"
})
);
}
function handleHeartbeatPong() {
if (heartbeatSentAt === null) {
return;
}
const rtt = performance.now() - heartbeatSentAt;
console.log(`heartbeat RTT: ${rtt.toFixed(1)} ms`);
recordMetric("websocket_heartbeat_rtt_ms", rtt);
heartbeatSentAt = null;
}
コードの役割: heartbeatを送信した時刻と応答を受信した時刻の差からRTTを求めています。
なぜ必要か: 単にtimeoutしたかどうかだけでなく、「普段より通信が遅くなっている」という兆候を検知できるためです。
注意点: heartbeat RTTはネットワーク往復時間だけを純粋に測っているとは限りません。サーバー側でheartbeat応答を処理するまでの待ち時間や、ブラウザ側のイベント処理遅延も含まれる可能性があります。そのため、アプリケーション全体のレスポンスタイムと同じ指標として扱わないようにします。
3-3. 遅延の増加傾向を見る
heartbeat RTTは、単発の値より時間的な傾向を見ることが重要です。一時的な遅延だけで障害と判断すると誤検知が増えます。
例えば通常時のRTTが安定している環境で、数分間かけて徐々に上昇している場合は、ネットワーク混雑やサーバー負荷の兆候かもしれません。逆に1回だけ大きな値が出てすぐ戻るなら、一時的な遅延の可能性があります。
平均値だけでなく中央値や上位パーセンタイルを見ると、一部の接続だけが遅い状況も見つけやすくなります。ただし固定の「何ms以上なら障害」という値をすべてのサービスへ適用せず、通常時の傾向と利用要件から判断します。
4. 切断ログを残す
4-1. 接続開始・終了時刻を記録する
WebSocket接続の開始時刻と終了時刻をログへ残すと、接続時間を調査できます。短時間で切断を繰り返している接続を見つける際に役立ちます。
接続ログには、接続ID、サーバーID、開始時刻、終了時刻、認証済みユーザーを直接特定しない安全な識別子などを記録します。必要に応じて接続元のネットワーク情報を扱う場合もありますが、個人情報の扱いには注意が必要です。
接続開始時のログ例は次のようになります。
event=websocket_connected
connection_id=ws_8f3a2
server_id=ws-server-a
connected_at=2026-08-26T09:30:00+09:00
authenticated=true
切断時は次のように記録できます。
event=websocket_closed
connection_id=ws_8f3a2
server_id=ws-server-a
connected_at=2026-08-26T09:30:00+09:00
closed_at=2026-08-26T09:42:18+09:00
duration_ms=738000
close_code=1000
was_clean=true
なぜ必要か: 同じconnection_idで開始と終了を関連付けることで、どのくらい接続が続いたか、どのサーバーで切れたかを調査できます。
4-2. Close Codeと切断理由を確認する
WebSocketの切断時にはClose Codeを記録すると、終了理由を分類しやすくなります。ブラウザではcloseイベントのCloseEvent.codeから確認できます。
例えば1000はNormal Closureを表しますが、1000以外がすべてサーバー障害というわけではありません。プロトコルエラー、ポリシー違反、メッセージサイズ、アプリケーション独自の終了理由など、コードによって意味が異なります。
ブラウザ側では次のように取得できます。
socket.addEventListener("close", (event) => {
console.log({
code: event.code,
reason: event.reason,
wasClean: event.wasClean
});
});
コードの役割: Close Code、理由文字列、クリーンに終了したかどうかを記録します。
なぜ必要か: 「切れた」という事実だけでは原因を絞り込めません。Close Code別に件数を見ることで、正常終了が増えたのか、異常系コードが増えたのかを判断できます。
例えば通常は1000が中心なのに、特定のデプロイ後から1008など特定コードが増えた場合、サーバー側のポリシー判定や認可処理の変更を確認する、といった調査につなげられます。
4-3. 再接続との関連を追える情報を残す
切断ログと再接続ログを関連付けられるようにすると、1回の障害でどの程度接続が揺れたかを追跡できます。
接続ごとに新しいconnection_idを発行しつつ、同じブラウザセッションや再接続系列を識別するsession_idやreconnect_chain_idのような識別子を持たせる方法があります。ただし、それらの値に生のアクセストークンや個人情報を利用してはいけません。
例えば次のようにログを残します。
event=websocket_reconnect
reconnect_chain_id=rc_2049
previous_connection_id=ws_8f3a2
new_connection_id=ws_91c7b
attempt=2
なぜ必要か: 切断1件ずつを見るだけでは、同じクライアントが短時間に何度も接続し直しているか分かりません。再接続系列を追えると、接続ループや大量再接続の原因分析がしやすくなります。
5. WebSocket障害を複数の指標から調べる
5-1. 切断数と再接続数を組み合わせて見る
切断数と再接続数はセットで見ると状況を判断しやすくなります。どちらか一方だけでは、正常な利用終了なのか障害なのか判断しにくいためです。
例えば切断数が増えていても再接続数が増えていなければ、利用者が画面を閉じただけかもしれません。一方、切断数と再接続数が同時に急増している場合は、多くのクライアントが接続を失って復旧を試みている可能性があります。
さらに現在接続数が急減していれば、より大規模な障害を疑えます。このように「切断増加 + 再接続増加 + 接続数減少」の組み合わせで見ると、単一指標より判断精度が上がります。
5-2. heartbeat timeoutとRTTから通信状態を見る
heartbeat timeoutとRTTを組み合わせると、通信品質が悪化してから完全に応答しなくなるまでの変化を観測できます。
例えばRTTの上位パーセンタイルが徐々に上昇し、その後heartbeat timeoutが急増した場合、ネットワークやサーバー処理の遅延が悪化した後に切断へ発展した可能性があります。
逆にRTTは安定しているのに突然多数の切断が発生した場合は、サーバープロセスの再起動、ロードバランサー設定、デプロイなど別の原因を調べるべきかもしれません。
典型的な判断例は次のようになります。
再接続数 ↑ 急増
heartbeat timeout ↑ 急増
RTT ↑ 上昇
CPU ↑ 上昇
この組み合わせなら、サーバー高負荷によってheartbeat処理が遅れ、timeoutと再接続が増えた可能性を疑います。
一方で、
再接続数 ↑ 急増
heartbeat timeout ↑ 急増
RTT ↑ 特定地域のみ上昇
CPU → 通常
であれば、ネットワーク経路や地域依存の問題を疑う材料になります。
5-3. Close Codeとログから切断原因を絞り込む
切断原因の調査では、メトリクスで異常時間帯を特定し、その時間のClose Code分布とログを確認します。メトリクスとログを役割分担させる考え方です。
例えば「10時15分から切断数が通常の数倍になった」とメトリクスで分かったら、その時間帯のClose Code別件数を確認します。特定コードだけ増えているなら、そのコードに対応する処理を優先的に調査できます。
さらにserver_id、接続時間、デプロイ時刻などを照合します。Server Bだけで異常切断が増えていれば、そのノード固有の問題かもしれません。全サーバーで同時に発生していれば、ロードバランサーやネットワーク、共通依存サービスを疑います。
6. アラート設計とログの注意点
6-1. 通常時の傾向を基準に異常を検知する
WebSocketのアラートは、固定値だけではなく通常時の傾向を基準に設計します。接続数やメッセージ数は時間帯や曜日によって大きく変わるためです。
例えば平日昼間に接続数が増えるサービスでは、接続数の増加自体は正常です。逆に深夜でも一定数存在するサービスなら、急減のほうが異常かもしれません。
そのため「接続数が1万を超えたら障害」と一律に決めるのではなく、過去の通常範囲、サーバー容量、CPU・メモリ、再接続数などと合わせて判断します。サービスごとのベースラインを作ることが重要です。
6-2. 単一指標だけで判断しない
WebSocket障害は、単一のメトリクスだけで原因を断定しないことが重要です。同じ指標の変化でも、複数の原因が考えられます。
例えばheartbeat timeout増加はネットワーク障害だけでなく、サーバーCPU高負荷やJavaScriptタイマー遅延でも起こります。再接続数増加も、障害だけでなく計画的なサーバー再起動で発生する場合があります。
アラートでは「heartbeat timeout増加 + 再接続増加」「接続数急減 + Close Code異常増加」のように複数の指標を関連付けると、重要度を判断しやすくなります。
6-3. 認証情報や個人情報をログへ残さない
WebSocketのログには、認証情報、個人情報、メッセージ本文を無条件に保存しないようにします。リアルタイム通信ではメッセージ数が多いため、ログ量だけでなく情報漏えいリスクも大きくなります。
特にアクセストークン、Cookie、JWT全体、Authorization情報などをログへ記録してはいけません。ユーザーのチャット本文や個人情報も、デバッグ目的だからといって無制限に保存すべきではありません。
原因分析に必要なのは、多くの場合connection_id、イベント種別、Close Code、処理時間、メッセージ種別、エラーコードなどです。本文が必要な場合でもマスキング、サンプリング、保存期間制限などを検討します。
7. まとめ
7-1. 接続・切断・通信品質を継続して観測する
WebSocketの監視では、接続できたかどうかだけでなく、その後の通信品質と切断状況を継続的に観測する必要があります。長時間接続だからこそ、時間の変化を見ることが重要です。
最低限、現在接続数、接続試行・失敗数、切断数、再接続数、メッセージ送受信数、エラー数、heartbeat timeout、RTT、Close Codeなどを監視します。
メトリクスでは全体の傾向を把握し、ログでは個別の接続や切断原因を追跡します。さらにCPU・メモリ・ネットワークなどの基盤指標と組み合わせることで、原因を絞り込みやすくなります。
7-2. WebSocket監視のチェックリスト
WebSocket監視では、「何件なら異常か」という固定値を決める前に、通常時の挙動を理解することが重要です。利用時間帯やシステム規模によって正常範囲は変わります。
また、接続数が多いだけで障害と判断せず、切断、再接続、RTT、heartbeat timeoutなど複数の指標から状況を確認します。
実装・運用時には、次の項目を確認してください。
- 現在のWebSocket接続数を取得できるか
- 接続試行数と接続失敗数を分けて計測しているか
- 切断数を監視しているか
- 再接続数を監視しているか
- 接続時間を計測しているか
- 短時間接続の急増を検知できるか
- Close Code別の切断数を集計しているか
- Close Code 1000以外を一律に障害扱いしていないか
- メッセージ送信数・受信数を監視しているか
- メッセージ処理エラー数を監視しているか
- heartbeat timeoutを記録しているか
- heartbeat RTTを計測しているか
- RTTをアプリケーション全体の処理時間と混同していないか
- RTTの平均だけでなく分布や上位パーセンタイルも確認しているか
- 接続開始・終了ログを関連付けられるか
- 再接続前後の接続を追跡できる識別子があるか
- サーバーIDをログへ記録しているか
- デプロイ時刻と切断増加を照合できるか
- CPU・メモリ・ネットワーク指標と合わせて確認できるか
- 通常時の接続数やRTTの傾向を把握しているか
- 単一指標だけで障害判定していないか
- 固定アラート閾値をすべての環境へ流用していないか
- アクセストークンやCookieをログへ記録していないか
- 個人情報やメッセージ本文を無条件に保存していないか
- ログのマスキングや保存期間を決めているか
WebSocket監視の目的は、単にグラフを増やすことではありません。「接続が維持できているか」「切断が増えていないか」「通信品質が悪化していないか」を継続的に確認し、異常が起きたときに複数の指標とログから原因を絞り込める状態を作ることが重要です。
8. 参考リンク
この記事では、次の公式仕様・公式資料を参考にしています。