Приведу пример распределения прерываний сетевых интерфейсов по ядрам процессора.
Для примера возьму сервер с accel-ppp, трафиком 6Gb/s, 500K+ pps, nat с ipoe и 6000 dchp клиентов.
А также обязательно отключим hyper-threading в BIOS, так как распределение нагрузки на виртуальные ядра может сильно увеличить нагрузку на некоторые физические ядра.
Посмотрим как распределены прерывания на данный момент (команды нужно выполнять от root пользователя):
cat /proc/interrupts grep ens2f0 /proc/interrupts grep ens2f1 /proc/interrupts watch -n 1 cat /proc/interrupts watch -n 1 cat /proc/softirqs ethtool -S eth0
Также в реальном времени посмотрим как загружены ядра процессора выполнив команду «top» и нажав «1» и что грузит набрав команду:
perf top
Посмотрим равномерно ли идет трафик по прерываниям, должны быть примерно одинаковые значения счетчиков (пример для ixgbe):
ethtool -S ens1f0 | grep .x_queue_._packets ethtool -S ens1f1 | grep .x_queue_._packets
Для i40e так:
ethtool -S ens1f0 | grep x_packets: ethtool -S ens1f1 | grep x_packets:
Посмотрим сколько прерываний возможно и активно на сетевом интерфейсе:
ethtool -l ens1f1 ethtool -l ens1f1
Например у меня в сервере стояло два процессора e5-2680 по 8 ядер, двух портовая сетевая плата HP 562SFP+ была в numa0 первого процессора и irqbalance распределил 16 прерываний обеих сетевых интерфейсов на 7 ядер первого процессора, кроме 0 ядра.
Поэтому я сначала указал вручную 8 прерываний вместо 16:
ethtool -L ens1f0 combined 8 ethtool -L ens1f1 combined 8
Приступим к настройке RSS. Назначить прерывание сетевого интерфейса на определенное ядро процессора можно так (где «X» — номер прерывания который отображается в первом столбце /proc/interrupts, а «N» — маска процессора):
echo N > /proc/irq/X/smp_affinity
Я посмотрел в таблице номера прерываний сетевых интерфейсов:
cat /proc/interrupts
Посмотрел как распределил нагрузку irqbalance для первого порта сетевой платы (ens1f0):
cat /proc/irq/47/smp_affinity cat /proc/irq/48/smp_affinity cat /proc/irq/49/smp_affinity cat /proc/irq/50/smp_affinity cat /proc/irq/51/smp_affinity cat /proc/irq/52/smp_affinity cat /proc/irq/53/smp_affinity cat /proc/irq/54/smp_affinity
Отобразилось:
00000000,00000004 00000000,00000002 00000000,00000020 00000000,00000010 00000000,00000008 00000000,00000020 00000000,00000040 00000000,00000080
Как распределил нагрузку irqbalance для второго порта сетевой платы (ens1f1):
cat /proc/irq/75/smp_affinity cat /proc/irq/76/smp_affinity cat /proc/irq/77/smp_affinity cat /proc/irq/78/smp_affinity cat /proc/irq/79/smp_affinity cat /proc/irq/80/smp_affinity cat /proc/irq/81/smp_affinity cat /proc/irq/82/smp_affinity
Отобразилось:
00000000,00000008 00000000,00000002 00000000,00000008 00000000,00000008 00000000,00000004 00000000,00000020 00000000,00000040 00000000,00000080
Можно еще посмотреть так PCI address of 0000:04:00.0:
ls -1 /sys/devices/*/*/0000:04:00.0/msi_irqs
Как видим через RSS irqbalance в моем случае распределил нагрузку криво, хотя на zabbix графиках нагрузка было примерно ровная, но простаивало 0 ядро.
Маску процессора можно определить используя bc по формуле:
apt install bc echo "obase=16; $[2 ** $cpuN]" | bc
Например посчитаем для восьми ядер:
echo "obase=16; $[2** 0]" | bc echo "obase=16; $[2** 1]" | bc echo "obase=16; $[2** 2]" | bc echo "obase=16; $[2** 3]" | bc echo "obase=16; $[2** 4]" | bc echo "obase=16; $[2** 5]" | bc echo "obase=16; $[2** 6]" | bc echo "obase=16; $[2** 7]" | bc
У меня получилось:
1
2
4
8
10
20
40
80
Перед изменениями обязательно остановим irqbalance и уберем из автозапуска при старте системы, так как он начнет возвращать свои значения:
systemctl is-enabled irqbalance systemctl disable irqbalance service irqbalance status service irqbalance stop
Соответственно я выполнил команды ниже, чтобы привязать по 8 прерываний обеих сетевых интерфейсов к 8 ядрам процессора:
echo 1 > /proc/irq/47/smp_affinity echo 2 > /proc/irq/48/smp_affinity echo 4 > /proc/irq/49/smp_affinity echo 8 > /proc/irq/50/smp_affinity echo 10 > /proc/irq/51/smp_affinity echo 20 > /proc/irq/52/smp_affinity echo 40 > /proc/irq/53/smp_affinity echo 80 > /proc/irq/54/smp_affinity echo 1 > /proc/irq/75/smp_affinity echo 2 > /proc/irq/76/smp_affinity echo 4 > /proc/irq/77/smp_affinity echo 8 > /proc/irq/78/smp_affinity echo 10 > /proc/irq/79/smp_affinity echo 20 > /proc/irq/80/smp_affinity echo 40 > /proc/irq/81/smp_affinity echo 80 > /proc/irq/82/smp_affinity
Нагрузка на ядра стала чуть ровнее чем в случае с irqbalance.
Посмотрим как настроен RPS (Receive Packet Steering — программный аналог аппаратного RSS), у меня по умолчанию отобразилось 00000000,00000000:
cat /sys/class/net/ens1f0/queues/*/rps_cpus cat /sys/class/net/ens1f1/queues/*/rps_cpus
RPS я решил включить, например чтобы очередь обрабатывалась на любом из 8 ядер, можно указать ff:
echo "ff" > /sys/class/net/ens1f0/queues/rx-0/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-1/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-2/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-3/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-4/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-5/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-6/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-7/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-0/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-1/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-2/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-3/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-4/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-5/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-6/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-7/rps_cpus
Чтобы на любом из 4 укажем f:
echo "f" | tee /sys/class/net/eth0/queues/rx-[0-3]/rps_cpus
После этого прерывания распределились еще ровнее, softirq нагрузка на Zabbix графиках шла у каждого ядра почти в одну линию.

Чтобы изменения не сбросились после перезапуска системы — добавим команды в /etc/rc.local:
/sbin/ethtool -L ens1f0 combined 8 /sbin/ethtool -L ens1f1 combined 8 echo 1 > /proc/irq/47/smp_affinity echo 2 > /proc/irq/48/smp_affinity echo 4 > /proc/irq/49/smp_affinity echo 8 > /proc/irq/50/smp_affinity echo 10 > /proc/irq/51/smp_affinity echo 20 > /proc/irq/52/smp_affinity echo 40 > /proc/irq/53/smp_affinity echo 80 > /proc/irq/54/smp_affinity echo 1 > /proc/irq/75/smp_affinity echo 2 > /proc/irq/76/smp_affinity echo 4 > /proc/irq/77/smp_affinity echo 8 > /proc/irq/78/smp_affinity echo 10 > /proc/irq/79/smp_affinity echo 20 > /proc/irq/80/smp_affinity echo 40 > /proc/irq/81/smp_affinity echo 80 > /proc/irq/82/smp_affinity echo "ff" > /sys/class/net/ens1f0/queues/rx-0/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-1/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-2/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-3/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-4/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-5/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-6/rps_cpus echo "ff" > /sys/class/net/ens1f0/queues/rx-7/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-0/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-1/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-2/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-3/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-4/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-5/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-6/rps_cpus echo "ff" > /sys/class/net/ens1f1/queues/rx-7/rps_cpus
Смотрите также мои статьи:
Настройка сети в Linux
Как узнать на каких NUMA node сетевые интерфейсы
Как отличить физические ядра процессора от виртуальных
Мониторинг использования CPU в Zabbix
Мониторинг PPS (Packets Per Second) в Zabbix