Причины отбрасывания UDP-пакетов в Linux - PullRequest
13 голосов
/ 06 мая 2011

У меня есть приложение Linux C ++, которое получает последовательные UDP-пакеты. Из-за последовательности я могу легко определить, когда пакет потерян или переупорядочен, то есть когда встречается «пробел». Система имеет механизм восстановления для устранения пробелов, однако, во-первых, лучше избегать пробелов. Используя простой основанный на libpcap анализатор пакетов, я определил, что в данных нет аппаратных пробелов. Тем не менее, я вижу много пробелов в моем приложении. Это говорит о том, что ядро ​​отбрасывает пакеты; это подтверждается просмотром файла / proc / net / snmp . Когда мое приложение обнаруживает разрыв, счетчик Udp InErrors увеличивается.

На системном уровне мы увеличили максимальный приемный буфер:

# sysctl net.core.rmem_max
net.core.rmem_max = 33554432

На уровне приложения мы увеличили размер буфера приема:

int sockbufsize = 33554432
int ret = setsockopt(my_socket_fd, SOL_SOCKET, SO_RCVBUF,
        (char *)&sockbufsize,  (int)sizeof(sockbufsize));
// check return code
sockbufsize = 0;
ret = getsockopt(my_socket_fd, SOL_SOCKET, SO_RCVBUF, 
        (char*)&sockbufsize, &size);
// print sockbufsize

После вызова getsockopt () значение печати всегда в 2 раза больше установленного значения (67108864 в приведенном выше примере), но я считаю, что этого следовало ожидать.

Я знаю, что неспособность использовать данные достаточно быстро может привести к потере пакета. Однако все это приложение проверяет последовательность, а затем помещает данные в очередь; фактическая обработка выполняется в другом потоке. Кроме того, машина современна (двойной Xeon X5560, 8 ГБ оперативной памяти) и очень легко загружена. У нас есть буквально десятки идентичных приложений, получающих данные со скоростью намного выше , которые не сталкиваются с этой проблемой.

Помимо слишком медленного использования приложения, есть ли другие причины, по которым ядро ​​Linux может отбрасывать UDP-пакеты?

FWIW, это на CentOS 4, с ядром 2.6.9-89.0.25.ELlargesmp.

Ответы [ 4 ]

7 голосов
/ 06 мая 2011

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

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

3 голосов
/ 23 августа 2011

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

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

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

Я решил это, играя с ионизацией (команда ionice) моего процесса и процесса базы данных. Помогло изменение класса ввода / вывода на Best Effort. Удивительно, но сейчас я не могу воспроизвести эту проблему, даже при том, что по умолчанию уместен ввод-вывод. Мое ядро ​​2.6.32-71.el6.x86_64.

Я все еще разрабатываю это приложение, поэтому постараюсь обновить свой пост, как только узнаю больше.

1 голос
/ 06 мая 2011

int ret = setsockopt(my_socket_fd, SOL_SOCKET, SO_RCVBUF, (char *)&sockbufsize, (int)sizeof(sockbufsize));

Прежде всего, setsockopt принимает (int, int, int, void *, socklen_t), поэтому нет необходимости в приведениях.

Используя простой анализатор пакетов на основе libpcap, я определил, что на аппаратном уровне нет пробелов в данных. Тем не менее, я вижу много пробелов в моем приложении. Это говорит о том, что ядро ​​отбрасывает пакеты;

Это говорит о том, что ваше окружение недостаточно быстрое. Захват пакетов, как известно, требует интенсивной обработки, и вы заметите, что глобальная скорость передачи по интерфейсу будет падать, когда вы начнете захватывать программы, такие как iptraf-ng или tcpdump на одной.

0 голосов
/ 19 мая 2016

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

Чтобы решить эту проблему, я добавил меньший локальный буфер в принимающий поток, и он только передавал данные вбуфер не был заблокирован (используя std :: mutex :: try_lock).

...