Как минимизировать потерю пакетов UDP - PullRequest
5 голосов
/ 25 ноября 2011

Я получаю ~ 3000 пакетов UDP в секунду, каждый из которых имеет размер ~ 200 байт. Я написал приложение Java, которое слушает эти пакеты UDP и просто записывает данные в файл. Затем сервер отправляет 15000 сообщений с ранее указанной скоростью. После записи в файл он содержит всего ~ 3500 сообщений. Используя wireshark, я подтвердил, что все 15000 сообщений были получены моим сетевым интерфейсом. После этого я попытался изменить размер буфера сокета (который изначально составлял 8496 байт):

(java.net.MulticastSocket)socket.setReceiveBufferSize(32*1024);

Это изменение увеличило количество сохраненных сообщений до ~ 8000. Я продолжал увеличивать размер буфера до 1 МБ. После этого количество сохраненных сообщений достигло ~ 14400. Увеличение размера буфера до больших значений не приведет к увеличению количества сохраненных сообщений. Я думаю, что достиг максимально допустимого размера буфера. Тем не менее мне нужно перехватить все 15000 сообщений, которые были получены моим сетевым интерфейсом.

Любая помощь будет оценена. Заранее спасибо.

Ответы [ 5 ]

5 голосов
/ 25 ноября 2011

Пахнет как ошибка, скорее всего, в вашем коде.Если UDP-пакеты доставляются по сети, они будут поставлены в очередь для локальной доставки, как вы видели в Wireshark.Возможно, ваша программа просто не делает своевременного прогресса при чтении из сокета - есть ли выделенный поток для этой задачи?

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

В любом случае вы, похоже, очень беспокоитесь о потерянных пакетах.По замыслу UDP не является надежным транспортом.Если потеря этих многоадресных пакетов является проблемой для вашей системы (а не просто загадкой, которую вы хотели бы решить из соображений производительности), то проект системы неправильный.

1 голос
/ 25 ноября 2011

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

1 голос
/ 25 ноября 2011

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

Однако невозможно гарантировать, что 100% пакетов будет получено по UDP, без возможности запрашивать повторную отправку пакетов (что TCP делает для вас)

0 голосов
/ 17 апреля 2019

Это ответ только для Windows, но следующие изменения в свойствах карты сетевого контроллера привели к разнице в DRAMATIC потери пакетов для нашего варианта использования.

Мы потребляем около 200 Мбит / с данных UDP и испытываем значительную потерю пакетов при умеренной нагрузке на сервер.

Используемая сетевая карта - это карта Asus ROG Aerion 10G , но я ожидаю, что большинство высокопроизводительных сетевых контроллеров будут иметь аналогичные свойства. Вы можете получить к ним доступ через Диспетчер устройств-> Сетевая карта-> Правой кнопкой мыши-> Свойства-> Дополнительные параметры .

1. Увеличьте количество приемных буферов:

Значение по умолчанию было 512; мы могли бы увеличить его до 1024. В нашем случае более высокие настройки были приняты, но сетевая карта отключается после того, как мы превысим 1024. Наличие большего количества доступных буферов на уровне сетевой карты дает системе больше терпимости к задержке при передаче данные из буферов сетевой карты в буферы сокетов, где наши приложения, наконец, смогут читать данные.

2. Установите для параметра «Скорость прерывания» значение «Выкл.»:

Если я правильно понял, модерация прерываний объединяет несколько уведомлений о «заполнении буфера» (через прерывания) в одно уведомление. Таким образом, ЦП будет прерываться реже и извлекать несколько буферов во время каждого прерывания. Это уменьшает загрузку ЦП, но увеличивает вероятность того, что готовый буфер будет перезаписан перед извлечением, если прерывание будет обработано поздно.

Кроме того, мы увеличили размер буфера сокета (как уже сделал OP), а также включили Циклическая буферизация на уровне сокета, как предложено Len Holgate в комментарии, Также следует увеличить допуск к задержке при обработке буферов сокетов.

0 голосов
/ 13 февраля 2014

Размер буфера приема настраивается на уровне ОС.

Например, в системе Linux, sysctl -w net.core.rmem_max=26214400 как в этой статье https://access.redhat.com/site/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/jgroups-perf-udpbuffer.html

...