У меня есть клиент-серверное приложение (Java), которое я перевожу с Solaris на RH Linux.
с тех пор, как я начал работать с ним в RH, я заметил некоторые проблемы, связанные с задержкой.
Мне удалось выделить проблему, которая выглядит так:
- клиент отправляет 5 сообщений (по 32 байта каждое) подряд (одна и та же временная метка приложения) на сервер.
- эхо-сообщения сервера.
- клиент получает ответы и печатает время приема-передачи для каждого сообщения.
в Solaris все хорошо: я получаю ВСЕ 5 ответов одновременно, примерно через 80 мс после отправки оригинальных сообщений (клиент и сервер находятся на расстоянии нескольких тысяч миль друг от друга: мой RTT пинга равен 80 мс, все нормально).
в RH первые 3 сообщения отражаются нормально (они приходят через 80 мс после отправки), однако следующие 2 сообщения приходят через 80 мс (итого 160 мс RTT).
картина всегда одна и та же. явно выглядело как проблема TCP.
на моем солярисе я ранее настроил стек tcp с двумя конкретными опциями:
- отключить алгоритм Nagle в глобальном масштабе
- установить tcp_deferred_acks_max в 0
на RH невозможно отключить Nagle глобально, но я отключил его на всех сокетах моих приложений (TCP_NODELAY).
поэтому я начал играть с tcpdump (на сервере) и сравнил оба вывода:
SOLARIS
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
REDHAT
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 и ACK TCP Dup в tcpdump, затем проблема полностью исчезла для всех следующих групп из 5 сообщений.
Мне не кажется, что это очень чистое и / или общее решение. Мне бы очень хотелось воспроизвести одинаковые условия в обеих ОС.
Я буду продолжать исследования, но любая помощь от гуру TCP будет принята с благодарностью!