2010-02-18 3 views
37

У меня есть приложение java на linux, которое открывает UDP-сокет и ждет сообщений.Как контролировать свободное пространство UDP U Linux?

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

Мы попытались увеличить буферы сокетов, но это не помогло - мы начали терять пакеты позже, чем раньше, но это все.

Для отладки, я хочу знать, насколько полный буфер udp ОС, в любой данный момент. Googled, но ничего не нашел. Вы можете мне помочь?

P.S. Ребята, я знаю, что UDP ненадежен. Однако - мой компьютер получает все сообщения UDP, в то время как мое приложение не может использовать некоторые из них. Я хочу оптимизировать свое приложение до максимума, вот в чем причина вопроса. Благодарю.

ответ

27

Linux предоставляет файлы /proc/net/udp и /proc/net/udp6, в котором перечислены все открытые сокеты UDP (для IPv4 и IPv6, соответственно). В обоих из них столбцы tx_queue и rx_queue отображают исходящие и входящие очереди в байтах.

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

+2

Спасибо за rx_queue, для остальных - см. Обновление) –

+1

@Juliano Кто сказал, что может выбрать протокол для использования? Возможно, он реализует протокол на основе udp для обслуживания существующих клиентов. – steffen

+2

Плакат хочет знать о мониторинге статистики UDP, а не о мнениях по использованию протокола. Сначала определив, где происходит потеря в слоях, тогда можно работать с исправлением. – RickS

-1

Процесс прост:

  1. При желании, приостановить процесс подачи заявки.

  2. Открыть разъем UDP. Вы можете вырвать его из работающего процесса, используя /proc/<PID>/fd, если необходимо. Или вы можете добавить этот код к самому приложению и отправить ему сигнал - он, конечно, уже будет иметь сокет.

  3. Позвоните recvmsg в плотной петле как можно быстрее.

  4. Подсчитайте, сколько у вас пакетов/байт.

Это отбросит любые датаграммы, которые в настоящее время буферизованы, но если это нарушит ваше приложение, ваше приложение уже было повреждено.

+0

Я уже собирался ответить на этот вопрос, но, по-моему, это смешно. Я просто надеюсь, что никто не попытался реализовать это :) – Navin

4

rx_queue сообщит вам длину очереди в любой момент времени, но это не скажет вам, насколько полная очередь была, то есть надводная отметка. Невозможно постоянно отслеживать это значение и не использовать его программно (см. How do I get amount of queued data for UDP socket?).

Единственный способ, которым я могу представить, как контролировать длину очереди, - переместить очередь в вашу собственную программу. Другими словами, запустите два потока: один читает сокет так быстро, как может, и выгружает дейтаграммы в вашу очередь; а другая - ваша программа, вытягивающая из этой очереди и обрабатывающая пакеты. Это, конечно, предполагает, что вы можете гарантировать, что каждый поток находится на отдельном CPU. Теперь вы можете отслеживать длину своей очереди и отслеживать отметку с водой.

46

UDP - это вполне жизнеспособный протокол. Это тот же самый старый пример правильного инструмента для правильной работы!

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

Это может быть допущено для коротких всплесков. Очередь делает именно то, что она должна делать - очереди дейтаграмм до тех пор, пока вы не будете готовы. Но если средняя скорость прибытия регулярно вызывает отставание в очереди, пришло время перепроектировать вашу программу. Здесь есть два основных варианта: сократить прошедшее время обработки с помощью коварных методов программирования и/или многопоточную вашу программу. Можно также использовать балансировку нагрузки для нескольких экземпляров вашей программы.

Как уже упоминалось, в Linux вы можете проверить файловую систему proc, чтобы получить информацию о том, что такое UDP. Например, если я cat в /proc/net/udp узел, я получаю что-то вроде этого:

$ cat /proc/net/udp 
    sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops    
    40: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000  0  0 3466 2 ffff88013abc8340 0   
    67: 00000000:231D 00000000:0000 07 00000000:0001E4C8 00:00000000 00000000 1006  0 16940862 2 ffff88013abc9040 2237  
122: 00000000:30D4 00000000:0000 07 00000000:00000000 00:00000000 00000000 1006  0 912865 2 ffff88013abc8d00 0   

От этого, я могу видеть, что сокет принадлежит идентификатор пользователя 1006, прослушивает порт 0x231D (8989), и что получают очередь составляет около 128 КБ. Поскольку 128 КБ является максимальным размером в моей системе, это говорит о том, что моя программа очень слаба, не отставая от прибывающих дейтаграмм. До сих пор было 2237 капель, а это означает, что уровень UDP не может помещать в очередь сокетов еще несколько дейтаграмм и должен их отбрасывать.

Вы можете наблюдать за поведением вашей программы с течением времени, например. с помощью:

watch -d 'cat /proc/net/udp|grep 00000000:231D' 

Отметим также, что NetStat команда делает примерно то же самое: netstat -c --udp -an

Мое решение для моей Weenie программы, будет многопоточной.

Cheers!

+0

как вы знаете, размер вашей udp-системы max max составляет 128 КБ? – Chinaxing

+2

@ Чинаксинг 'cat/proc/sys/net/core/rmem_max' – wakjah