web-dev-qa-db-ja.com

チューニング方法TCP 2つのノード間の高周波接続用

私は過去数日間頭を悩ませており、次の問題の解決策を考え出そうとしています:

私たちのデータセンターでは、BigIPハードウェア上で実行されているF5を使用しています。F5は、全国のさまざまなオフィスの場所にあるクライアントマシンからのHTTPSリクエストの単一の入口ポイントとして機能します。 F5はTLSを終了し、すべての要求を2つのTraefikロードバランサーに転送します。2つのTraefikロードバランサーは、要求をさまざまなサービスインスタンスにルーティングします(TraefikノードはRed Hat EnterpriseのDockerで実行されていますが、これは私の問題とは無関係です)。スループット、CPU、メモリの観点から見ると、これら3つのネットワークコンポーネントは、十分な容量を確保して、要求とトラフィックの量を処理する能力を超えています。

ただし、特に高負荷時にクライアントが行うHTTP(S)リクエストで1000ミリ秒の遅延が頻繁に発生することに気付きました。次の根本原因まで問題を追跡しました。

  • 高負荷時に、F5 "クライアント"は高頻度(おそらく100 + /秒)でTraefik "サーバー"ノードへの新しいTCP接続を開始します。
  • これらの接続は、HTTP応答が返されると、Traefikの「サーバー」側で終了します。
  • 閉じられた各接続は、Traefikホスト上で60秒間TIME_WAIT状態のままです。
  • F5が新しい接続を開始すると、エフェメラルポート範囲から使用可能なポートがランダムに選択されます。
  • 時々(多くの場合、高負荷時に)、同じ送信元IP +ポート、宛先IP +ポートの組み合わせを使用して、TIME_WAIT状態のTraefikにすでに接続があります。これが発生すると、TraefikホストのTCPスタック(?)は最初のSYNパケットを無視します。注: RFC 6056 は、これをinstance-idsの衝突と呼びます。
  • 1000ミリ秒後、再送信タイムアウト(RTO)メカニズムがF5を開始し、SYNパケットを再送信します。今回は、Traefikホストが接続を受け入れ、要求を正しく完了します。

明らかに、これらの1000ミリ秒の遅延は絶対に許容できません。したがって、これまでに次のソリューションを検討しました。

  1. F5のRTOを減らして、再送信を高速化します。 200msまで。
  2. Net.ipv4.tcp_fin_timeoutを減らして閉じますabandoned TIME_WAIT より高速な接続。
    更新:これは放棄された接続にのみ適用されます反対側では、FINが返されない場合。 TIME_WAIT状態の接続には影響しません。
  3. Net.ipv4.tcp_tw_reuseを有効にする:着信接続には役に立たない。
  4. Net.ipv4.tcp_tw_recycleを有効にします。クライアントがランダム化されたTCPタイムスタンプを送信する場合、AFAIKは矛盾します。この機能がLinuxから削除されたかどうかに関する矛盾する情報(経験的証拠を含む)。また、一般的に混乱しないことをお勧めします。
  5. ソースIPを追加するか、Traefikが複数のポートでリッスンするようにして、IP /ポートタプルの順列の数を増やします。

#1はバンドエイドなので破棄します。遅延はまだ発生していますが、少し目立ちません。いずれにしても、#3は何の効果もありません。#4はシステムを機能させない可能性があります。葉っぱ #2 と#5。

しかし、私が何十もの投稿や技術記事を読んだ後に私が学んだことを基にすると、どちらも最終的にはこれらの「衝突」の可能性を(== --- ==)減らすだけです。送信側F5が最終的に(疑似)ランダムに選択するのは、fin_timeout設定がどれだけ短いかに関係なく、ターゲットのTraefikホストでTIME_WAIT状態にまだ存在しているエフェメラルポート、ソースIP、およびターゲットポートの組み合わせをランダムに選択するためです(とにかく数秒の範囲に留まる必要があります)?衝突の可能性を減らすだけでなく、なくすことはしません。

私のすべての調査の後、そして巨大なWebアプリケーションの時代に、この問題がWeb(および利用可能な解決策)でこれ以上議論されていないことに本当に驚いています。衝突の発生をゼロに近づけるTCPの土地により良い、より体系的な解決策があるかどうかについてのあなたの考えと考えを本当に感謝します。古い接続がTIME_WAIT状態であっても、Traefikホストが新しい接続をすぐに受け入れることができるTCP構成に沿って考えています。しかし、今のところ、それを見つけることはできません。

ランダムな考えとポイント:

  • 現時点では、社内のさまざまなアプリケーションを変更して、実行時間の長いHTTP(S)接続を使用して、1秒あたりのリクエスト/接続の数を減らすことはできません。
  • F5とTraefikのネットワークアーキテクチャは議論の余地があり、変更できません。
  • 私は最近、Windowsクライアントでの一時的なポート選択を調査しました。そのアルゴリズムはランダムではなく、シーケンシャルなようです。ポートが再利用されるまでの時間を最大化し、セキュリティを低下させます。
  • それ以外はアイドル状態のシステムでの負荷テスト中に、1秒あたり最大100のHTTPリクエスト/接続を生成しました。 F5が60kを超える一時ポートを使用するように構成されているにもかかわらず、最初の衝突は数秒後(たとえば、合計2000リクエスト前)にすでに発生しました。これは、ポートIDアルゴリズムの疑似ランダムな性質によるものだと思います。これは、インスタンスとIDの衝突を回避するというかなり貧弱な仕事をしているようです。
  • TraefikホストがSYNパケットの再送信時にTCP接続を受け入れるという事実は、おそらくTCPの機能です。 _実装。 RFC6056はTIME_WAIT assassinationについて語っており、これに関連している可能性があります。

更新:Per The Star Experiment 、net.ipv4.tcp_fin_timeout設定はTIME_WAIT状態には影響せず、FIN_WAIT_2状態にのみ影響します。そして Samir Jafferali に従って、Linuxシステム(Red Hat Linuxを含む)では、TIME_WAIT期間はソースコードにハードコードされており、構成できません。ソースによるとBSDでは、それは設定可能ですが、私はこれを確認していません。

8
Christoph

私たちのデータセンターでは、BigIPハードウェア上で動作するF5が動作しますassingleingress point HTTPSリクエストに対してさまざまなクライアントマシンから全国のオフィスの場所

この単一のポイント(フロントエンド)が接続をバッ​​クエンドに渡すときに単一のままである場合、なぜ問題が発生するのでしょうか。特に接続の強度が「おそらく1秒あたり100以上」の場合。

あなたの設定は基本的に、カーディナリティが高い1つのセットを、カーディナリティが大幅に低い別のセットに絞り込んでいます。

最終的には、これらの「衝突」の可能性を減らすだけです

これは、パケット交換ネットワークがどのように機能するかに基づいて行われます。たとえば、イーサネットレベルでは衝突も発生します。ランダム性は避けられず、TCP/IPはそれを処理します。 IPプロトコル自体は、実際にはLANを考慮せずに構築されています(ただし、そこでもうまく機能します)。

したがって、「ソースIPを追加するか、Traefikを複数のポートでリッスンさせる」というのは、かなり合理的な方法です。

4
poige

さらにIPアドレスを追加するのが最も簡単な方法だと思いますが、外部リクエストごとに新しいIPアドレスを作成する代わりに、F5ノードとTraefikノード間のTCP接続の再利用を検討することを検討しましたか?

F5がそれをどのようにサポートするかはわかりませんが、F5ノードとTraefikノード間でhttp2に切り替えるだけの簡単なものでしょう。 https://developers.google.com/web/fundamentals/performance/http2#one_connection_per_Origin を参照してください

3
Pedro Perez

結局のところwas結局のところ、この問題に対する非常に単純な解決策です。これは、Traefikベンダーとしばらくの間作業した後でわかったものです。また、DockerでTraefikを実行しているという事実doesが重要であることもわかります。問題と解決策は私たちの設定に非常に固有ですが、他の人が同じ問題に遭遇した場合に備えて、ここで文書化したいと思います。それにもかかわらず、インスタンスIDの衝突が実際の問題であるため、これはnotを無効にします。

要するに、すべてのTraefikインスタンスは、Docker Swarmクラスターで実行されているホスト制約付きコンテナー(つまり、特定のホストに関連付けられている)として構成されます。 Traefikインスタンスは、Docker Swarm参加者ではないF5から到達可能になるように、ホストレベルでポートを公開する必要があります。これらの公開されたポートは、ingressモードで構成されていましたが、これは不要なだけでなく(Docker Swarm入力ネットワークを介してトラフィックをルーティングする必要もありません)、ドロップ/無視されたSYNパケットの原因。ポートモードをHostに切り替えると、遅延はなくなりました。

前:

  ports:
  - target: 8080
    published: 8080
    protocol: tcp
    mode: ingress

後:

  ports:
  - target: 8080
    published: 8080
    protocol: tcp
    mode: Host
2
Christoph