MAATRIX / Блог / Сколько пакетов в секунду переварит ваш сервер: замер PPS вместо мегабит

Сколько пакетов в секунду переварит ваш сервер: замер PPS вместо мегабит

MAATRIX

Когда выбирают тариф или объясняют, почему сервер «тормозит под нагрузкой», почти всегда смотрят на одну цифру — мегабиты или гигабиты в секунду. Канал загружен на 30%, значит, есть запас, рассуждает админ, и ошибается: при мелких пакетах сервер может упереться в потолок процессора на обработке прерываний задолго до того, как канал заполнится хоть наполовину. Разбираемся, что такое PPS, чем он отличается от полосы пропускания, как его измерить и когда именно мелкие пакеты убивают производительность раньше, чем кончается мегабитная ёмкость канала.

Почему мегабиты не равны пакетам

Пропускная способность канала считается в битах в секунду — это просто объём данных, который физически проходит через провод или радиоэфир за единицу времени. Но данные не идут сплошным потоком: они нарезаны на пакеты, и у каждого пакета есть заголовки (Ethernet, IP, TCP/UDP) и полезная нагрузка. Заголовки занимают фиксированный объём независимо от размера пакета — условно говоря, около 40–60 байт служебной информации на пакет при обычном TCP/IP поверх Ethernet.

Отсюда простое следствие: один и тот же канал в 1 Гбит/с можно заполнить очень по-разному. Если гонять пакеты по 1500 байт (стандартный MTU для Ethernet), то на заполнение канала понадобится порядка 80 тысяч пакетов в секунду. Если же пакеты по 64 байта (минимальный размер Ethernet-кадра, характерный, например, для DNS-запросов, игрового трафика или части DDoS-атак), то тот же 1-гигабитный канал по битам заполнится числом пакетов на порядок большим — сотнями тысяч в секунду. Полоса та же, а нагрузка на систему обработки пакетов — совсем другая.

Дело в том, что стоимость обработки одного пакета для CPU почти не зависит от его размера. Прерывание, вызов драйвера, разбор заголовков, поиск в таблице маршрутизации или conntrack, передача пакета выше по стеку — всё это происходит один раз на пакет, независимо от того, 64 в нём байта или 1500. Значит, стоимость в тактах CPU растёт вместе с числом пакетов в секунду (PPS — packets per second), а не вместе с числом бит в секунду. Именно поэтому сервер, спокойно переваривающий 1 Гбит/с крупными пакетами, может захлебнуться на трафике в 200 Мбит/с, если этот трафик состоит из мелких пакетов.

Где именно упирается CPU

Путь пакета от сетевой карты до приложения состоит из нескольких этапов, и почти все они линейны по числу пакетов, а не по числу байт:

  • Аппаратное прерывание (IRQ) — карта сигнализирует CPU о приходе данных. Современные карты используют батчинг (interrupt coalescing) и polling через NAPI, но каждая порция пакетов всё равно требует отдельного прохода обработчика.
  • Разбор заголовков и маршрутизация — ядро должно понять, что за пакет, кому он адресован, какое правило firewall/conntrack к нему применить.
  • Пересечение границы ядро-пространство пользователя — копирование данных в сокет-буфер, пробуждение процесса через epoll/select.
  • Обработка в приложении — если это DNS-сервер, каждый запрос — отдельный пакет, отдельный разбор, отдельный ответ, независимо от того, что содержимое крошечное.

Каждый шаг имеет накладные расходы «за штуку». Обработка прерываний и программных прерываний (softirq) в Linux видна в top как %si — если это значение упирается в потолок одного ядра, а остальные простаивают, вы, скорее всего, смотрите ровно на эту проблему. Подробнее о механике прерываний и о том, почему без настройки вся нагрузка ложится на одно ядро, разобрано в статье о том, почему сетевая карта отбирает у вас целое ядро.

Важно понимать: полоса канала и PPS — это два независимых ограничения, и упереться можно в любое из них раньше другого. Крупные файлы по FTP или видеопоток на 4К упрутся в мегабиты. DNS-резолвер, отдающий тысячи мелких ответов, VoIP-шлюз с потоком RTP-пакетов, игровой сервер с частыми маленькими апдейтами состояния или сервер под волюметрической DDoS-атакой мелкими пакетами — упрутся в PPS, часто оставляя канал загруженным на считаные проценты.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Как замерить PPS: sar -n DEV

Самый простой и всегда доступный инструмент — sar из пакета sysstat. Он собирает статистику по интерфейсам с интервалом опроса, и в его выводе есть прямые счётчики пакетов в секунду, а не только байтов.

apt install sysstat   # Debian/Ubuntu
dnf install sysstat   # AlmaLinux/RHEL

Снять срез в реальном времени с интервалом 1 секунда:

sar -n DEV 1

Типичный вывод:

12:41:03        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
12:41:04         eth0  184532.00   91204.00   14812.30   7301.15      0.00      0.00      0.00     12.40

Здесь rxpck/s и txpck/s — это и есть PPS на приём и передачу, а rxkB/s/txkB/s — полоса в килобайтах. Ключевой момент: сравните %ifutil (загрузку интерфейса по байтам, показатель близкий к тому, что видно в мониторинге по трафику) с тем, насколько близко rxpck/s подошло к практическому потолку карты и CPU для вашего железа. Если %ifutil низкий (условно, 10–15%), а rxpck/s уже под сотни тысяч и растёт вместе с %si в top — вы упираетесь именно в PPS, а не в канал.

Для истории по интервалам (не разово, а за период) sar можно направить в лог через cron/systemd timer — стандартная настройка sysstat уже это делает по умолчанию, и тогда прошлые данные доступны через sar -n DEV -f /var/log/sysstat/saXX.

Отдельно стоит смотреть на счётчик %ifutil с осторожностью: он оценочный и на некоторых системах считается некорректно для интерфейсов без объявленной скорости (например, virtio-интерфейсы внутри VM). В таких случаях надёжнее ориентироваться на сырые rxpck/s/txpck/s, сравнивая их с ранее замеренной производительностью карты, а не полагаться на процент.

Как замерить PPS: ethtool -S

sar даёт картину на уровне ядра Linux (интерфейс как таковой), но не показывает, что происходит внутри самой карты — сколько пакетов физически обработано на аппаратном уровне, сколько сброшено из-за переполнения буфера, сколько ошибок. Для этого нужен ethtool со статистикой конкретного драйвера:

ethtool -S eth0

Вывод сильно зависит от драйвера и модели карты (Intel i40e/ixgbe, Mellanox mlx5, virtio_net в виртуалках и так далее), но общая логика одна: там будут счётчики вида rx_packets, tx_packets, а также — что важнее для диагностики упора в PPS — счётчики потерь и переполнений: rx_dropped, rx_missed_errors, rx_fifo_errors, для многоочередных карт — отдельные счётчики по каждой очереди (rx_queue_0_packets, rx_queue_1_packets и так далее).

Практический приём: снимите ethtool -S eth0 дважды с интервалом (например, 5 секунд), вычтите значения — это даст пакеты в секунду и, что важнее, скорость роста счётчиков потерь:

ethtool -S eth0 | grep -iE "drop|miss"

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

Если счётчики распределены по очередям неравномерно — одна очередь забита, остальные почти пустые — это почти всегда означает, что распределение пакетов по ядрам (RSS) настроено плохо или не настроено вовсе, и вся нагрузка ложится на одно ядро вместо равномерного размазывания по нескольким. О том, как трафик физически движется от карты дальше по системе, полезно посмотреть в статье о пути пакета от сетевой карты до сокета.

RSS, RPS и multiqueue: как распределить нагрузку по ядрам

Один процессорный поток (одно ядро) физически ограничен в том, сколько прерываний и пакетов он способен обработать в секунду — грубо говоря, десятки-сотни тысяч в зависимости от поколения CPU, сложности обработки и настроек. Если вся сетевая нагрузка сваливается на одно ядро, потолок PPS сервера равен потолку этого одного ядра, даже если остальные 15 ядер простаивают. Именно для решения этой проблемы существуют механизмы распределения приёма пакетов.

RSS (Receive Side Scaling) — это аппаратная функция самой сетевой карты. Карта вычисляет хэш от полей пакета (обычно src/dst IP и src/dst порт) и на основе хэша раскладывает входящие пакеты по нескольким аппаратным очередям приёма (RX queues), каждая из которых обслуживается своим прерыванием и, как следствие, может быть закреплена за отдельным ядром CPU. Требование для RSS — карта должна физически поддерживать multiqueue (почти все современные серверные карты 1G/10G/25G это умеют) и иметь достаточно очередей. Посмотреть текущее число очередей и их максимум:

ethtool -l eth0

Вывод покажет Pre-set maximums (что умеет карта) и Current hardware settings (что реально включено). Если очередей меньше, чем ядер, и карта умеет больше — стоит увеличить:

ethtool -L eth0 combined 8

RPS (Receive Packet Steering) — программный аналог RSS в самом ядре Linux. Полезен, если карта не поддерживает multiqueue (нередкий случай для virtio в виртуалках) или нужно более гибкое распределение, чем даёт аппаратный хэш. Настраивается через /sys/class/net/eth0/queues/rx-0/rps_cpus — битовой маской указываются ядра, между которыми распределяются пакеты конкретной очереди. Минус в том, что RPS сам тратит циклы CPU на распределение, то есть частично компенсирует проблему ценой дополнительной нагрузки — в отличие от RSS, где эту работу делает карта.

Важный нюанс, о котором часто забывают: даже с настроенным RSS, прерывания от разных очередей должны быть равномерно раскиданы по ядрам через irqbalance или вручную через /proc/irq/<N>/smp_affinity. Если RSS создал 8 очередей, но все 8 прерываний привязаны к одному и тому же ядру (частая ситуация сразу после установки новой карты или обновления ядра, когда irqbalance ещё не отработал), от multiqueue толку не будет — узкое место просто останется тем же самым ядром. Проверить текущее распределение:

cat /proc/interrupts | grep eth0

Если числа прерываний по каждой строке (очереди) растут преимущественно в одной колонке (одном CPU) — распределения фактически нет, несмотря на формально настроенный RSS.

Когда мелкие пакеты убивают производительность раньше канала

Практическая граница, где стоит переключить внимание с мегабит на PPS, — трафик, состоящий преимущественно из пакетов заметно меньше MTU:

СценарийТипичный размер пакетаЧто происходит
Веб-сервер, крупные ответы (файлы, видео)Близко к MTU (1500 байт)Канал (мегабиты) обычно упирается раньше PPS
DNS-сервер (резолвер, авторитативный)60–150 байт на запрос/ответPPS часто становится потолком раньше канала
Игровой сервер (частые апдейты состояния)50–200 байтPPS — обычно основное ограничение
VoIP / RTP-поток100–200 байт на пакет, но пакетов очень многоPPS ограничивает раньше, чем полоса
DDoS мелкими пакетами (SYN-флуд, UDP-флуд с мелкой нагрузкой)40–64 байтаАтака целится именно в PPS, а не в канал — заполнить гигабитный канал по битам такой атакой сложно, а вот забить CPU обработкой прерываний легко

Последний пункт — не абстракция. Волюметрическая атака мелкими пакетами часто выглядит в графиках трафика скромно (условно, десятки-сотни мегабит), потому что мониторинг обычно снимает именно байты, а не пакеты. При этом сервер уже недоступен, потому что CPU полностью занят обработкой прерываний — до приложения, слушающего порт, эти пакеты может даже не долетать в разумном темпе. Подробнее о том, как выглядит короткая атака в графиках мониторинга, — в статье про DDoS-атаку на 20 минут и что было видно в графиках. Общие практики защиты — в статье про защиту от DDoS на выделенном сервере.

Конкретное число PPS, которое ваш сервер способен переварить до деградации, зависит от процессора (частота, число ядер, поколение), сетевой карты (число очередей, offload-функции), настройки RSS/IRQ affinity и от того, что делает с каждым пакетом ядро и приложение (простой NAT — дёшево, conntrack с глубокой инспекцией — намного дороже). Это именно ориентир для прикидки, а не гарантия — для точного числа под конкретную нагрузку нужен собственный замер тем же sar/ethtool на трафике, максимально похожем на боевой.

Что делать, если сервер упирается в PPS

Если замеры показывают, что %si растёт быстрее полосы канала, а rx_missed_errors/rx_dropped начинают увеличиваться под нагрузкой, есть несколько практических направлений:

  • Включить multiqueue (ethtool -l/ethtool -L) и проверить, что число очередей осмысленно соотносится с числом ядер сервера.
  • Проверить распределение IRQ по ядрам через /proc/interrupts и, если irqbalance не справляется (частая ситуация на серверах с жёстко закреплёнными под приложение ядрами), настроить smp_affinity вручную.
  • Проверить offload-функции карты (checksum offload, TSO/GRO) — они снимают часть работы с CPU, но ускоряют не всё одинаково: при глубокой инспекции трафика отдельные функции иногда приходится отключать.
  • Оценить, что дорого именно в приложении — например, DNS-сервер с синхронным логированием каждого запроса упрётся в PPS раньше, чем тот же сервер без логирования на каждый пакет.
  • Закладывать запас по PPS, а не только по мегабитам, если ожидаются мелкие пакеты — DNS, VoIP, игровые бэкенды, публичные API с частыми мелкими запросами.
  • Рассмотреть XDP/eBPF для раннего дропа нежелательного трафика — обработка на уровне драйвера до попадания пакета в стек ядра дешевле всего именно по PPS, актуально прежде всего при защите от DDoS мелкими пакетами.

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли определить упор в PPS только по графикам трафика в мониторинге?

Обычно нет — стандартные графики (Zabbix, Grafana с SNMP или netdata) чаще всего показывают биты/байты в секунду. Если метрики rxpck/s/txpck/s и счётчики ошибок с карты не заведены отдельно, упор в PPS виден лишь косвенно — через рост %si в CPU-графике при невысокой загрузке канала.

RSS работает одинаково на всех сетевых картах?

Нет, число очередей, алгоритм хэширования и набор офлоад-функций различаются между производителями и поколениями карт. Точные возможности конкретной карты стоит смотреть через ethtool -l, а не считать, что «раз карта серверная — 16 очередей и всё само работает».

VPS тоже упирается в PPS так же, как выделенный сервер?

Да, механика та же, но добавляется слой виртуализации: виртуальная карта (обычно virtio-net) сама имеет накладные расходы на пакет, а число доступных очередей и ядер ограничено конфигурацией VM. На VPS RSS часто не настроить так же гибко, как на железе с прямым доступом к физической карте.

Что дешевле для CPU: пакет на 1500 байт или на 64 байта?

Обработка в CPU почти не зависит от размера полезной нагрузки — стоимость определяется числом самих пакетов, а не байт в них. Поэтому 64-байтовый пакет обходится почти так же дорого, как 1500-байтовый, хотя по трафику разница в 20+ раз.

Нужно ли гнаться за максимальным числом RSS-очередей?

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

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →