バックエンドサービスTCP通信異常調査

ビジネスモデル:バックエンドサービスはTCP経由でグループのマーケットデータゲートウェイと接続を確立します。各接続において、まず認証リクエストを送信し、その後、継続的にハートビートパケットを送信して接続状態を維持します。 しかし、ある日、サービス接続が切れているという警告メッセージを受け取りました。ログを詳細に調査した結果、バックグラウンドサービスは継続的にハートビートパケットを送信しているものの、相手からの応答はなく、それでも接続は切断されませんでした。

現場概説

元々会社で残業してプロジェクトの進捗を詰めていたところ、仕事のグループチャットに突然警告メッセージが飛び込んできた。最初はよくあるトラブルかと思ったが、ネットワークのタイムアウトで心跳送信が失敗し、結果としてサービス接続が切れたのだろうと推測した。しかし、ログを詳しく調査したところ、実際はそうではなかった。バックエンドから認証ログインメッセージは送信されているものの、応答がないままで、その間も心跳パケットは途絶えず送られ続けている。ログの深掘り分析の結果、以下のいくつかの重要な問題点が明らかになった:

認証メッセージに応答がない場合、相手のシステムが再起動中の可能性が非常に高く、その結果、認証メッセージがタイムリーに処理されなかったと考えられます。 未認証のままハートビートデータが送信される問題について調査した結果、プログラムのロジックに欠陥があることが判明しました。ハートビート送信関数の判定ロジックには問題があり、接続状態のみを検証しているものの、認証状態の検証は考慮されていませんでした。 サービスが接続を解除できれば、再接続メカニズムがトリガーされ、承認メッセージが再送信されます。

現在、まだ最後の解決すべき問題が残っています—それはなぜサービスが接続を切断していないのかです。この問題を解決するには、より深く詳細な調査が必要です。

ネットワークデータパケットを解析する

tcpdumpは非常に強力なネットワークパケットキャプチャツールであり、ネットワークデータパケットをキャプチャするために使用できます。ネットワークパケットを分析することで、ネットワーク通信の詳細をより直感的に理解できます。ここでは、tcpdumpを使用してネットワークデータパケットをキャプチャし、さらに分析することができます。

tcpdump

グラフ中のデータから、心拍が常に正常に送信されていることがわかりますが、相手側のサーバーからはデータが一切返信されておらず、ただ ACK だけが送られてきました。これにより、接続は自動的に切断されません。

一般的なフラグの説明

TCPプロトコルにおいて、PSH(Push)とACK(Acknowledgment)は、データ転送とフロー制御の確認にそれぞれ使用される重要なフラグです。それらの役割は以下の通りです。


1. PSH(Push Flag)

  • 機能: PSH フラグの役割は、**受信側がバッファ内のデータを上層アプリケーションに直ちにプッシュする(バッファがいっぱいになるまで待つのではなく)**ことです。つまり、PSHフラグが付いたデータセグメントを受信すると、受信側は可能な限り速やかに処理してアプリケーションに渡すため、オペレーティングシステムのバッファに一時的に保存することはありません。

  • 典型的な状況:

    • HTTP/HTTPSリクエスト:クライアントがリクエストを送信する際(例:GET /index.html)には、PSHを設定し、サーバーに直ちにレスポンスすることを期待します。
    • SSHプロトコル:キーボード入力ごとにPSHがトリガーされ、入力文字のリアルタイム転送を保証します。
    • リアルタイム通信:ビデオストリーミングやオンラインゲームなどの低遅延シナリオでは、PSHを使用して遅延を削減することがあります。
  • 注意:

    • PSHは必須ではなく、受信側はこのフラグを無視しても構いません(ただし、データは通常通り処理する必要があります)。
    • 送信元がPSHを設定しない場合、受信側は自身のバッファポリシーに基づいてデータをいつプッシュするかを決定します。

2. ACK(Acknowledgment Flag)

  • 機能: ACK フラグは、先行するデータセグメントが正しく受信されたことを示すものです。各 ACK には、期待される次のバイトのシーケンス番号を含む確認番号(Acknowledgment Number)が含まれており、これは TCP の信頼性のある転送の中核となるメカニズムです。

  • 動作原理:

    • 送信元がデータセグメントを送信する際、受信者が期待する ACK 値(例えば ACK = シーケンス番号 + データ長)を一緒に持ちます。
    • 受信側はデータを受信後、ACKセグメントを生成し、受信確認済みのデータシーケンス番号を示すものとする。
    • 送信者は、対応するACKを受け取るまで、未確認のデータを再送しません。
    • 送信元がシーケンス番号100~199のデータセグメントを送信した場合、受信側のACK200であるべきです。
    • 受信側が100~199のデータの一部を受信していない場合、ACK=150を送信側に送信して再送を要求します。

PSHとACKの組み合わせ

TCP パケットにおいて、PSHACK が同時に出現することは、以下の状況でよく見られます。

  • HTTPリクエスト応答 クライアントが POST リクエストを送信する際(データを含む場合)、PSHACK(以前の応答に対する確認)が設定されます。

    Client → Server: SYN, ACK=1 → 建立连接
    Client → Server: PSH, ACK=1, 数据 → 发送请求数据
    Server → Client: PSH, ACK=数据长度+1 → 返回响应
    
  • SSHハンドシェイク後のコマンド送信 クライアントがコマンドを入力すると、PSHACKを含むデータセグメントを送信し、コマンドが直ちに転送され、サーバーによって処理されることを保証します。


他のフラグとの関連

フラグ 名前 簡単な説明
SYN 同期 初期化接続(三次握手)
FIN 終了 エレガントな接続のクローズ
リセット 強制終了 (異常時)
URG 緊急 緊急ポインタをマークする(ほとんど使用しない)

まとめ

  • データがアプリケーション層にできるだけ早く到達することに注力し、遅延を低減することです。
  • ACKは、データの信頼性のある転送に焦点を当てており、パケットの消失や順不同を避けることを目的としています。

両者は協調して働き、TCPプロトコルの効率と信頼性のバランスを取った。

金融ITプログラマーのいじくり回しと日常のつぶやき
Hugo で構築されています。
テーマ StackJimmy によって設計されています。