миграция Solaris на RH: проблема с задержкой в ​​сети, размер окна tcp и другие параметры tcp

У меня есть клиент-серверное приложение (Java), которое я переношу с Solaris на RH Linux. так как я начал запускать его в RH, я заметил некоторые проблемы, связанные с задержкой. Мне удалось выделить проблему, которая выглядит так:

  • клиент отправляет 5 сообщений (каждое по 32 байта) подряд (с той же отметкой времени приложения) на сервер.
  • сервер повторяет сообщения.
  • клиент получает ответы и печатает время приема-передачи для каждого сообщения.

в Solaris все хорошо: я получаю ВСЕ 5 ответов одновременно, примерно через 80 мс после отправки исходных сообщений (клиент и сервер находятся на расстоянии нескольких тысяч миль друг от друга: мой пинг RTT составляет 80 мс, все нормально).

в RH первые 3 сообщения отображаются нормально (они поступают через 80 мс после отправки), однако следующие 2 прибывают через 80 мс (всего 160 мс RTT).

схема всегда одна и та же. явно выглядело как проблема TCP.

в моем боксе Solaris я ранее настроил стек tcp с двумя конкретными параметрами:

  1. глобально отключить алгоритм Нэгла
  2. установите 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!


person Bastien    schedule 08.06.2010    source источник
comment
Трассировка не соответствует вашему описанию. Трассировка redhat занимает меньше времени, чем Solaris, поэтому я не вижу проблем с задержкой. Кроме того, эхо очень быстрое (менее 1 мс), поэтому похоже, что это делается по петле или по локальной сети.   -  person ZZ Coder    schedule 08.06.2010
comment
временные метки на левой стороне нельзя сравнивать (между Solaris и RH), они просто относятся к моменту получения первого пакета (я думаю) ВНУТРИ КАЖДОЙ КОРОБКИ, что может быть практически в любое время. испытания не проводятся одновременно. проблема заключается во времени отклика между приемом MSG и эхо-ответом, измеренном на СЕРВЕРЕ. на Solaris все эхо-сигналы отправляются примерно через 2 мс после получения первого сообщения (2,087500 - 2,085645 = 0,001855) на RH, 4-е и 5-е эхо-сигналы отправляются через 90 мс (2,171019 - 2,081163)   -  person Bastien    schedule 09.06.2010


Ответы (1)


Похоже, алгоритм предотвращения перегрузки срабатывает на коробке Red Hat.

Обратите внимание, что начиная с пакета 26 сервер видел и подтверждал все от клиента, но клиент только подтверждал начальный SYN сервера — он еще не подтверждал никаких сообщений сервера. Обратите также внимание на то, что пакет 27, который снова запускает процесс, — это клиент, подтверждающий получение сервером первых двух партий данных (пакеты 19 и 22).

Какой алгоритм управления перегрузкой использует коробка Red Hat? (/proc/sys/net/ipv4/tcp_congestion_control) — вы можете попробовать переключиться на один из других доступных.

person caf    schedule 08.06.2010
comment
да, это то, о чем я беспокоюсь, я вижу, что многие эхо-сигналы не подтверждаются клиентом, и представьте, что какой-то механизм больше не позволяет серверу отправлять что-либо до тех пор, пока не будут получены ACK: он отправляет 4-е и 5-е эхо только ПОСЛЕ того, как он получил подтверждение. просто не слишком хорошо знаю, что вызывает этот механизм и как на него воздействовать. поэкспериментирую с контролем заторов, в настоящее время он кубический, буду исследовать... спасибо! - person Bastien; 09.06.2010
comment
@Bastien: Попробуйте установить его на reno (просто echo "reno" > /proc/sys/net/ipv4/tcp_congestion_control) и посмотрите, нравится ли вам такое поведение больше. - person caf; 09.06.2010