TCPソケットSYNキューとAcceptキューの差異分析

TCPソケットSYNキューとAcceptキューの差異分析

まず、「LISTENING」状態の TCP ソケットには 2 つの独立したキューがあることを理解する必要があります。

  • SYN キュー
  • キューを受け入れる

これら 2 つの用語は、「reqsk_queue」、「ACK バックログ」、「listen バックログ」、または「TCP バックログ」と呼ばれることもありますが、混乱を避けるためにこの記事では上記の 2 つの用語を使用します。

SYN キュー

SYN キューには、SYN パケットを受信する接続が格納されます (カーネル コード構造 struct inet_request_sock に対応)。その役割は、SYN+ACK パケットに応答し、タイムアウトするまで ACK パケットが受信されない場合は再送信することです。 Linux では、再送信回数は次のようになります。

$ sysctl net.ipv4.tcp_synack_retries

net.ipv4.tcp_synack_retries = 5

ドキュメントにおける tcp_synack_retries の説明は次のとおりです。

tcp_synack_retries - 整数
パッシブ TCP 接続の SYNACK を再送信する回数。値は 255 を超えることはできません。
デフォルト値は 5 です。初期 RTO が 1 秒の場合、対応する最後の再送信は 31 秒になります。
対応する最後のタイムアウトは 63 秒後です。

SYN+ACK を送信した後、SYN キューはクライアントから送信された ACK パケット (つまり、3 ウェイ ハンドシェイクの最後のパケット) を待機します。 ACK パケットを受信すると、まず対応する SYN キューが見つかり、次に対応する SYN キュー内の関連データが一致しているかどうかがチェックされます。一致した場合、カーネルは接続に関連するデータを SYN キューから削除し、完全な接続 (カーネル コード構造 struct inet_sock に対応) を作成し、この接続を Accept キューに追加します。

キューを受け入れる

Accept キューには、確立された接続、つまり上位レベルのアプリケーションによって削除されるのを待機している接続が格納されます。プロセスが accept() を呼び出すと、ソケットはキューから取り出され、上位レベルのアプリケーションに渡されます。

これは、Linux が SYN パケットを処理する方法の簡単な説明です。ちなみに、ソケットで TCP_DEFER_ACCEPT と TCP_FASTOPEN が有効になっている場合、動作方法が若干異なりますが、この記事では紹介しません。

キューサイズの制限

アプリケーションは、listen(2) システムコールを呼び出して backlog パラメータを渡すことによって、SYN キューと Accept キューの最大サイズを設定します。たとえば、次に示すように、SYN キューと Accept キューの両方の最大サイズは 1024 に設定されています。

聞く(sfd, 1024)

4.3 より前のカーネルでは、SYN キューのサイズは別の方法で計算されることに注意してください。

SYN キューの最大サイズは以前は net.ipv4.tcp_max_syn_backlog を使用して設定されていましたが、現在は使用されなくなりました。現在、net.core.somaxconn は、SYN キューと Accept キューの両方の最大サイズを表すために使用されます。私たちのサーバーでは、これを 16k に設定しています。

$ sysctl net.core.somaxconn

ネット.コア.somaxconn = 16384

上記の情報を知った後、適切なキューのサイズはどれくらいなのかと疑問に思うかもしれません。適切なキューのサイズはどれくらいですか?

答えは「それは場合による」です。ほとんどの TCP サービスでは、これはそれほど重要ではありません。たとえば、Go 言語バージョン 1.11 より前では、キュー サイズを設定するメソッドはありませんでした。

ただし、キューのサイズを増やす正当な理由がいくつかあります。

  • 接続確立要求のレートが非常に高い場合、高性能サービスであっても SYN キューを大きく設定する必要がある場合があります。
  • SYN キューのサイズ、つまり ACK パケットを待機している接続の数。つまり、クライアントとの平均往復時間が長くなるほど、SYN キューに蓄積される接続の数が多くなります。たとえば、ほとんどのクライアントがサーバーから遠く離れているシナリオでは、ラウンドトリップ時間が数百ミリ秒を超えるため、キューのサイズを大きく設定できます。
  • TCP_DEFER_ACCEPT オプションがオンになっている場合、ソケットは SYN-RECV 状態に長く留まるため、SYN​​ キューに留まる時間が長くなります。

ただし、バックログを大きくしすぎると、SYN キューの各スロットにメモリが必要になるため、悪影響が出る可能性があります。 SYN フラッド攻撃に遭遇した場合、これらの攻撃パケットにリソースを浪費する必要はありません。 SYN キュー内の inet_request_sock 構造体は、4.14 カーネルではそれぞれ 256 バイトのメモリを占有します。

Linux では、SYN キューの現在のステータスを表示する場合、ss コマンドを使用して SYN-RECV 状態のソケットを照会できます。たとえば、次の実行結果は、ポート 80 の SYN キューに現在 119 個の要素があり、ポート 443 の SYN キューに 78 個の要素があることを示しています。

$ ss -n 状態 syn-recv スポーツ = :80 | wc -l
119
$ ss -n 状態 syn-recv スポーツ = :443 | wc -l
78

プログラムが accept() を十分な速さで呼び出さない場合はどうなるでしょうか?このデータはSystemTapスクリプトresq.stpでも確認できます。

プログラムが accept() を十分な速さで呼び出さない場合はどうなりますか?

  • それ以降に受信されたSYNパケットはSYNキューによって処理されません。
  • 後続のACKパケット(接続を確立するために使用される)はSYNキューによって処理されません。
  • TcpExtListenOverflows / LINUX_MIB_LISTENOVERFLOWS カウントの増加
  • TcpExtListenDrops / LINUX_MIB_LISTENDROPS カウントの増加

このような状況が発生した場合、プログラムの処理パフォーマンスが後で正常に戻り、サーバーによって破棄されたパケットをクライアントが再送信することを期待するしかありません。

カーネルのこの動作は、ほとんどのサービスで許容されます。ちなみに、グローバルパラメータ net.ipv4.tcp_abort_on_overflow を調整することでこの動作を変更できますが、このパラメータは変更しない方がよいでしょう。

nstat のカウントを表示することで、Accept キューのオーバーフローの状態を観察できます。

$ nstat -az TcpExtListenDrops
TcpExtListenDrops 49199 0.0

しかし、これは世界全体の数です。観察するのは直感的ではありません。たとえば、成長していることが観察されることもありますが、すべてのサービス プログラムは正常であるように見えます。この時点で、ss コマンドを使用して、単一のリスニング ポートの Accept キュー サイズを観察できます。

$ ss -plnt スポーツ = :6443|猫
状態 受信Q 送信Q ローカルアドレス:ポート ピアアドレス:ポート
聞く 0 1024 *:6443 *:*

Recv-Q 列には Accept キュー内のソケットの数が表示され、Send-Q にはキューの最大サイズが表示されます。上記の例では、プログラムによって accepted() されていないソケットはないことがわかりますが、ListenDrops カウントは増加していることがわかります。

これは、プログラムが処理を永久に停止するのではなく、短時間だけ停止して新しい接続を処理しないためです。しばらくすると、プログラムは正常に戻ります。この場合、ss コマンドを使用してこの現象を観察することは難しいため、カーネルにフックして破棄された SYN パケットを出力する SystemTap スクリプトを作成しました。

$ sudo stap -v acceptq.stp
時間 (us) acceptq qmax ローカルアドレス リモートアドレス
1495634198449075 1025 1024 0.0.0.0:6443 10.0.1.92:28585
1495634198449253 1025 1024 0.0.0.0:6443 10.0.1.92:50500
1495634198450062 1025 1024 0.0.0.0:6443 10.0.1.92:65434
...

上記の操作により、どの SYN パケットが ListenDrops の影響を受けるかを観察できます。この方法では、どのプログラムが接続を失っているかを知ることもできます。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Python に基づいて TCP 3 ウェイ ハンドシェイク接続をシミュレートし、データを送信する
  • TCP/IPプロトコルにおける3ウェイハンドシェイクと4ウェイウェーブの原理とプロセスの分析
  • TCPの3ウェイハンドシェイクと4ウェイウェーブの詳細な紹介
  • Wireshark の基本的な紹介と TCP 3 ウェイ ハンドシェイクの学習
  • TCP 3ウェイハンドシェイクと原理
  • Java での TCP プロトコル ソケット ネットワーク プログラミングに基づくファイル転送の実装
  • TCPパフォーマンスチューニングの実装原理とプロセス分析
  • JavaはTCPプロトコルに基づいてファイルアップロードを実装します
  • TCP 3 回目のハンドシェイク データ転送プロセス図

<<:  HTML テーブルタグチュートリアル (32): セルの水平方向の配置属性 ALIGN

>>:  MySQLは実際に分散ロックを実装できる

推薦する

Windows に異なる (2 つの) バージョンの MySQL データベースをインストールする詳細なチュートリアル

1. 原因: SQL ファイルをインポートする必要があるのですが、インポートできません。この文を実行...

MySQLのインデックス設計の原則と一般的なインデックスの違いについて簡単に説明します。

インデックス定義: ディスク上に保存される個別のデータベース構造であり、データ テーブル内のすべての...

HTML におけるスクリプトの配置に関する簡単な説明

以前は、スクリプトは HTML 内のどこにでも配置できると思っていましたが、今日、要件に取り組んでい...

Centos7でmysql6の初期化インストールパスワードをインストールする方法

1. まずデータベースサーバーを停止しますサービスmysqld停止2.vim /etc/my.cnf...

nginx プロキシ サーバーで双方向証明書検証を構成する方法

証明書チェーンを生成するスクリプトを使用して、ルート証明書、中間証明書、および 3 つのクライアント...

thead、tfoot、tbodyを使用して表を作成します

これらの 3 つのタグを間違った方法で使用して、タイトルを表に沿わせたり、tbody の高さを固定し...

シャドウソックスを使用してLAN透過ゲートウェイを構築する

目次dnsmasq をインストールして設定するChinaDNS をインストールして設定するshado...

Linux で docker-compose を使用したソフトウェア構成の詳細な説明

序文この記事では、docker-compose の構成をいくつか紹介します。これらを参考にして、独自...

grep を使用して MySQL エラー ログ情報を取得する方法の詳細な説明

MySQL のメンテナンスを容易にするために、エラー情報を収集するためのインターフェースを提供するス...

反応ルーティングでパラメータを渡すいくつかの方法についての簡単な説明

最初のパラメータ渡し方法は、動的ルーティングパラメータ渡しです。リンクのパス属性を設定することで、ル...

DockerでLNMPアーキテクチャを展開する方法

環境要件: IPホスト名192.168.1.1ノード1プロジェクト計画:コンテナネットワークセグメン...

SqlクエリMySqlデータベーステーブル名と説明テーブルフィールド(列)情報

以下では、SQL クエリ ステートメントを使用して、Mysql データベース内のテーブルのテーブル名...

XHTML 入門チュートリアル: よく使われる XHTML タグ

<br />記事と同様に、Web ページにも明確な段落と重要度の異なるタイトルが必要です...

PHP 開発環境の構築に関する win10 docker-toolsbox チュートリアル

画像をダウンロード docker プル mysql:5.7 docker pull php:7.2-...