Чрезвычайно высокая задержка, когда сеть загружается, TCP, libevent

В нашем проекте онлайн-игры на основе C/S мы используем TCP для передачи по сети. Мы включаем Libevent, используем bufferevent для каждого соединения для автоматической обработки с помощью сетевого ввода-вывода.

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

  • средняя загрузка ЦП снизилась (повторение 0%-60%-0%-60%, что-то ждет?)
  • чистый трафик уменьшился (nethogs)
  • клиенты, подключенные к серверу, еще живы (netstat & tcpdump)

Похоже, что-то волшебным образом замедлило всю систему, но новое соединение с сервером отреагировало вовремя.

Когда я изменил протокол на UDP, он хорошо работает в той же ситуации: нет явных задержек, система работает быстро. Чистый трафик составляет около 3 м / с.

Проект выполняется в Интранете. Я также проверил максимальную скорость загрузки, около 18M/S.

Я изучил часть заголовочных файлов Libevent и ducumentations, попытался установить ограничение скорости для всех подключений. Он сделал некоторые улучшения, но не полностью решил проблему, хотя я пробовал несколько разных конфигураций. Вот мои параметры: read_rate 163840, read_burst 163840, write_rate 163840, write_burst 163840, tick_len 500ms.

Спасибо за помощь!

1 ответ

Решение

TCP = протокол управления передачей. Он реагирует на потерю пакетов, повторно передавая неподтвержденные пакеты после задержки. В случае повторной потери, она будет экспоненциально отступать. Взгляните на этот снимок сети при попытке открыть соединение с хостом, который не отвечает:

введите описание изображения здесь

Он отправляет первоначальный SYN, а затем, не получив подтверждения в течение 1 с, пытается снова. Не получив подтверждение, он отправляет еще через ~2 с, затем ~4 с, затем ~8 с и так далее. Таким образом, вы можете видеть, что вы можете получить серьезную задержку перед лицом повторной потери пакетов.

Поскольку вы сказали, что намеренно напрягли сеть и что использование ЦП является непоследовательным, одно из возможных объяснений состоит в том, что TCP ожидает повторной передачи потерянных пакетов.

Лучший способ увидеть, что происходит, - получить в сети информацию о том, что фактически передается. Если ваши хосты подключены к одному коммутатору, вы можете "связать" интересующий вас порт с портом другого хоста, где вы можете сделать перехват.

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

Я бы предложил установить wireshark для анализа захвата сети (что вы можете сделать в реальном времени, используя wireshark, чтобы сделать захват). Каждый раз, когда вы работаете с сетевой системой, я бы порекомендовал использовать wireshark, чтобы вы могли лучше понять, что на самом деле происходит в сети. Первый фильтр, который я бы предложил вам использовать, это tcp.analysis.flags который покажет вам пакеты, наводящие на мысль о проблемах.

Я также предложил бы сначала отключить ограничение скорости, чтобы попытаться увидеть, что происходит (ограничение скорости - это еще одна причина не отправлять пакеты, что, вероятно, усложнит диагностику происходящего). Кроме того, 500 мс может быть длинным tick_len в зависимости от того, как работает ваша игра. Если ваша пакетная конфигурация позволяет использовать скорость в 100 мс, вам придется ждать 400 мс, прежде чем вы сможете продолжить передачу. График ввода-вывода - очень полезная функция Wireshark в этом отношении. Это может помочь вам увидеть скорость передачи, хотя интервал между тиками по умолчанию и единица измерения не очень полезны в этом отношении. Вот пример пакетного потока, скорость которого ограничена 200 Мбит / с:

введите описание изображения здесь

Обратите внимание, что интервал между тиками равен 1 мс, а единица измерения - бит / тик, что делает вершину графика 1 Гбит / с, скорость рассматриваемого интерфейса.

Другие вопросы по тегам