UDP-пакет отбрасывается ядром Linux

У меня есть сервер, который отправляет UDP-пакеты через многоадресную рассылку, и несколько клиентов, которые перечисляют эти многоадресные пакеты. Каждый пакет имеет фиксированный размер 1040 байт, общий размер данных, отправляемых сервером, составляет 3 ГБ.

Моя среда выглядит следующим образом:

Сеть Ethernet 1 Гбит

40 узлов, 1 отправитель и 39 получателей. Все узлы имеют одинаковую аппаратную конфигурацию: 2 процессора AMD, каждый процессор имеет 2 ядра на частоте 2,6 ГГц

На стороне клиента один поток читает сокет и помещает данные в очередь. Один дополнительный поток извлекает данные из очереди и выполняет небольшую обработку.

Во время многоадресной передачи я распознаю частоту отбрасывания пакетов 30% на стороне узла. Наблюдая статистику netstat –su, я могу сказать, что пропущенные клиентским приложением пакеты равны значению RcvbufErrors из вывода netstat.

Это означает, что все отсутствующие пакеты отбрасываются ОС, потому что буфер сокета был заполнен, но я не понимаю, почему поток захвата не может прочитать буфер вовремя. Во время передачи 2 из 4 ядер используются на 75%, остальные спят. Я единственный, кто использует эти узлы, и я предположил бы, что у машин такого типа нет проблем с пропускной способностью 1 Гбит. Я уже провел некоторую оптимизацию, добавив флаги компилятора g++ для amd cpus, это уменьшило частоту выпадения пакетов до 10%, но, на мой взгляд, все еще слишком высоко.

Конечно, я знаю, что UDP не надежен, у меня есть свой собственный протокол исправления.

У меня нет никаких прав администратора, поэтому я не могу изменить параметры системы.

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

РЕДАКТИРОВАТЬ: я решил эту проблему с помощью 2 потоков, которые читают сокет. Буфер сокета recv все еще иногда переполняется. Но среднее падение составляет менее 1%, поэтому с ним не проблема.

3 ответа

Отслеживание сбрасываний сети в Linux может быть немного сложным, поскольку существует много компонентов, в которых могут происходить отбрасывания пакетов. Они могут возникать на аппаратном уровне, в подсистеме сетевых устройств или на уровне протоколов.

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

Помимо очевидного удаления всего несущественного из цикла чтения сокета:

  • Увеличьте приемный буфер сокета с setsockopt(2),
  • использование recvmmsg(2) если ваше ядро ​​его поддерживает, чтобы уменьшить количество системных вызовов и копий ядра пользователя,
  • Рассмотрим неблокирующий подход с триггером epoll(7),
  • Посмотрите, действительно ли вам нужны потоки, блокировка / синхронизация очень дороги.

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

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