Load balancing в OpenWrt

Цей посібник пояснює, як вручну реалізувати балансування навантаження (Load balancing) в OpenWrt, закріплюючи переривання (IRQ) за певними Ethernet-портами та призначаючи один або кілька ядер CPU для обробки мережевих черг.

З джерела: https://www.kernel.org/doc/html/latest/core-api/irq/irq-affinity.html

`/proc/irq/IRQ#/smp_affinity` і `/proc/irq/IRQ#/smp_affinity_list` визначають, які CPU дозволені для певного джерела переривань (IRQ). Це бітова маска (`smp_affinity`) або список CPU (`smp_affinity_list`). Заборонено відключати всі CPU одразу. Якщо контролер IRQ не підтримує afініті (affinity), значення не змінюється і залишається за замовчуванням — усі CPU.

`/proc/irq/default_smp_affinity` визначає маску спорідненості (affinity) за замовчуванням, яка застосовується до всіх неактивних IRQ. Після активації IRQ його бітова маска спорідненості буде встановлена в значення за замовчуванням. Її потім можна змінити, як описано вище. Маска за замовчуванням — `0xffffffff`.

Щоб призначити IRQ конкретному CPU або групі CPU, потрібно використовувати бітову маску. Для цього вмикаємо потрібні CPU у двійковому представленні та перетворюємо це число у шістнадцяткове. Це дозволяє обмежити обробку певних IRQ певними ядрами CPU — для досягнення балансування або в гетерогенних SoC, наприклад, при розподілі між продуктивними та енергоефективними ядрами.

Бітові маски для CPU:

Бінарне Hex CPU-ядра
00000001 1 0
00000010 2 1
00000011 3 0,1
00000100 4 2
00000101 5 0,2
00000110 6 1,2
00000111 7 0,1,2
00001000 8 3
00001001 9 0,3
00001010 A 1,3
00001011 B 0,1,3
00001100 C 2,3
00001101 D 0,2,3
00001110 E 1,2,3
00001111 F 0,1,2,3
00110000 30 4,5

У OpenWrt за замовчуванням використовується підтримка багатоядерної обробки (SMP).

Наступні скрипти відповідають за ці налаштування:

cat /etc/hotplug.d/net/20-smp-packet-steering
cat /etc/hotplug.d/net/40-net-smp-affinity

Більш автоматизоване рішення — використання irqbalance:

irqbalance — це демон для Linux, що розподіляє апаратні переривання між логічними ядрами процесора. Його мета — покращення загальної продуктивності, що дозволяє рівномірніше розподіляти навантаження та оптимізувати енергоспоживання.

Однак `irqbalance` не завжди забезпечує передбачуваний розподіл навантаження. Тому краще використовувати ручне налаштування для точнішого контролю над балансуванням.

Насамперед потрібно знайти та ідентифікувати активні переривання.

Щоб переглянути поточні налаштування або зміни:

cat /proc/interrupts

Нижче наведено приклад з NanoPi R4S, який має 4 ядра A53 (CPU 0–3) і 2 ядра A72 (CPU 4 і 5):

root@OpenWrt:~# cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5
 23:   27142318   12185540    5391618    2352924  137831569  145154023     GICv3  30 Level     arch_timer
 25:   67873664   61308794   11619382    2662637   16876546   43550490     GICv3 113 Level     rk_timer
 26:          0          0          0          0          0          0  GICv3-23   0 Level     arm-pmu
 27:          0          0          0          0          0          0  GICv3-23   1 Level     arm-pmu
 28:          0          0          0          0          0          0     GICv3  37 Level     ff6d0000.dma-controller
 29:          0          0          0          0          0          0     GICv3  38 Level     ff6d0000.dma-controller
 30:          0          0          0          0          0          0     GICv3  39 Level     ff6e0000.dma-controller
 31:          0          0          0          0          0          0     GICv3  40 Level     ff6e0000.dma-controller
 32:          1          0          0          0          0          0     GICv3  81 Level     pcie-sys
 34:          0          0          0          0          0          0     GICv3  83 Level     pcie-client
 35:          0          0          0          0  165575364          0     GICv3  44 Level     eth0
 36:   20438175          0          0          0          0          0     GICv3  97 Level     dw-mci
 37:          0          0          0          0          0          0     GICv3  58 Level     ehci_hcd:usb1
 38:          0          0          0          0          0          0     GICv3  60 Level     ohci_hcd:usb3
 39:          0          0          0          0          0          0     GICv3  62 Level     ehci_hcd:usb2
 40:          0          0          0          0          0          0     GICv3  64 Level     ohci_hcd:usb4
 42:          0          0          0          0          0          0     GICv3  91 Level     ff110000.i2c
 43:          6          0          0          0          0          0     GICv3  67 Level     ff120000.i2c
 44:          0          0          0          0          0          0     GICv3  68 Level     ff160000.i2c
 45:          6          0          0          0          0          0     GICv3 132 Level     ttyS2
 46:          0          0          0          0          0          0     GICv3 129 Level     rockchip_thermal
 47:    6393498          0          0          0          0          0     GICv3  89 Level     ff3c0000.i2c
 50:          0          0          0          0          0          0     GICv3 147 Level     ff650800.iommu
 52:          0          0          0          0          0          0     GICv3 149 Level     ff660480.iommu
 56:          0          0          0          0          0          0     GICv3 151 Level     ff8f3f00.iommu
 57:          0          0          0          0          0          0     GICv3 150 Level     ff903f00.iommu
 58:          0          0          0          0          0          0     GICv3  75 Level     ff914000.iommu
 59:          0          0          0          0          0          0     GICv3  76 Level     ff924000.iommu
 69:          0          0          0          0          0          0     GICv3  59 Level     rockchip_usb2phy
 70:          0          0          0          0          0          0     GICv3 137 Level     xhci-hcd:usb5
 71:          0          0          0          0          0          0     GICv3 142 Level     xhci-hcd:usb7
 72:          0          0          0          0          0          0  rockchip_gpio_irq  21 Level     rk808
 78:          0          0          0          0          0          0     rk808   5 Edge      RTC alarm
 82:          0          0          0          0          0          0  rockchip_gpio_irq   7 Edge      fe320000.mmc cd
 84:          0          0          0          0          0          0   ITS-MSI   0 Edge      PCIe PME, aerdrv
 85:         10          0          0          0          0          0  rockchip_gpio_irq  10 Level     stmmac-0:01
 86:          0          0          0          0          0          0  rockchip_gpio_irq  22 Edge      gpio-keys
 87:          0          0          0          0          0 1156859750   ITS-MSI 524288 Edge      eth1
IPI0:   7085496   10371429    7027071    6124604     310818     114897       Rescheduling interrupts
IPI1:   2817025    2457651     882759     515246    2752519     543745       Function call interrupts
IPI2:         0          0          0          0          0          0       CPU stop interrupts
IPI3:         0          0          0          0          0          0       CPU stop (for crash dump) interrupts
IPI4:   5558568    4633615    2762056    1122565     763629    3435183       Timer broadcast interrupts
IPI5:    413711     300799     161541     117511     109020      76881       IRQ work interrupts
IPI6:         0          0          0          0          0          0       CPU wake-up interrupts
Err:          0

Щоб знайти IRQ для ваших Ethernet-інтерфейсів, використовуйте:

grep eth /proc/interrupts

Приклад:

root@OpenWrt:~# grep eth /proc/interrupts
 35:          0          0          0          0  165661665          0     GICv3  44 Level     eth0
 87:          0          0          0          0          0 1157284700   ITS-MSI 524288 Edge      eth1

Отже, тут `eth0` — це IRQ 35, а `eth1` — IRQ 87.

Одне переривання (IRQ) можна прив’язати лише до одного ядра CPU.

Прив’язка переривань до ядер CPU

Призначити переривання від `eth0` ядру CPU 0:

echo 1 > /proc/irq/35/smp_affinity

Призначити переривання від `eth1` ядру CPU 1:

echo 2 > /proc/irq/87/smp_affinity

Автоматичне визначення IRQ для інтерфейсу:

# IRQ для eth0:
echo f > /proc/irq/$(grep eth0 /proc/interrupts | awk -F ':' '{print $1}' | xargs)/smp_affinity
 
# IRQ для eth1:
echo f > /proc/irq/$(grep eth1 /proc/interrupts | awk -F ':' '{print $1}' | xargs)/smp_affinity

Команда `grep` знаходить рядок із `/proc/interrupts`, `awk` витягує перший стовпчик (номер IRQ), а `xargs` прибирає зайві пробіли.

У ядрах Linux версії 5.15 і новіших потрібно використовувати:

echo -n #HEX# > /proc/irq/#НОМЕР_IRQ#/smp_affinity

Якщо ви перезапустите Smart Queue Management (SQM) або зміните його налаштування, це скине прив’язку переривань до CPU. Вам потрібно повторно застосувати налаштування вручну.

Джерело: Receive Packet Steering (RPS)

Receive Packet Steering (RPS) подібний до Receive Side Scaling (RSS) тим, що дозволяє скеровувати пакети на певні ядра CPU для обробки. Але RPS реалізований програмно, що дозволяє уникнути перенавантаження апаратної черги одного мережевого інтерфейсу, яка могла б стати “вузьким місцем” при великому трафіку.

Мережеві черги можуть бути розподілені між усіма ядрами CPU або ж прив’язані до одного ядра.

Призначити чергу eth0 ядру 3:

echo 4 > /sys/class/net/eth0/queues/rx-0/rps_cpus

Призначити чергу eth1 ядру 4:

echo 8 > /sys/class/net/eth1/queues/rx-0/rps_cpus

Призначити черги eth0 та eth1 всім 6 ядрам:

echo 3f > /sys/class/net/eth0/queues/rx-0/rps_cpus
echo 3f > /sys/class/net/eth1/queues/rx-0/rps_cpus

Ви можете або відредагувати існуючий скрипт:

cat /etc/hotplug.d/net/40-net-smp-affinity

Або створити власний скрипт із новими значеннями, і помістити його в каталог:

/etc/hotplug.d/net/

Приклад:

# /etc/hotplug.d/net/50-mysettings-for-net-smp-affinity
 
# Призначення переривань
# eth0 → ядро 0
echo 1 > /proc/irq/35/smp_affinity
 
# eth1 → ядро 2
echo 2 > /proc/irq/87/smp_affinity
 
# RPS: використовувати всі ядра (0–5)
echo 3f > /sys/class/net/eth0/queues/rx-0/rps_cpus
echo 3f > /sys/class/net/eth1/queues/rx-0/rps_cpus

Тепер перезавантажте пристрій і перевірте, чи збереглися налаштування.

Подяка за обговорення та внесок:

  • mercygroundabyss
  • moeller0
  • walmartshopper
  • xShARkx

Джерела/тематики обговорень:

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2025/05/31 11:57
  • by vazaz