tcpdump увеличивает производительность udp
Я запускаю набор нагрузочных тестов, чтобы определить производительность следующей настройки:
Node.js test suite (client) --> StatsD (server) --> Graphite (server)
Короче говоря, набор тестов node.js отправляет определенное количество метрик каждые x секунд в экземпляр StatsD, который находится на другом сервере. Затем StatsD сбрасывает метрики каждую секунду в экземпляр Graphite, расположенный на том же сервере. Затем я смотрю, сколько метрик фактически было отправлено набором тестов и сколько было получено Graphite для определения потери пакетов между набором тестов и Graphite.
Однако я заметил, что иногда я получаю очень большие скорости отбрасывания пакетов (обратите внимание, что он отправляется по протоколу UDP), в диапазоне от 20-50%. И вот тогда я начал изучать, где эти пакеты отбрасывались, понимая, что это может быть связано с некоторой проблемой производительности StatsD. Поэтому я начал регистрировать показатели в каждой части системы, чтобы отслеживать, где произошло это падение. И здесь все становится странным.
Я использую tcpdump для создания файла захвата, который я проверяю после завершения теста. Но всякий раз, когда я запускаю тесты с запущенным tcpdump, потеря пакетов практически отсутствует! Похоже, что tcpdump каким-то образом повышает производительность моих тестов, и я не могу понять, почему и как это происходит. Я запускаю следующую команду для регистрации сообщений tcpdump на сервере и клиенте:
tcpdump -i any -n port 8125 -w test.cap
В одном конкретном тестовом примере я посылаю 40000 метрик / с. Тест при запуске tcpdump имеет потерю пакетов около 4%, в то время как тест без потери пакетов составляет около 20%
Обе системы работают как виртуальные машины Xen со следующей настройкой:
- Intel Xeon E5-2630 v2 с частотой 2,60 ГГц
- 2 ГБ ОЗУ
- Ubuntu 14.04 x86_64
Вещи, которые я уже проверил на возможные причины:
- Увеличение размера буфера приема / отправки UDP.
- Нагрузка процессора влияет на тест. (максимальная загрузка 40-50%, как на стороне клиента, так и на стороне сервера)
- Запуск tcpdump на определенных интерфейсах вместо 'any'.
- Запуск tcpdump с '-p' для отключения случайного режима.
- Запуск tcpdump только на сервере. Это привело к потере пакетов на 20% и, похоже, не повлияло на тесты.
- Запуск tcpdump только на клиенте. Это привело к увеличению производительности.
- Увеличение netdev_max_backlog и netdev_budget до 2^32-1. Это не имеет значения.
- Перепробовал все возможные настройки беспорядочного режима на каждом нике (сервер включен и клиент выключен, сервер выключен и клиент включен, оба включены, оба выключены). Это не имеет значения.
4 ответа
Когда tcpdump запущен, он будет довольно быстро читать при поступлении кадров. Моя гипотеза состоит в том, что настройки буфера кольцевого пакета NIC могут быть немного маленького размера; когда tcpdump работает, он очищается более своевременно.
Если вы являетесь подписчиком Red Hat, то эта статья поддержки очень полезна. Обзор приема пакетов. Там есть некоторые вещи, которые, я думаю, вы еще не рассматривали.
Подумайте, как ваша система работает с IRQ; рассмотреть возможность увеличения "dev_weight" сетевого интерфейса (что означает, что больше пакетов будет прочитано из NIC в пространство пользователя); посмотрите, как часто приложение читает сокет (может ли оно использовать выделенный поток, есть ли известные проблемы / обходные пути в отношении масштабируемости).
Увеличить буфер кадров NIC (используя ethtool
команда - посмотрите на --set-ring
и т.д. аргументы).
Посмотрите на "масштабирование на стороне приема" и используйте хотя бы столько потоков приема для чтения в трафике.
Интересно, делает ли tcpdump что-то классное, например, использует поддержку ядра для кольцевых буферов пакетов? Это поможет объяснить поведение, которое вы видите.
Какого губернатора вы используете? Я видел подобное поведение с "по требованию" или "консервативным" губернатором.
Попробуйте использовать регулятор производительности и отключить все энергосберегающие функции в BIOS сервера.
Это что-то меняет?
Я подозреваю, что принимающая сторона просто не способна обрабатывать скорость передачи пакетов, и вот почему:
использование tcpdump на клиенте уменьшает количество отброшенных пакетов: tcpdump замедляет работу клиента, и поэтому сервер видит гораздо более низкую скорость упаковщика, с которой он все еще может частично справиться. Вы должны быть в состоянии подтвердить эту гипотезу, проверив счетчики пакетов RX/TX на клиенте и сервере
Вы упомянули, что вы увеличили размер приема / отправки UDP-буфера, не могли бы вы подробно рассказать, как? Важно, чтобы на сервере вы изменили и rmem_max, и rmem_default, например:
sysctl -w net.core.rmem_max=524287 sysctl -w net.core.wmem_max=524287 sysctl -w net.core.rmem_default=524287 sysctl -w net.core.wmem_default=524287
Тестирование ваших настроек
Остановите statsd и приложение узла, затем в режиме ожидания системы используйте iperf для проверки скорости передачи пакетов, которую может обработать сеть / ядро. Если вы можете передавать 40K пакетов / с с помощью iperf, но не можете с помощью statsd, тогда вам следует сосредоточить свои усилия на настройке statsd.
Другие переменные
Также не забудьте настроить net.core.netdev_max_backlog: максимальное количество пакетов, которые могут быть помещены в очередь, когда определенный интерфейс получает пакеты быстрее, чем ядро может их обработать.
Другой способ ip_conntarck
module, Вы уверены, что ваш linux-box может принять новое соединение? проверить через:
root@debian:/home/mohsen# sysctl net.ipv4.netfilter.ip_conntrack_max
net.ipv4.netfilter.ip_conntrack_max = 65536
root@debian:/home/mohsen# sysctl net.ipv4.netfilter.ip_conntrack_count
net.ipv4.netfilter.ip_conntrack_count = 29
Вы должны проверить
net.ipv4.netfilter.ip_conntrack_max > net.ipv4.netfilter.ip_conntrack_count
если max == count, ваше максимальное соединение заполнено, и ваш linux-box не может принять новое соединение.
Если у вас нет ip_conntrack, вы можете легко загрузить через modprobe ip_conntrack