Solaris から RH Linux に移行するクライアント/サーバー アプリ (Java) があります。RH での実行を開始してから、レイテンシーに関連するいくつかの問題に気付きました。次のような問題を切り分けることができました。
- クライアントは 5 つのメッセージ (各 32 バイト) を連続して (同じアプリケーションのタイムスタンプで) サーバーに送信します。
- サーバーはメッセージをエコーします。
- クライアントは応答を受信し、各メッセージの往復時間を出力します。
Solaris では、すべて問題ありません。元のメッセージを送信してから約 80 ミリ秒で、同時に 5 つの応答すべてを受け取ります (クライアントとサーバーは互いに数千マイル離れています。私の ping RTT は 80 ミリ秒で、すべて正常です)。
RH では、最初の 3 つのメッセージは正常にエコーされます (送信後 80 ミリ秒で到着します) が、次の 2 つは 80 ミリ秒後に到着します (合計 160 ミリ秒の RTT)。
パターンは常に同じです。明らかにTCPの問題のように見えました。
私のsolarisボックスでは、以前に2つの特定のオプションを使用してtcpスタックを構成していました。
- nagle アルゴリズムをグローバルに無効にする
- tcp_deferred_acks_max を 0 に設定します
RH では、nagle をグローバルに無効にすることはできませんが、すべてのアプリのソケット (TCP_NODELAY) で無効にしました。
そこで、(サーバー マシン上で) tcpdump を使い始め、両方の出力を比較しました。
ソラリス:
22 2.085645 client server TCP 56150 > 6006 [PSH, ACK] Seq=111 Ack=106 Win=66672 Len=22 "MSG_1 RCV"
23 2.085680 server client TCP 6006 > 56150 [ACK] Seq=106 Ack=133 Win=50400 Len=0
24 2.085908 client server TCP 56150 > 6006 [PSH, ACK] Seq=133 Ack=106 Win=66672 Len=22 "MSG_2 RCV"
25 2.085925 server client TCP 6006 > 56150 [ACK] Seq=106 Ack=155 Win=50400 Len=0
26 2.086175 client server TCP 56150 > 6006 [PSH, ACK] Seq=155 Ack=106 Win=66672 Len=22 "MSG_3 RCV"
27 2.086192 server client TCP 6006 > 56150 [ACK] Seq=106 Ack=177 Win=50400 Len=0
28 2.086243 server client TCP 6006 > 56150 [PSH, ACK] Seq=106 Ack=177 Win=50400 Len=21 "MSG_1 ECHO"
29 2.086440 client server TCP 56150 > 6006 [PSH, ACK] Seq=177 Ack=106 Win=66672 Len=22 "MSG_4 RCV"
30 2.086454 server client TCP 6006 > 56150 [ACK] Seq=127 Ack=199 Win=50400 Len=0
31 2.086659 server client TCP 6006 > 56150 [PSH, ACK] Seq=127 Ack=199 Win=50400 Len=21 "MSG_2 ECHO"
32 2.086708 client server TCP 56150 > 6006 [PSH, ACK] Seq=199 Ack=106 Win=66672 Len=22 "MSG_5 RCV"
33 2.086721 server client TCP 6006 > 56150 [ACK] Seq=148 Ack=221 Win=50400 Len=0
34 2.086947 server client TCP 6006 > 56150 [PSH, ACK] Seq=148 Ack=221 Win=50400 Len=21 "MSG_3 ECHO"
35 2.087196 server client TCP 6006 > 56150 [PSH, ACK] Seq=169 Ack=221 Win=50400 Len=21 "MSG_4 ECHO"
36 2.087500 server client TCP 6006 > 56150 [PSH, ACK] Seq=190 Ack=221 Win=50400 Len=21 "MSG_5 ECHO"
37 2.165390 client server TCP 56150 > 6006 [ACK] Seq=221 Ack=148 Win=66632 Len=0
38 2.166314 client server TCP 56150 > 6006 [ACK] Seq=221 Ack=190 Win=66588 Len=0
39 2.364135 client server TCP 56150 > 6006 [ACK] Seq=221 Ack=211 Win=66568 Len=0
レッドハット:
17 2.081163 client server TCP 55879 > 6006 [PSH, ACK] Seq=111 Ack=106 Win=66672 Len=22 "MSG_1 RCV"
18 2.081178 server client TCP 6006 > 55879 [ACK] Seq=106 Ack=133 Win=5888 Len=0
19 2.081297 server client TCP 6006 > 55879 [PSH, ACK] Seq=106 Ack=133 Win=5888 Len=21 "MSG_1 ECHO"
20 2.081711 client server TCP 55879 > 6006 [PSH, ACK] Seq=133 Ack=106 Win=66672 Len=22 "MSG_2 RCV"
21 2.081761 client server TCP 55879 > 6006 [PSH, ACK] Seq=155 Ack=106 Win=66672 Len=22 "MSG_3 RCV"
22 2.081846 server client TCP 6006 > 55879 [PSH, ACK] Seq=127 Ack=177 Win=5888 Len=21 "MSG_2 ECHO"
23 2.081995 server client TCP 6006 > 55879 [PSH, ACK] Seq=148 Ack=177 Win=5888 Len=21 "MSG_3 ECHO"
24 2.082011 client server TCP 55879 > 6006 [PSH, ACK] Seq=177 Ack=106 Win=66672 Len=22 "MSG_4 RCV"
25 2.082362 client server TCP 55879 > 6006 [PSH, ACK] Seq=199 Ack=106 Win=66672 Len=22 "MSG_5 RCV"
26 2.082377 server client TCP 6006 > 55879 [ACK] Seq=169 Ack=221 Win=5888 Len=0
27 2.171003 client server TCP 55879 > 6006 [ACK] Seq=221 Ack=148 Win=66632 Len=0
28 2.171019 server client TCP 6006 > 55879 [PSH, ACK] Seq=169 Ack=221 Win=5888 Len=42 "MSG_4 ECHO + MSG_5 ECHO"
29 2.257498 client server TCP 55879 > 6006 [ACK] Seq=221 Ack=211 Win=66568 Len=0
そのため、RH で正常に動作していないことを確認しました。パケット 28 の送信が遅すぎます。サーバーは、何かを行う前にパケット 27 の ACK を待っているようです。
私にはそれが最も可能性の高い理由のようです...
次に、Solaris と RH のダンプで「Win」パラメータが異なることに気付きました。Solaris では 50400、RH では 5888 のみです。それは別のヒントです...
スライド ウィンドウとバッファ ウィンドウに関するドキュメントを読み、ソケットの Java で rcvBuffer と sendBuffer をいじりましたが、この 5888 値を他の値に変更することはできませんでした (毎回 tcpdump で直接確認しました)。
誰もこれを行う方法を知っていますか? 場合によってはバイパスする必要があるかもしれない「自動ネゴシエーション」などがあるため、決定的な情報を得るのに苦労しています...
最終的に、RH で「tcp_slow_start_after_idle」パラメーターを 0 に設定することで、最初の問題を部分的にしか取り除くことができませんでしたが、「win」パラメーターはまったく変更されませんでした。5 つのメッセージの最初の 4 つのグループに同じ問題があり、tcpdump で TCP 再送信と TCP Dup ACK が発生し、その後の 5 つのメッセージのすべてのグループで問題が完全に解消されました。
私にとっては、非常にクリーンで一般的なソリューションのようには思えません。両方の OS でまったく同じ条件を再現したいと思っています。
私は調査を続けますが、TCP の専門家からの助けをいただければ幸いです。