Pull to refresh

Comments 25

Спасибо, интересно было почитать! Не очень только уловил отчего же в самом начале не вылезла корреляции проблемы с определенными серверами сервиса А, где, собственно, и не была включена tcp_window_scaling?

Спасибо!

В первую очередь начали исследовать сервисы, сервис А редко изменяется, а вот сервис Б обновляется довольно часто - поэтому сначала пошли в ту сторону. В сторону "железа" не смотрели до последнего, потому что изменения в конфигурации происходят крайне редко и по истории изменений никаких обновлений не было. Также в момент проблемы у нас было довольно много энтропии в системе: переход в кубер, постоянное обновления сервисов и т.п.

Когда я рефлексировал на тему того как можно было быстрее выйти на исходную проблему у меня пришло в голову только одно - правильно ставить эксперименты и более пристально проверять гипотезы.

Захватывающая история! А сколько по времени заняло решение проблемы?

Спасибо! Суммарно ушло порядка 2 недель с учетом походов по ложным следам. Когда плотно сели за исследование, проблему нашли где-то за 3 дня.

Правильный вывод то так и не сделан - сервера должны разворачиваться тулами с заранее определённой конфигурацией. Никакой ручной конфигурации, тем более на prod серверах.

Конфигурирование через тулы - это тоже ручное действие (имею ввиду написание самого конфига). У нас все сервера наливаются через автоматику и ручной кастомизации на серверах не происходит (только на момент экспериментов, с принудительном откатом до оригинальной конфигурации). В данном случае опция была прописана некорректно в самом конфигурационном файле, который разливался автоматикой на сервера.

P.S. Замечу, что конфигурация серверов не однородна по ряду причин, поэтому на части серверов были одни настройки, на части другие. После того как нашли проблему прошли по всем серверам и актуализировали опцию

Автоматика была когда то давно неверно настроена. Это и обнаружили

Не раскрыто кто садовник и доколе

Личность садовника не так важна :)

Про проблему - имела место быть, сейчас все работает штатно.

В давнее время сталкивался с проблемой медленной работы сети из-за фуркции масштабирования окна. Правда обстоятельства были несколько другие: масштабирование массово пошло на клиенты, начиная с Win7 (точнее, Vista), для которых MS переписала стек TCP/IP, а в Win2K3 (под которым тогда были основные серверы) старый стек имел ошибку, мешавшую ему нормально работать. Обновление MS выпустила оперативно, но пока его распространили, обходным решением было отключать масштабирование окна TCP на проблемных клиентах. Благо сеть была гигабитной локалкой, больших задержек в ней не было, доступ был все больше для чтения с диска/записи на диск (файл-сервер чаще всего), а диски были не столь скоростными, потому ограничение размера окна на реальную работу не влияло.
Так что мысль начет окна передачи была бы одной из первых (где-то после проверки сети на потрею пакетов — скорость TCP к этому чувствительна).

Если проблема была в отключенном tcp_window_scaling, то почему вы не увидели того, что при тестировании через iperf скорость также не растет?

Возможно, iperf был многопоточным? Суммарно много медленных потоков показывают хорошую картинку — идём дальше...

Вообще такое поведение больше похоже на небольшое начальное окно - при отправке небольшого пакета данных окно не успевает вырасти, а при проверке через iperf TCP-сессия держится дольше и окно увеличивается достаточно.

Этот момент у меня не получилось до конца раскопать, хотя я совершал несколько заходов. Возможно кто-то сможет подсказать здесь. Ниже приведу вывод iperf для разных конфигурация scaling. Как я писал, из того что получилось заметить, что iperf начинает подсвечивать наличие проблемы на географически удаленных ДЦ.

Запуск iperf3 на серверах в билзлежащих ДЦ c tcp_window_scaling = 1

[hostA~]# net.ipv4.tcp_window_scaling = 1 
[hostA~]# iperf3 -c hostB -V 
....
TCP MSS: 1468 (default) 
[  4] local hostA port 38440 connected to hostB port 5201 Starting Test: protocol: TCP, 1 streams, 131072 byte blocks, omitting 0 seconds, 10 second test 
Test Complete. Summary Results: 
[ ID] Interval           Transfer     Bandwidth       Retr 
[  4] 0.00-10.00  sec  1022 MBytes   857 Mbits/sec    0             sender 
[  4] 0.00-10.00  sec  1019 MBytes   854 Mbits/sec                  receiver CPU Utilization: local/sender 5.1% (0.2%u/4.9%s), remote/receiver 6.6% (0.5%u/6.1%s)

Запуск iperf3 на серверах в билзлежащих ДЦ c tcp_window_scaling = 0

[hostA ~]# sysctl  net.ipv4.tcp_window_scaling=0 
net.ipv4.tcp_window_scaling = 0 
[hostA ~]# iperf3 -c hostB -V 
...
TCP MSS: 1468 (default) [
[ 4] local hostA port 52814 connected to hostB port 5201 Starting Test: protocol: TCP, 1 streams, 131072 byte blocks, omitting 0 seconds, 10 second test
Test Complete. Summary Results: 
[ ID] Interval           Transfer     Bandwidth       Retr 
[  4]   0.00-10.00  sec   913 MBytes   766 Mbits/sec    0             sender 
[  4]   0.00-10.00  sec   913 MBytes   766 Mbits/sec                  receiver

Как видно, незначительная деградация наблюдается, но цифры не бьются с реальной скоростью передачи.

У меня два предположения:

  1. iperf3 в обход системных настроек и все-таки включает tcp window scaling

  2. iperf3 выставляет начальное значение окна, достаточное чтобы прокачать гигабитный линк даже без scaling

Это можно проверить если включить дебаг в iperf3 (он покажет какое окно выставляет) и/или посмотреть в дампе что там на самом деле улетает в сеть.

Нашел еще такое на просторах:

There are no per-process APIs for sockets at all, just per-socket APIs and global kernel configurations.

But you don't need to modify the scale settings directly. You just need to set the socket receive buffer size you want prior to connecting. Then the appropriate window scale is negotiated during the connect handshake. If you want mo window scaling! make sure your socket receive buffer is < 64k before connecting. In the case of accepted sockets, that is set on the listening socket.

Это тоже можно увидеть в выхлопе дебага айперфа и косвенно в дампе.

Спасибо большое за идеи! Постараюсь в ближайшее время проверить эти гипотезы.

Простите за возможно глупый вопрос, я совсем-совсем далек от этой области. Но все-таки спрошу:


131072 byte blocks — это размер блока, который отправляет iperf? По умолчанию iperf работает ведь не с мегабайтными блоками? Может, имеет значение: блок всего вдвое больше "окна" в 64 Кб или в 20 раз?

Интересно как вы умудрились её выключить - если она уже лет 20 как включена по умолчанию...

Вот этот момент похоже останется тайной, покрытой мраком

Простая ошибка, когда таймаут обработки запускается сразу после того, как данные попали в процедуру отправки, а не реально были переданы. Нужно либо запускать таймаут после того, как пакет полностью уйдёт (типа flush перед взведением) или учитывать время, необходимое для передачи (или что-то ещё - всё индивидуально). Если я правильно понял (поправьте, если нет), вы подковырнули настройки передачи, чтобы время отправки опустить в рамки погрешности.

Не до конца уловил идею про "момент" запуска таймаута. В нашем случае таймаут ограничивает разрешенное время передачи всего пакета (например, на случай тупящей сети) - если этого не сделать, сервис начнет деградировать в производительности (уменьшится rps) потому что будет стоять в отправку данных.

Если я правильно понял (поправьте, если нет), вы подковырнули настройки передачи, чтобы время отправки опустить в рамки погрешности. - в общем правильно. Подтюнили настройки TCP, чтобы "разогнать" пропускную способность.

спасибо интересно! не знал о таком

До меня так и не дошло, почему проблема проявлялась не на всех серверах с Б, хотя причиной были серверы без Б с А.

На самом деле проблема проявлялась на всех серверах с сервисом Б, но в момент начала исследования это было не очевидно, поскольку тайматили произвольные пары A и Б и таймауты происходили не массово (так как больших сообщений много меньше чем маленьких).

Sign up to leave a comment.