«Потерянные» UDP-пакеты (JBoss + DatagramSocket) - PullRequest
5 голосов
/ 23 февраля 2011

Я разрабатываю часть некоторого корпоративного приложения на основе JBoss + EJB.Мой модуль должен обрабатывать огромное количество входящих пакетов UDP.Я провел нагрузочное тестирование, и похоже, что в случае отправки пакетов с интервалом 11 мс все нормально, но в случае интервала 10 мс некоторые пакеты теряются.Это довольно странно, на мой взгляд, но я несколько раз проводил сравнение нагрузочных тестов с интервалом 10/11 мс, и это всегда один и тот же результат (10 мс - некоторые «потерянные» пакеты, 11 мс - все хорошо).

Если эточто-то не так с синхронизацией, я ожидаю, что она также будет видна в случае тестов 11 мс (как минимум один потерянный пакет или хотя бы одно неверное значение счетчика).Так что, если это не из-за синхронизации, то, возможно, DatagramSocket, через который я получаю пакеты, работает не так, как ожидалось.

Я обнаружил, что размер буфера приема (SO_RCVBUF) имеет значение по умолчанию 57344 (возможно, это зависит от сетевых буферов ввода-вывода).Я подозреваю, что, возможно, когда этот буфер заполнится, новые входящие дейтаграммы UDP будут отклонены.Я попытался установить это значение немного выше, но я заметил, что если я преувеличиваю, буфер возвращается к размеру по умолчанию.Если это зависит от нижележащего уровня, как я могу узнать максимальный размер буфера для определенной ОС / сетевой карты на уровне JBoss?

Возможно ли, что это вызвано размером приемного буфера, или, может быть, значение 57344 достаточно велико для обработки большинства случаев?У вас есть опыт работы с такими проблемами?

На моем DatagramSocket не установлено время ожидания.Мои UDP-дейтаграммы содержат около 70 байтов данных (значение без заголовка дейтаграммы).

[отредактировано] Мне нужно использовать UDP, потому что я получаю данные Cisco Netflow - это протокол, используемый сетьюустройства для отправки статистики трафика.Кроме того, я не имею никакого влияния на формат отправленных байтов (например, я не могу добавить счетчики для пакетов и т. Д.).Не ожидается, что все пакеты будут обработаны (некоторые дейтаграммы могут быть потеряны), но я ожидаю, что обработаю большинство пакетов.Во время интервальных тестов 10 мс было потеряно около 30% пакетов.

Маловероятно, что медленная обработка вызывает эту проблему.В настоящее время одноэлементный компонент содержит ссылку на DatagramSocket, вызывающий метод приема в цикле.Когда пакет получен, он передается в очередь и обрабатывается выбранным из пула компонентом без сохранения состояния.Синглтон «Фасад» отвечает только за прием пакетов и передачу их на обработку (он не ожидает завершения обработки).

Заранее спасибо, Петр

Ответы [ 4 ]

5 голосов
/ 23 февраля 2011

UDP не гарантирует доставку, поэтому вы можете настроить параметры, но вы не можете гарантировать, что сообщение будет доставлено, особенно в случае очень больших объемов передачи данных.

Если вам нужно гарантировать доставку, вы должны использовать вместо этого TCP.

Если вам нужно (или вы хотите) использовать UDP, вы можете кодировать каждый пакет числом, а также отправлять ожидаемое количество пакетов. Например, если вы отправили 10 больших пакетов, вы можете включить информацию: пакет 1/10, пакет 2/10 и т. Д. Таким образом, вы можете по крайней мере сказать, не получили ли вы все пакеты. Если вы их не получили, вы можете отправить запрос на повторную отправку пропущенных пакетов.

3 голосов
/ 23 февраля 2011

UDP по своей сути ненадежен.

дейтаграммы могут быть выброшены в любой точке между отправителем и получателем, даже внутри получателя на уровне ниже вашего кода. Установка большего размера буфера recv, вероятно, поможет сетевому коду внутри вашей машины буферизовать больше дейтаграмм, но вы должны ожидать, что некоторые дейтаграммы все равно будут потеряны.

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

[Re your edit ...] А что обрабатывает вашу очередь и как работает блокировка между производителем и потребителями? Измените свой код так, чтобы логика recv просто увеличивала счетчик, отбрасывала данные и возвращалась назад, чтобы увидеть, теряете ли вы меньше дейтаграмм; В любом случае, UDP ненадежен, вы будете иметь датаграммы, которые будут отброшены, и вы должны просто ожидать этого и иметь дело с этим. Беспокойство об этом означает, что вы сосредоточены на неправильной проблеме; используйте данные, которые вы ПОЛУЧИТЕ, и предположите, что вы не получите большую их часть, и тогда ваша программа будет работать, даже если сеть перегружена и большинство ваших дейтаграмм будут отброшены.

Итак, вот как это работает с UDP.

2 голосов
/ 23 февраля 2011

В ваших тестах выяснилось, что в буфере может быть только до двух пакетов, поэтому, если каждый пакет меньше 28 КБ, это должно быть хорошо.

Как вы знаете, UDP с потерями, но вы должны иметь возможность отправлять более одного пакета за 10 мс. Я предлагаю вам написать простой приемник, который просто слушает пакеты, просто чтобы определить, является ли ваше приложение или что-то на уровне сети / ОС. (Подозреваю позже)

1 голос
/ 23 февраля 2011

Я не знаю Java, но ... позволяет ли API вызывать асинхронное прослушивание / получение для дейтаграммы:

  • Использование O / S API для получения (передачи вашегобуфер уровня приложения в качестве параметра)
  • (Подождите, пока нечего получать ...)
  • (O / S получает что-то из сети ...)
  • O / S помещает полученный пакет в буфер и завершает / возвращает ваш вызов API

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

...