У нас есть инфраструктура, расположенная в нескольких крупных городах по всему миру - Сингапуре, Лондоне и Лос-Анджелесе. RTT между любыми двумя местоположениями превышает> 150 мс.
Недавно мы обновили все серверы для использования каналов со скоростью 1 Гбит / с (со 100 Мбит / с). Мы провели несколько тестов на основе TCP между серверами в разных местах и получили удивительные результаты. Эти результаты полностью повторяемы.
Похоже, что всякий раз, когда отправитель работает на скорости 1 Гбит / с, наша пропускная способность очень сильно страдает из-за длинных ссылок.
Подход к тестированию, применявшийся ранее, чрезвычайно прост - я просто использую cURL для загрузки двоичного файла размером 1 ГБ с целевого сервера (поэтому в приведенном выше случае клиент cURL работает на лондонском сервере и загружается из Лос-Анджелеса, так что LA является отправителем) . Конечно, здесь используется одно TCP-соединение.
Повторяя те же тесты по UDP с помощью iperf, проблема исчезает!
Это прямо указывает на некоторую проблему конфигурации TCP или NIC / порта, на мой взгляд.
Оба сервера работают под управлением CentOS 6.x с кубическим протоколом TCP. Оба имеют максимальные окна отправки и получения TCP 8 МБ, а также временные метки TCP и выборочные подтверждения. Во всех тестовых случаях используется одна и та же конфигурация TCP. Полная конфигурация TCP приведена ниже:
net.core.somaxconn = 128
net.core.xfrm_aevent_etime = 10
net.core.xfrm_aevent_rseqth = 2
net.core.xfrm_larval_drop = 1
net.core.xfrm_acq_expires = 30
net.core.wmem_max = 8388608
net.core.rmem_max = 8388608
net.core.wmem_default = 131072
net.core.rmem_default = 131072
net.core.dev_weight = 64
net.core.netdev_max_backlog = 1000
net.core.message_cost = 5
net.core.message_burst = 10
net.core.optmem_max = 20480
net.core.rps_sock_flow_entries = 0
net.core.netdev_budget = 300
net.core.warnings = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_retrans_collapse = 1
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_tw_buckets = 262144
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_abort_on_overflow = 0
net.ipv4.tcp_stdurg = 0
net.ipv4.tcp_rfc1337 = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_orphan_retries = 0
net.ipv4.tcp_fack = 1
net.ipv4.tcp_reordering = 3
net.ipv4.tcp_ecn = 2
net.ipv4.tcp_dsack = 1
net.ipv4.tcp_mem = 1528512 2038016 3057024
net.ipv4.tcp_wmem = 4096 131072 8388608
net.ipv4.tcp_rmem = 4096 131072 8388608
net.ipv4.tcp_app_win = 31
net.ipv4.tcp_adv_win_scale = 2
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_frto = 2
net.ipv4.tcp_frto_response = 0
net.ipv4.tcp_low_latency = 0
net.ipv4.tcp_no_metrics_save = 0
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_tso_win_divisor = 3
net.ipv4.tcp_congestion_control = cubic
net.ipv4.tcp_abc = 0
net.ipv4.tcp_mtu_probing = 0
net.ipv4.tcp_base_mss = 512
net.ipv4.tcp_workaround_signed_windows = 0
net.ipv4.tcp_dma_copybreak = 4096
net.ipv4.tcp_slow_start_after_idle = 1
net.ipv4.tcp_available_congestion_control = cubic reno
net.ipv4.tcp_allowed_congestion_control = cubic reno
net.ipv4.tcp_max_ssthresh = 0
net.ipv4.tcp_thin_linear_timeouts = 0
net.ipv4.tcp_thin_dupack = 0
Прилагаю пару изображений графиков ввода-вывода WireShark для некоторых тестовых случаев (извините, я пока не могу публиковать изображения напрямую):
Тестовый пример 1 (100 Мбит / с -> 100 Мбит / с) - приятная плавная передача. Никаких потерь при захвате. - http://103.imagebam.com/download/dyNftIGh-1iCFbjfMFvBQw/25498/254976014/100m.png
Тестовый пример 3 (1 Гбит / с -> 100 Мбит / с) - передача votaile, требуется много времени для достижения любой скорости - никогда не приближается к 100 Мбит / с. Пока никаких потерь / ретрансляций при захвате! - http://101.imagebam.com/download/KMYXHrLmN6l0Z4KbUYEZnA/25498/254976007/1g.png
Таким образом, когда используется длинная ссылка с соединением 1 Гбит / с, мы получаем гораздо более низкую пропускную способность TCP, чем при использовании соединения 100 Мбит / с.
Я был бы очень признателен за советы от любых экспертов по TCP!
Спасибо!
ОБНОВЛЕНИЕ (2013-05-29):
Мы решили проблему с помощью тестового примера № 4 выше (отправитель 1 Гбит / с, приемник 1 Гбит / с, через большое RTT). Теперь мы можем достичь ~ 970 Мбит / с в течение нескольких секунд после начала передачи. Проблема появляется быть переключателем, используемым с хостинг-провайдером. Это решило переход к другому.
Однако тестовый пример №3 по большей части остается проблемным. Если у нас есть приемник, работающий на скорости 100 Мбит / с, а отправитель - на 1 Гбит / с, то мы видим примерно 2-3 минуты ожидания, пока получатель достигнет 100 Мбит / с (но теперь он достигает полной скорости, в отличие от раньше). Как только мы уменьшим скорость отправителя до 100 Мбит / с или увеличим скорость получателя до 1 Гбит / с, проблема исчезнет, и мы сможем увеличить скорость до полной за секунду или две.
Основная причина в том, что мы видим убытки, конечно же, очень скоро после начала передачи. Однако это не соответствует моему пониманию того, как работает медленный старт; скорость интерфейса не должна иметь к этому никакого отношения, так как она должна регулироваться ACK от приемника.
Предложения с благодарностью получены, пожалуйста! Если бы я мог предложить здесь награду, я бы сделал это!
Решено! Подробнее см. http://comments.gmane.org/gmane.linux.drivers.e1000.devel/11813
Короче говоря, похоже, что подключенный сервер со скоростью 1 Гбит / с будет отправлять пакеты трафика во время фазы экспоненциального роста TCP, что приведет к затоплению буферов в некоторые промежуточное устройство (кто знает что). Остается два варианта:
1) Свяжитесь с каждым промежуточным оператором сети и попросите их настроить соответствующие буферы для обеспечения моей желаемой пропускной способности и RTT. Вряд ли! 2) Ограничьте всплески.
Я решил ограничить каждый поток TCP для работы со скоростью не более 100 Мбит / с. Число здесь довольно произвольное - я выбрал 100 Мбит / с просто потому, что знал, что предыдущий путь может обрабатывать 100 Мбит / с, и мне больше не нужно для индивидуального потока.
Надеюсь, это поможет кому-то в будущем.
Основная проблема - большая задержка WAN. Будет очень хуже, если он также потеряет случайный пакет.
1, tcp_mem также необходимо установить большим, чтобы выделить больше памяти. Например, установите его как net.ipv4.tcp_mem = 4643328 6191104 9286656
2, вы можете захватывать пакеты через wirehark / tcpdump в течение нескольких минут, а затем анализировать, не были ли потеряны случайные пакеты. Вы также можете загрузить файл пакетов, если хотите.
3, вы можете попробовать настроить другие параметры TCP, например. установите tcp_westwood = 1 и tcp_bic = 1
Повторяя те же тесты по UDP с помощью iperf, проблема исчезает!
Из Лос-Анджелеса (1 Гбит / с) в Лондон (1 Гбит / с): пропускная способность> 250 Мбит / с
Кажется, проблема не исчезла, теряется около 75% ваших пакетов? Если TCP все время переходит в медленный запуск, средняя пропускная способность может быть довольно низкой.
Кстати, у вас есть ориентиры для Лондона до Лос-Анджелеса и от Лондона до Лондона?