Выберите продукт

Linux IRQ/softirq и ksoftirqd: как убрать CPU jitter и настроить RPS/RFS, irqbalance и ethtool

Если ksoftirqd грузит CPU, растёт softirq и «пилит» задержка, обычно виноваты сетевые IRQ и распределение очередей. Разберём /proc/interrupts и /proc/softirqs, irqbalance, RSS и RPS/RFS/XPS, а также тюнинг ethtool, GRO/GSO и NAPI (netdev_budget).
Linux IRQ/softirq и ksoftirqd: как убрать CPU jitter и настроить RPS/RFS, irqbalance и ethtool

На прод-серверах «внезапные» пики softirq, рост ksoftirqd/N и деградация сетевой задержки (CPU jitter) почти всегда упираются в то, как ядро распределяет обработку пакетов между CPU. Особенно заметно на VPN/туннелях, прокси, балансировщиках, busy веб-узлах и везде, где высокий PPS (много маленьких пакетов).

Ниже — практический разбор: как быстро подтвердить, что проблема именно в сети, где искать перекос, и что настраивать в правильном порядке: irqbalance, IRQ affinity, RSS, RPS/RFS/XPS, offload’ы (GRO/GSO/TSO) и параметры NAPI (netdev_budget).

Короткая теория: IRQ, softirq и ksoftirqd

IRQ — аппаратные прерывания: устройство (например, NIC) сигналит CPU «пришли пакеты/есть работа». В Linux обработка IRQ обычно делится на две стадии:

  • top-half (жёсткий IRQ): минимальная работа, чтобы быстро «снять событие» и не блокировать прерывания;
  • bottom-half: основная обработка уходит в контекст softirq (для сети — NET_RX и NET_TX).

Если работы слишком много и ядро не успевает отработать softirq «сразу» в текущем контексте, оно переносит догоняющую обработку в поток ksoftirqd/N (на каждом CPU свой). Это не «плохой процесс», а симптом: сеть попадает в режим, где latency обычно хуже и появляется разброс задержек.

Высокий CPU у ksoftirqd чаще означает перекос: обработка пакетов и прерывания «прилипли» к одному ядру или к узкой группе ядер.

Как выглядит проблема: симптомы и быстрые маркеры

Типичные признаки:

  • в top/htop растёт ksoftirqd на одном или нескольких CPU;
  • в mpstat увеличивается %soft (иногда вместе с %sys);
  • p50 «нормальный», но p99/p999 заметно хуже (jitter);
  • одно ядро перегружено (hot CPU), остальные простаивают;
  • под нагрузкой растут drops/overruns по драйверу NIC или в сетевом стеке.
  • Полезная привычка: прежде чем тюнить sysctl, убедитесь, что у вас нет явного перекоса IRQ/очередей. Иначе вы будете «лечить следствие».

    Диагностика перекоса IRQ и нагрузки softirq по ядрам CPU

    Быстрая диагностика: подтверждаем сетевой softirq и находим перекос

    1) Смотрим распределение softirq по CPU

    cat /proc/softirqs

    Смотрите в первую очередь NET_RX и NET_TX. Если один CPU сильно впереди остальных — это почти всегда источник jitter.

    2) Смотрим динамику загрузки по CPU

    mpstat -P ALL 1

    Ищите CPU, где стабильно высокие %soft и/или %sys. Дальше обычно вы идёте в сторону IRQ affinity, RSS и очередей.

    3) Находим «кто генерирует IRQ»

    cat /proc/interrupts

    Это основной файл для темы. Для сетевых устройств строки обычно содержат имя интерфейса/очереди/драйвера: eth0, ens3, rx-0, TxRx, mlx5_comp и т.п.

    Что искать в выводе:

    • одна IRQ-строка «убегает» в один CPU;
    • у NIC много MSI-X векторов, но активны 1–2 (часто RSS выключен или не даёт нужной параллельности);
    • IRQ сидит на том же CPU, где работает ваше приложение (конкуренция за CPU time и кэш).

    4) Проверяем дропы и статистику драйвера

    ip -s link show dev eth0
    ethtool -S eth0

    Набор счётчиков зависит от драйвера, но полезно отслеживать рост rx_dropped, rx_missed_errors, rx_no_buffer, а также пер-очередную статистику (если есть).

    FastFox VDS
    Облачный VDS-сервер в России
    Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

    irqbalance: когда включать, а когда лучше руками

    irqbalance пытается распределять IRQ по CPU автоматически. На «типовой» машине это часто быстро лечит ситуацию «всё на CPU0».

    Нюансы, из-за которых иногда лучше ручной режим:

    • если вы делаете pinning/изоляцию CPU под приложение, автоматическая миграция IRQ может ухудшить предсказуемость;
    • irqbalance может периодически перекладывать IRQ, а это иногда даёт jitter;
    • в виртуализации поведение зависит от виртуального NIC и политики хоста.

    Практический алгоритм:

    1. Если видите явный перекос — проверьте, что irqbalance запущен и не отключён политиками.
    2. Если после включения/перезапуска стало ровнее — фиксируйте результат и переходите к RSS/очередям.
    3. Если требования по стабильной latency жёсткие — обычно выигрывает ручная фиксация IRQ affinity и настройка очередей.

    Если вы параллельно настраиваете ограничение ресурсов для сервисов (чтобы соседние процессы не «отъедали» CPU во время пиков softirq), посмотрите материал про лимиты CPU и памяти в systemd.

    RSS, очереди NIC и MSI-X: база, без которой RPS/RFS не дадут максимум

    RSS (Receive Side Scaling) — аппаратное распределение входящих потоков по RX-очередям NIC на основе хэша (обычно 5-tuple). Каждая очередь обычно соответствует MSI-X IRQ вектору. Если RSS работает правильно, нагрузка по IRQ и NET_RX становится заметно ровнее.

    Проверяем количество каналов (очередей)

    ethtool -l eth0

    Если драйвер позволяет увеличить число очередей под число CPU/vCPU (и под реальную нагрузку), это может снизить давление на ksoftirqd за счёт параллелизма:

    ethtool -L eth0 combined 4

    Важно: «больше очередей» не всегда лучше. На малом трафике это может поднять overhead, на большом — улучшить p99. Меряйте: PPS, %soft, drops, latency.

    Проверяем RSS хэш/таблицу (если драйвер поддерживает)

    ethtool -x eth0

    Если очередей мало или распределение выглядит странно, вернитесь к каналам (ethtool -L) и дальше проверьте IRQ affinity по векторным IRQ.

    RPS/RFS/XPS: когда железо не распределяет как надо (или вы в VM)

    Если RSS недоступен, не помогает или вы хотите лучше «приклеить» обработку к CPU приложения, используйте программные механизмы:

    • RPS (Receive Packet Steering) — распределяет обработку RX по CPU на уровне ядра;
    • RFS (Receive Flow Steering) — старается направить пакет на CPU, где выполняется поток, читающий сокет (лучше кэш-локальность);
    • XPS (Transmit Packet Steering) — распределяет TX по CPU.

    Все настройки находятся в /sys/class/net/eth0/queues/ (очереди rx-N и tx-N).

    Включаем RPS на RX-очередях

    Для каждой RX-очереди задаётся маска CPU в rps_cpus. Пример для CPU0–CPU3 (hex-маска f):

    for f in /sys/class/net/eth0/queues/rx-*/rps_cpus; do echo f > "$f"; done

    На системах с большим числом CPU маска будет длиннее. В качестве стартовой точки часто работает «разрешить все CPU», но для минимального jitter обычно лучше выделить CPU-набор под сеть и не смешивать с тяжёлым user-space.

    Включаем RFS (таблица потоков)

    Чтобы RFS работал, нужны записи flow table: на очередях rps_flow_cnt и глобальный лимит net.core.rps_sock_flow_entries.

    sysctl -w net.core.rps_sock_flow_entries=32768
    for f in /sys/class/net/eth0/queues/rx-*/rps_flow_cnt; do echo 2048 > "$f"; done

    Размеры зависят от числа очередей и активных соединений. Слишком маленькие значения не дадут эффекта, слишком большие добавят память и overhead.

    Включаем XPS для TX

    for f in /sys/class/net/eth0/queues/tx-*/xps_cpus; do echo f > "$f"; done

    XPS чаще заметен при высоком исходящем трафике и нескольких TX-очередях: помогает снизить конкуренцию в одном CPU и сделать задержку ровнее.

    IRQ affinity вручную: когда нужно «прибить гвоздями»

    Если вы видите в /proc/interrupts, что конкретные IRQ сидят на одном CPU, можно задать affinity вручную через /proc/irq/IRQNUM/smp_affinity_list (удобный list-формат) или smp_affinity (hex-маска).

    Схема такая: находите номер IRQ для нужной очереди NIC (первый столбец в /proc/interrupts), затем задаёте список CPU:

    cat /proc/irq/123/smp_affinity_list
    echo 1-3 > /proc/irq/123/smp_affinity_list

    Если вы используете CPU isolation/pinning под приложение, не отдавайте IRQ на изолированные CPU: это почти всегда ухудшает предсказуемость latency.

    Если вы подбираете конфигурацию виртуалки под PPS-нагрузку (прокси, VPN, балансировщик) — пригодится шпаргалка по выбору тарифа: как подобрать VDS по CPU и RAM.

    Схема очередей сетевого интерфейса и распределения обработки пакетов по CPU (RSS/RPS/RFS/XPS)

    ethtool и offload’ы: GRO/GSO/TSO и полезные проверки

    Смотрим текущие offload-настройки

    ethtool -k eth0

    Ключевые механизмы, которые часто снижают PPS-нагрузку на сетевой стек (и, как следствие, давление на softirq и ksoftirqd):

    • GRO — склейка входящих пакетов, меньше обработок на уровне ядра;
    • GSO — отложенная сегментация на отправке;
    • TSO — сегментация TCP на стороне драйвера/железа.

    Для большинства веб-нагрузок и типовых сервисов включённые offload’ы помогают. Но есть сценарии, где они могут мешать (специфические туннели, фильтры, отдельные требования к latency). Поэтому правильный путь — менять по одному параметру и мерить p99/p999, drops и %soft.

    Пример (меняйте осознанно и тестируйте):

    ethtool -K eth0 gro on gso on tso on

    NAPI и netdev_budget: когда softirq «не успевает выгрести»

    NAPI снижает число IRQ под нагрузкой и переводит обработку в poll-режим. Это полезно для throughput, но при неудачных бюджетах может добавлять jitter.

    Параметры, которые обычно трогают:

    • net.core.netdev_budget — сколько пакетов можно обработать за один проход;
    • net.core.netdev_budget_usecs — ограничение по времени (мкс) на один проход.

    Посмотреть текущие значения:

    sysctl net.core.netdev_budget net.core.netdev_budget_usecs

    Пример осторожного тюнинга (нет «магических чисел», только стартовая точка):

    sysctl -w net.core.netdev_budget=600
    sysctl -w net.core.netdev_budget_usecs=8000

    Логика: если бюджет слишком мал — backlog не разгребается и работа уходит в ksoftirqd. Если бюджет слишком велик — можно «залипать» в сети и ухудшать latency других задач. Меняйте по одному параметру и сравнивайте метрики.

    Виртуальный хостинг FastFox
    Виртуальный хостинг для сайтов
    Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

    Пошаговый план (runbook), чтобы не тюнить вслепую

    Шаг 1. Зафиксируйте исходные метрики

    • mpstat -P ALL 1 (5–10 минут под реальной нагрузкой);
    • снимки /proc/interrupts и /proc/softirqs до/после;
    • ip -s link и ethtool -S (drops/ошибки);
    • latency на уровне приложения (p95/p99/p999).

    Шаг 2. Уберите явный перекос IRQ

    • проверьте irqbalance;
    • если нужно — задайте IRQ affinity для MSI-X векторов NIC вручную.

    Шаг 3. Приведите в порядок очереди и RSS

    • проверьте каналы через ethtool -l;
    • при необходимости настройте ethtool -L;
    • снова проверьте распределение в /proc/interrupts.

    Шаг 4. Настройте RPS/RFS/XPS (если нужно)

    • RPS — чтобы разнести обработку RX по CPU;
    • RFS — чтобы приблизить обработку к CPU приложения;
    • XPS — чтобы разнести TX и сгладить пики.

    Шаг 5. Проверьте offload’ы через ethtool

    • если offload’ы выключены — включите и сравните;
    • если включены, но jitter высокий — тестируйте по одному параметру.

    Шаг 6. Только потом трогайте netdev_budget

    Иначе можно «замазать» перекос IRQ/очередей, а проблема останется и вернётся при следующем изменении нагрузки.

    Частые ошибки

    • «Отключим все offload’ы — будет быстрее». Часто становится хуже: PPS растёт, softirq и ksoftirqd улетают.
    • Слишком много очередей при маленьком трафике: overhead, иногда хуже стабильность.
    • IRQ на изолированных CPU: приложение и сеть начинают конкурировать за одно ядро.
    • Тюнить только sysctl без работы с IRQ/RSS/RPS: эффект нестабилен.

    Мини-чеклист «после»

    • в /proc/interrupts IRQ NIC распределены по нескольким CPU без явного hot-ядра;
    • в /proc/softirqs NET_RX/NET_TX растут ровнее;
    • mpstat: %soft не упирается в один CPU, пики ниже;
    • drops/ошибки на интерфейсе не растут (или растут заметно медленнее);
    • p99/p999 latency улучшаются, jitter уменьшается.

    Оговорки для виртуалок

    На VM/VDS поведение зависит от виртуального NIC (например, virtio-net) и политики хоста. Но логика диагностики та же: /proc/interrupts, очереди, распределение по CPU, RPS/RFS, offload’ы. Часто помогает увеличить число vCPU (чтобы было куда распределять очереди) и затем правильно разложить IRQ/RPS.

    Если вы подбираете площадку под сетевой PPS, обычно разумная отправная точка — VDS, где у вас есть контроль над ядрами и системными настройками.

    Итог

    ksoftirqd — индикатор того, что сетевой стек не успевает обрабатывать пакеты «в моменте» и догоняет их планово. В большинстве случаев лечится не «убийством процесса», а выравниванием источника нагрузки: IRQ affinity и очередей NIC, включением/настройкой RSS и (при необходимости) RPS/RFS/XPS, плюс аккуратным тюнингом offload’ов через ethtool и параметров NAPI вроде net.core.netdev_budget.

Поделиться статьей

Вам будет интересно

Linux: eBPF для сетевого troubleshooting — где теряются пакеты (tc/qdisc/conntrack) OpenAI Статья написана AI (GPT 5)

Linux: eBPF для сетевого troubleshooting — где теряются пакеты (tc/qdisc/conntrack)

Когда «тормозит сеть», виноваты не всегда приложение и не всегда канал. Ниже — практичный eBPF-плейбук: как поймать TCP retransmit ...
Linux: apt/yum/dnf зависают — проверяем DNS, IPv6 и MTU (практический чеклист) OpenAI Статья написана AI (GPT 5)

Linux: apt/yum/dnf зависают — проверяем DNS, IPv6 и MTU (практический чеклист)

Если apt update висит на Connecting, yum/dnf уходят в таймаут, а веб «вроде работает», чаще всего виноваты DNS (включая systemd-re ...
NVMe в Linux: scheduler, read_ahead, discard и mount options для минимальной latency и максимальных IOPS OpenAI Статья написана AI (GPT 5)

NVMe в Linux: scheduler, read_ahead, discard и mount options для минимальной latency и максимальных IOPS

Разбираем настройки, которые реально влияют на NVMe в Linux: scheduler (none и mq-deadline), read_ahead, TRIM через discard или fs ...