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は実際に分散ロックを実装できる

推薦する

LED を使って Linux カーネルを使い始める方法を探る

目次序文LEDトリガー探索を始めるLEDデバイス登録LEDディレクトリ類推によって理解するクラスディ...

自動的にフォーカスを取得する要素入力ボックスの実装

最近のプロジェクトでフォームを作成するときに、コメント ボックスまで自動的にスクロールし、コメント ...

alpineをベースにdockerfileで作成したクローラーScrapyイメージの実装

1.アルパインイメージをダウンロードする [root@DockerBrian ~]# docker ...

JavaScript でローカル変数をグローバル変数に変換する方法

まず関数の自己呼び出しを知る必要がある関数の自己呼び出し - 自己呼び出し関数1 回限りの関数 - ...

Alibaba Cloud ECS サーバーでポート 8080 を開く方法

セキュリティ上の理由から、Alibaba Cloud Server ECS にはデフォルトで独自のセ...

iFrameは背景を覆うポップアップレイヤーとして使うのに最適です

最近、私は「ぶどうコレクション」というプロジェクトに取り組んでいます。簡単に言うと、Budou ペー...

Centos7 での python3 のインストールとアンインストールに関するチュートリアル

1. Python 3をインストールする1. 依存パッケージをインストールしますyum instal...

MySQL インデックスの設計と最適化の方法

目次インデックスとは何ですか?左端のプレフィックス一致の原則key_lenの計算方法インデックスの最...

JavaScript のドキュメント オブジェクト モデル (DOM)

目次1. DOMとは何か2. 要素を選択する3. getElementById() 4. クエリセレ...

TomcatコンポーネントはWebサーバーのアーキテクチャの進化を示しています

1. tomcat とは誰ですか? 2. Tomcat は何ができますか? Tomcat は Web...

Vue 天気予報入門

この記事では、参考までに天気予報を実装するためのVueの具体的なコードを紹介します。具体的な内容は次...

Vue で pdfjs を使用して PDF ファイルをプレビューする方法

目次序文考えるライブラリディレクトリの解析とダウンロード使い方ファイルの場所実際の通話質問要約する序...

マウスが画像のハイパーリンク上を通過するときに画像のサイズ(幅、高さ)を変更する CSS

マウスが画像の上を通過したときに画像のハイパーリンクを変更する方法:コードをコピーコードは次のとおり...

ログインフォームを実装するためのJavaScript

この記事の例では、ログインフォームを実装するためのJavaScriptの具体的なコードを参考までに共...

CSSは、マウスを線の上に置くと線全体の色を変える効果を実現します。

まとめ:以下のように、CSS で指定した行にマウスを置いたときに行全体の色を変更する方法を示します。...