2

ソケット フラッシュ動作に関連していると思われる発信メッセージにかなりの遅延がある問題を解決しようとしています。私は、quickfixj イニシエーターからアクセプターへの発信 FIX メッセージのパケット キャプチャを行ってきました。

環境を要約すると、Java イニシエーターは、別のサーバー上のサーバー ソケットへのソケット接続を確立します。どちらのサーバーも Redhat Enterprise Linux 5.10 を実行しています。インターフェイスの netstat からの MSS は 0 です。NIC の MTU はすべて 1500 です (ループバック インターフェイスでは無限だと思います)。アプリケーション側では、メッセージは quickfixj によってバイト配列にエンコードされ、ソケットに書き込まれます。ソケットは、TCP_NODELAY を有効にして構成されています。

ループバック インターフェイスを使用してイニシエーターと同じサーバーでアクセプター (ServerSocket) を実行すると、送信側のレイテンシーがないため、レイテンシーの原因としてアプリケーションを排除できるとほぼ確信しています。これは、ループバック インターフェイスを使用したパケット キャプチャ エントリの例です。

"No.","Time","Source","Destination","Protocol","Length","SendingTime (52)","MsgSeqNum (34)","Destination Port","Info","RelativeTime","Delta","Push"
"0.001606","10:23:29.223638","127.0.0.1","127.0.0.1","FIX","1224","20150527-09:23:29.223","5360","6082","MarketDataSnapshotFullRefresh","0.001606","0.000029","Set"
"0.001800","10:23:29.223832","127.0.0.1","127.0.0.1","FIX","1224","20150527-09:23:29.223","5361","6082","MarketDataSnapshotFullRefresh","0.001800","0.000157","Set"
"0.001823","10:23:29.223855","127.0.0.1","127.0.0.1","FIX","1224","20150527-09:23:29.223","5362","6082","MarketDataSnapshotFullRefresh","0.001823","0.000023","Set"
"0.002105","10:23:29.224137","127.0.0.1","127.0.0.1","FIX","825","20150527-09:23:29.223","5363","6082","MarketDataSnapshotFullRefresh","0.002105","0.000282","Set"
"0.002256","10:23:29.224288","127.0.0.1","127.0.0.1","FIX","2851","20150527-09:23:29.224,20150527-09:23:29.224,20150527-09:23:29.224","5364,5365,5366","6082","MarketDataSnapshotFullRefresh","0.002256","0.000014","Set"
"0.002327","10:23:29.224359","127.0.0.1","127.0.0.1","FIX","825","20150527-09:23:29.224","5367","6082","MarketDataSnapshotFullRefresh","0.002327","0.000071","Set"
"0.287124","10:23:29.509156","127.0.0.1","127.0.0.1","FIX","1079","20150527-09:23:29.508","5368","6082","MarketDataSnapshotFullRefresh","0.287124","0.284785","Set"

主な関心事は、1/ パケット長 (ここでは最大で 2851) にもかかわらず、各パケットに PUSH フラグが設定されていることです。2/ ここで測定しているレイテンシの尺度は、メッセージがエンコードされる前に設定された「送信時間」と、パケット キャプチャ時間の「時間」です。パケット キャプチャは、データを送信しているイニシエーターと同じサーバーで実行されています。10,000 パケットのパケット キャプチャの場合、ループバックを使用する場合、「SendingTime」と「Time」の間に大きな違いはありません。このため、送信遅延の原因であるアプリケーションを排除できると思います。

アクセプターが LAN 上の別のサーバーに移動すると、MTU サイズを超えるパケットの送信遅延が悪化し始めます。これは、キャプチャのスニペットです。

"No.","Time","Source","Destination","Protocol","Length","SendingTime (52)","MsgSeqNum (34)","Destination Port","Info","RelativeTime","Delta","Push"
"68.603270","10:35:18.820635","10.XX.33.115","10.XX.33.112","FIX","1223","20150527-09:35:18.820","842","6082","MarketDataSnapshotFullRefresh","68.603270","0.000183","Set"
"68.603510","10:35:18.820875","10.XX.33.115","10.XX.33.112","FIX","1223","20150527-09:35:18.820","843","6082","MarketDataSnapshotFullRefresh","68.603510","0.000240","Set"
"68.638293","10:35:18.855658","10.XX.33.115","10.XX.33.112","FIX","1514","20150527-09:35:18.821","844","6082","MarketDataSnapshotFullRefresh","68.638293","0.000340","Not set"
"68.638344","10:35:18.855709","10.XX.33.115","10.XX.33.112","FIX","1514","20150527-09:35:18.821","845","6082","MarketDataSnapshotFullRefresh","68.638344","0.000051","Not set"

ここで重要なことは、パケットが MSS (MTU から派生) よりも小さい場合、PUSH フラグが設定され、送信者の遅延がないことです。Nagle のアルゴリズムを無効にすると、これらの小さなパケットに PUSH が設定されるため、これは予想されることです。パケット サイズが MSS (この場合は 1514 のパケット サイズ) よりも大きい場合、パケットがキャプチャされた時間と SendingTime の差は 35 ミリ秒に跳ね上がります。

大きなパケット サイズのメッセージがループバック インターフェイスで 1 ミリ秒未満で送信されたため、この 35 ミリ秒の遅延がメッセージをエンコードするアプリケーションによって引き起こされた可能性は低いと思われます。キャプチャは送信側でも行われるため、MTU セグメンテーションも原因ではないようです。最も可能性の高い理由は、PUSH フラグが設定されていないため (パケットが MSS よりも大きいため)、OS レベルのソケットおよび/または TCP スタックが 35ms 後までフラッシュすることを決定していないことです。他のサーバーのテスト アクセプターは低速なコンシューマーではなく、同じ LAN 上にあるため、ACK はタイムリーです。

> MSSパケットの遅延を送信するこのソケットの原因について、誰かが何かポインタを与えることができますか? 米国の実際の取引相手に対して、この送信者の遅延は 300 ミリ秒にも達します。パケット サイズが MSS より大きい場合、以前の ACKS に関係なくすぐに送信されると思いました (ソケット バッファー サイズを超えない限り)。通常、Netstat は 0 のソケット q と風サイズを示し、起動時からでも、すべての > MSS パケットで問題が発生するようです。これは、ソケットが何らかの理由ですぐにフラッシュしないことを決定しているように見えますが、どのような要因がそれを引き起こす可能性があるかは不明です.

編集: EJP で指摘されているように、Linux にはフラッシュがありません。私が理解しているように、ソケット送信はデータをLinuxカーネルのネットワークバッファに入れます。そして、これらの非プッシュ パケットの場合、カーネルは前のパケットからの ack を待ってから配信しているようです。これは私が期待するものではありません.TCPでは、ソケットバッファがいっぱいになるまでパケットが配信されることを期待しています。

4

1 に答える 1

1

TCP の動作は多くの要因によって異なるため、これは包括的な答えではありません。しかし、この場合、これが私たちが直面した問題の原因でした。

輻輳ウィンドウは、TCP 輻輳制御の実装で、輻輳の兆候 (つまり再送信) を検出しない限り、確認応答なしで送信されるパケットの量を増やすことができます。一般的に言えば、これらが発生すると、輻輳アルゴリズムは輻輳ウィンドウをリセットし、ack を送信する前に送信できるパケットを制限します。これは、パケットが以前のパケットの確認応答を待ってカーネル バッファーに保持されていたため、私たちが目撃した送信者の遅延に現れています。この点に関して、輻輳制御の動作をオーバーライドする TCP_NODELAY、TCP_CORK などのタイプの命令はありません。

私たちの場合、これは他の会場への長い往復時間によってさらに悪化しました。ただ、1日のパケットロスが非常に少ない専用線だったので、輻輳制御が効く原因は再送ではなかった。これにより、輻輳ウィンドウもリセットされますが、パケット損失ではなくアイドル状態を検出します。

"tcp_slow_start_after_idle - BOOLEAN 設定されている場合、RFC2861 の動作を提供し、アイドル期間後に輻輳ウィンドウをタイムアウトさせます。アイドル期間は現在の RTO で定義されます。設定されていない場合、アイドル期間後に輻輳ウィンドウはタイムアウトしません。デフォルト: 1

(これらの問題に直面した場合は、カーネルが現在設定されているもの以外の他の形式の輻輳制御アルゴリズムを調査することもできます)。

于 2015-07-02T13:28:50.557 に答える