У меня есть клиент-серверное приложение (Java), которое я переношу с Solaris на RH Linux. так как я начал запускать его в RH, я заметил некоторые проблемы, связанные с задержкой. Мне удалось выделить проблему, которая выглядит так:
- клиент отправляет 5 сообщений (каждое по 32 байта) подряд (с той же отметкой времени приложения) на сервер.
- сервер повторяет сообщения.
- клиент получает ответы и печатает время приема-передачи для каждого сообщения.
в Solaris все хорошо: я получаю ВСЕ 5 ответов одновременно, примерно через 80 мс после отправки исходных сообщений (клиент и сервер находятся на расстоянии нескольких тысяч миль друг от друга: мой пинг RTT составляет 80 мс, все нормально).
в RH первые 3 сообщения отображаются нормально (они поступают через 80 мс после отправки), однако следующие 2 прибывают через 80 мс (всего 160 мс RTT).
схема всегда одна и та же. явно выглядело как проблема TCP.
в моем боксе Solaris я ранее настроил стек tcp с двумя конкретными параметрами:
- глобально отключить алгоритм Нэгла
- установите 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 отправлен СЛИШКОМ ПОЗДНО, похоже, что сервер ждет ACK пакета 27, прежде чем что-либо делать.
мне кажется это самая вероятная причина...
потом я понял, что параметры "Win" разные на дампах Solaris и RH: 50400 на Solaris, только 5888 на RH. это еще одна подсказка...
Я прочитал документ об окне слайдов и окне буфера и поиграл с rcvBuffer и sendBuffer в java на своих сокетах, но мне так и не удалось изменить это значение 5888 на что-либо другое (каждый раз я проверял непосредственно с помощью tcpdump).
кто-нибудь знает, как это сделать? Мне трудно получить точную информацию, так как в некоторых случаях есть «автосогласование», которое мне может потребоваться обойти, и т. д.
В конце концов мне удалось лишь частично избавиться от моей первоначальной проблемы, установив для параметра «tcp_slow_start_after_idle» значение 0 на RH, но это совсем не изменило параметр «win». та же проблема была для первых 4 групп из 5 сообщений, с повторной передачей TCP и TCP Dup ACK в tcpdump, затем проблема полностью исчезла для всех следующих групп из 5 сообщений.
Мне это не кажется очень чистым и/или общим решением. Я бы очень хотел воспроизвести одинаковые условия в обеих ОС.
Я продолжу исследования, но буду очень признателен за любую помощь гуру TCP!