...

Jak prawidłowo skonfigurować IRQ Balance w systemie Linux: praktyczny przewodnik

W systemie Linux funkcja IRQ Balance kontroluje rozkład przerwań sprzętowych między rdzeniami procesora, decydując tym samym, czy obciążenie sieciowe jest rozłożone równomiernie, czy też poszczególne rdzenie spowalniają działanie systemu. Pokażę Ci, jak celowo wykorzystywać irqbalance, kiedy przechodzę na ręczne przypisywanie IRQ oraz jakie ustawienia stosować na serwerach o wysokim obciążenie sieci naprawdę mają znaczenie.

Punkty centralne

Zanim przejdę do szczegółów, podsumuję najważniejsze decyzje, które niezawodnie pomogły mi w projektach o dużym obciążeniu wejścia/wyjścia. Uważam, że dobrym punktem wyjścia jest automatyczny podział za pomocą irqbalance, następnie mierzę jego skuteczność i wprowadzam selektywne dostosowania. W przypadku obciążeń deterministycznych ręcznie przypisuję poszczególne sygnały IRQ do określonych rdzeni i wykluczam pozostałe procesory z automatycznego podziału. Wcześnie uwzględniam bliskość NUMA, ponieważ zmniejsza ona opóźnienia i zapewnia przepustowość. Dzięki przejrzystemu monitorowaniu szybciej wykrywam wąskie gardła i reguluję je bez zbędnych Ryzyko.

Ta lista pokazuje, na co zwracam szczególną uwagę podczas konfiguracji:

  • Automatyczny Najpierw: włączyć irqbalance, zmierzyć efekt
  • Affinität ukierunkowane: zablokowanie krytycznych sygnałów IRQ, zmniejszenie jittera
  • Zablokowane procesory: Zarezerwuj jądra dla wątków aplikacji
  • NUMA Uwaga: należy utrzymywać sygnały IRQ w pobliżu węzła pamięci
  • Monitoring: Sprawdź /proc/interrupts i opóźnienia

Podstawy IRQ w skrócie

Żądanie przerwania (IRQ) to sygnał, za pomocą którego sprzęt przekazuje zadanie do procesora, przerywając w ten sposób bieżące zadanie. Jeśli zbyt wiele takich sygnałów trafi do tego samego rdzenia, wzrasta jego obciążenie, a czas reakcji wydłuża się, podczas gdy inne rdzenie pozostają niewykorzystane; właśnie to chcę osiągnąć za pomocą Dystrybucja uniknąć. Moduł irqbalance dynamicznie rozdziela te IRQ między kilka rdzeni i w regularnych odstępach czasu ocenia stan systemu. Najpierw sprawdzam /proc/interrupts i sprawdź w kolumnach, ile sygnałów IRQ dociera na każdy procesor. Jeśli w poszczególnych kolumnach pojawia się zbyt duża liczba sygnałów, aktywnie reguluję ten poziom, redukując w ten sposób niepotrzebne Hotspoty.

Automatyczny rozkład obciążenia za pomocą irqbalance

W nowoczesnych dystrybucjach uruchamiam usługę irqbalance, która domyślnie okresowo dostosowuje rozkład sygnałów IRQ. Włączam ją ręcznie za pomocą systemctl enable --now irqbalance i sprawdzam stan, zanim podejmę bardziej zdecydowane działania; w ten sposób wykorzystuję to, co mam Automatyczny. Pliki konfiguracyjne znajdują się, w zależności od systemu, w /etc/sysconfig/irqbalance lub /etc/default/irqbalance, gdzie mogę wykluczyć procesory lub sygnały IRQ. Szczególnie pomocna jest zmienna IRQBALANCE_BANNED_CPUS jako maska 64-bitowa, służąca do rezerwowania określonych rdzeni dla aplikacji. Osoby, które chcą zgłębić praktyczne przykłady, znajdą tutaj zwięzłe wprowadzenie do Wydajność sieci, do których często odwołuję się podczas warsztatów i które wykorzystuję w projektach.

Jak bezpiecznie skonfigurować ręczne przypisanie IRQ

Jeśli obciążenia są bardzo wrażliwe na wahania lub jeśli określone jądra mają pozostać zarezerwowane wyłącznie dla procesów przestrzeni użytkownika, ręcznie ustawiam przypisanie IRQ. W tym celu zapisuję maski bitowe zgodnie z /proc/irq/NUMER IRQ/smp_affinity oraz określam, na których jądrach może być uruchamiane przerwanie; zapewnia to możliwość planowania Prowadzenie. Najpierw ustalam odpowiednie numery IRQ za pomocą grep w /proc/interrupts. W przypadku urządzeń sieciowych często przypisuję kolejki RX/TX do rdzeni znajdujących się blisko wątków aplikacji, pozostawiając inne rdzenie wolne. Dobry przegląd uzasadnień tego podejścia zawiera ten krótki Przewodnik po powiązaniach IRQ, z którego regularnie korzystam jako punkt wyjścia.

Poniższa tabela przedstawia popularne maski bitowe oraz ich znaczenie. Korzystam z tych przykładów, aby szybko i bezbłędnie wprowadzać konfiguracje, a następnie sprawdzać ich działanie za pomocą /proc/interrupts do zweryfikować.

Cel Przykładowy szablon (hex) jądra Komentarz
Tylko procesor 0 0x1 0 Prosty test, niewielkie rozproszenie
Tylko procesor 1 0x2 1 Oddziela sygnały IRQ od procesora CPU0, zmniejsza Interferencja
CPU0–CPU1 0x3 0–1 Rozłożone na dwa rdzenie, lekkie Ulga
CPU2–CPU3 0xC 2-3 Przydatne, gdy 0–1 dotyczy wątków aplikacji darmowy pobyt
CPU0–CPU3 0xF 0–3 Szerokie rozłożenie na 4 rdzenie, mieszanie Obciążenie

Pomiar: Prawidłowe odczytywanie /proc/interrupts

Otwieram plik /proc/interrupts i widzę po jednym IRQ na wiersz oraz liczniki dla poszczególnych procesorów w kolumnach; to od razu ujawnia nierównowagi widoczny. Jeśli jedna kolumna rośnie znacznie szybciej niż pozostałe, obciążenie skupia się właśnie tam. Wtedy sprawdzam, który sterownik ma w tym udział i czy RSS/RPS już rozdziela obciążenie. Dodatkowo uruchamiam tymczasowo irqbalance w tle z wyjściem debugowania, aby zrozumieć jego decyzje i uniknąć błędnych ocen. Po każdej zmianie ponownie sprawdzam liczniki i mierzę opóźnienia pod obciążeniem, aby móc potwierdzić efekty i uniknąć niepotrzebnych Ryzyko można tego uniknąć.

Izolacja procesora i maski zakazane

Ustawiłem IRQBALANCE_BANNED_CPUS, aby konsekwentnie wykluczyć określone jądra z automatycznego przydzielania; w ten sposób rezerwuję zasoby dla wątków aplikacji. W nowszych konfiguracjach korzystam dodatkowo z IRQBALANCE_BANNED_IRQS, jeśli poszczególne urządzenia mają działać samodzielnie na jednym jądrze; zmniejsza to zakłócenia w przypadku wrażliwych Obciążenia. W scenariuszach wymagających niskiego opóźnienia celowo wyłączam funkcję irqbalance i statycznie przypisuję sygnały IRQ, aby nie zakłócało tego ponowne przydzielanie. Ci, którzy chcą dokładniej zrozumieć sposób przypisywania obsługi przerwań przez procesor, znajdą przydatne informacje na temat Obsługa przerwań na serwerach. Najważniejsze jest to, aby najpierw dokonać pomiarów, następnie ustalić parametry i ponownie sprawdzić efekt, aby uniknąć niespodzianek w Działanie których należy unikać.

Aspekty NUMA i bliskość

W systemach NUMA staram się kierować sygnały IRQ w miarę możliwości do jąder tego węzła NUMA, w pamięci którego znajdują się dane, których to dotyczy; zmniejsza to opóźnienie i zwiększa Przepustowość. Łączę to z afynacją procesora dla aplikacji, aby wątki i przerwania działały lokalnie względem siebie. irqbalance działa dobrze w środowisku NUMA, ale w razie potrzeby dostosowuję ustawienia za pomocą masek zakazanych. Kluczowe jest, aby nie rozpraszać obciążenia między węzłami, jeśli i tak można je utrzymać lokalnie. Kto zachowa tę bliskość, zyska stałe czasy odpowiedzi i oszczędzi cenne Schowek-zasoby.

Intensywny kurs dotyczący sieci: RSS, RPS/RFS i XPS

Zanim dopracuję maski IRQ, sprawdzam funkcje karty sieciowej, takie jak RSS, a także mechanizmy jądra, takie jak RPS/RFS i XPS; mają one duży wpływ na rozdzielanie pakietów. RSS rozdziela przerwania kolejki już między kilka jąder, podczas gdy RPS/RFS kształtują przetwarzanie w jądrze, a XPS – ścieżki transmisji; pozwala to uniknąć niepotrzebnych Hotspoty. Dostosowuję te mechanizmy do mojej strategii IRQ, aby nie działały one w sprzeczności. Jeśli kolejki, preferencje IRQ i preferencje aplikacji są ze sobą zgrane, operacje wejścia/wyjścia sieciowego przebiegają znacznie płynniej. Następnie ponownie dokonuję pomiarów pod rzeczywistym obciążeniem, zanim podejmę dalsze Kroki postawię.

MSI-X, Multi-Queue i przejrzysty układ kolejki

Wiele kart sieciowych 10–100G wykorzystuje technologię MSI-X i udostępnia osobne wektory przerwań dla każdej kolejki RX/TX. Najpierw sprawdzam za pomocą ethtool -l eth0 (liczba kanałów) oraz /proc/interrupts, ile kolejek jest faktycznie aktywnych i jak się nazywają (np. eth0‑TxRx‑0, eth0-TxRx-1). Celem jest dostosowanie liczby kolejek do liczby wykorzystywanych rdzeni na węzeł NUMA oraz deterministyczne przypisanie ich do tych rdzeni. Za pomocą ethtool -L eth0 combined N ustawiam liczbę kolejek; następnie porządkuję generowane sygnały IRQ za pomocą smp_affinity odpowiednich rdzeni. Dbam o to, aby pary RX/TX z tej samej kolejki były przypisane do tego samego rdzenia lub przynajmniej do tego samego gniazda, tak aby Lokalizacja pamięci podręcznej działa. Ważne: zmiany liczby kolejek i powinowactwa sprawdzam bezpośrednio w /proc/interrupts oraz przeprowadzając krótki test obciążenia (pps/przepustowość), zanim przystąpię do dalszej optymalizacji.

Koalescencja przerwań i budżet NAPI

Szczególnie przy wysokich częstotliwościach pakietów wartości koalescencji wpływają na skuteczność mojej strategii IRQ. Przy ethtool -c eth0 widzę, czy rx-mikrosekund oraz oprawki rx są ustawione. Większa koalescencja zmniejsza liczbę sygnałów IRQ na sekundę i odciąża procesor, ale zwiększa opóźnienie i wahania. Dokonuję ostrożnych regulacji: małe kroki, po każdym pomiar (opóźnienie p95/p99 i obciążenie procesora). Po stronie nadawczej działa tx-usecs analogowo. Ponadto skaluję zachowanie NAPI poprzez net.core.netdev_budget oraz net.core.netdev_budget_usecs, kiedy NET_RX zaczynają się gromadzić w SoftIRQ. Jeśli liczba utraty pakietów wzrasta w /proc/net/softnet_stat, w ramach testu zwiększam budżet lub bardziej konsekwentnie rozdzielam kolejki RX; jeśli opóźnienie systemu staje się uciążliwe, zmniejszam te wartości. GRO/LRO oraz TSO/GSO uwzględniam w kontekście wzajemnego oddziaływania: nadmierna agregacja zmniejsza obciążenie IRQ, ale może powodować skoki opóźnień – równoważę je za pomocą profilu aplikacji.

Przejrzyste odczytywanie SoftIRQ

Oprócz twardych przerwań (HardIRQ) decyduję również o obciążeniu w miękkich przerwaniach (SoftIRQ). Za pomocą cat /proc/softirqs Obserwuję NET_RX oraz NET_TX na procesor; jeśli niektóre kolumny dominują, zbyt wiele pracy trafia właśnie tam, do wątków ksoftirqd. Jeden top -H pokaż mi szybko, które ksoftirqd/N Obciążam rdzenie. Mierzę głębiej za pomocą perf top lub krótkich rekord wydajności Uruchamia się, aby zidentyfikować wąskie gardła w sterowniku lub przetwarzaniu stosu. Gdy aktywowane są wątki ksoftirqd (zamiast bezpośredniej obsługi w kontekście IRQ), opóźnienie często znacznie wzrasta; reaguję na to lepszym rozłożeniem kolejek, zwiększeniem budżetu NAPI lub celowym przypisaniem procesora do konkretnych wątków ksoftirqd za pomocą taskset -pc. Ważne: Dokumentuję te zmiany, ponieważ są one subtelne i w razie wątpliwości muszę mieć możliwość szybkiego przywrócenia poprzedniego stanu.

Właściwe wykorzystanie technologii SMT/Hyper-Threading i topologii

Gdy funkcja SMT jest aktywna, dzielę jedno fizyczne jądro z dwoma procesorami logicznymi. Sprawdzam relacje między procesorami za pomocą lscpu -e oraz /sys/devices/system/cpu/cpuX/topology/thread_siblings_list. W przypadku ścieżek, w których opóźnienie ma kluczowe znaczenie, unikam umieszczania wątku aplikacji i powiązanego IRQ na tym samym rdzeniu fizycznym (różne wątki SMT); konkurują one bowiem o jednostki wykonawcze i pamięci podręczne. Preferuję pary, w których np. wątek aplikacji działa na procesorze CPU2, a powiązana z nim kolejka RX na procesorze CPU3 (inne rdzenie fizyczne, ten sam węzeł NUMA). Jeśli SMT zakłóca spójność, planuję zamiast tego z mniejszą liczbą, ale wyłącznych rdzeni fizycznych i oszczędzam sobie niepokoju Zakłócenia.

Wirtualizacja: KVM, vhost i SR-IOV

W środowiskach wirtualnych rozpatruję host i gościa osobno. Na hoście równomiernie rozdzielam fizyczne sygnały IRQ kart sieciowych między jądra odpowiedniego węzła NUMA. Jeśli gość korzysta z wirtualnej sieci (virtio-net), powstają dodatkowe sygnały IRQ dla wątków vhost; rozpoznaję je w /proc/interrupts i przypisuję procesy robocze vhost spójnie z kolejkami fizycznej karty sieciowej. Na poziomie gościa ustawiam również preferencje RSS/XPS i IRQ, o ile sterownik virtio udostępnia kilka kolejek. W przypadku SR-IOV warto przypisać każdemu systemowi-gościowi jedną lub więcej VF z własnymi wektorami MSI-X i przypiąć je w systemie-gościu; izolacja poprawia opóźnienia i przewidywalność. Trzymam się jasnego schematu: vCPU systemu gościnnego na dedykowanych pCPU, powiązane IRQ na pobliskich rdzeniach, a wątki emulatora/vhost nie powinny mieszać się z wątkami aplikacji wymagającymi intensywnych obliczeń – w ten sposób ścieżka danych pozostaje możliwy do zaplanowania.

Częstotliwość procesora, stany C i tuning NOHZ

Opóźnienia IRQ ulegają pogorszeniu, gdy jądra przechodzą w głębokie stany C lub są agresywnie taktowane. W przypadku wrażliwych obciążeń ustawiam regulator procesora na Wykonanie (cpupower frequency‑set -g performance) oraz ograniczam głębokie stany C za pomocą opcji rozruchu lub sterowników, aby skrócić czas budzenia. Na serwerach o dużym obciążeniu często przynosi to lepsze efekty niż jakiekolwiek precyzyjne dostrajanie afiliacji. W przypadku bardzo wymagających profili opóźnień dodaję nohz_full= oraz rcu_nocbs= dla izolowanych jąder, tak aby zegar „Tick-Timer” i wywołania zwrotne RCU nie zakłócały się wzajemnie; procesory zarządzające (Housekeeping-CPU) definiuję celowo oddzielnie. Te zmiany testuję jednak osobno, ponieważ mogą one wywierać skutki uboczne na planowanie zadań i pobór energii. Najważniejsze pozostaje: dokładne porównanie wartości pomiarowych przed i po zmianie, w przeciwnym razie będę się błąkał w ciemno Optymalizacje w ciemności.

Systemd, Cgroups i izolacja aplikacji

Oprócz przypisywania IRQ oddzielam wątki aplikacji za pomocą Cgroups i systemd-Affinity. Za pomocą CPUAffinity= W plikach Unit oraz w kontrolerach procesorów (cgroup v2) przypisuję usługom stałe jądra. W ten sposób zapobiegam przenoszeniu wątków przez harmonogram na te procesory, które przeznaczyłem na przerwy IRQ. W środowiskach kontenerowych ustawiam cpuset.cpus i sprawdzić cpuset.cpus.effective, aby obietnice dotyczące zasobów rzeczywiście przyniosły efekty. Ważne: IRQBALANCE_BANNED_CPUS kieruje tylko tam, gdzie irqbalance nie rozdziela zadań; wątki jądra, takie jak ksoftirqd, nadal podlegają harmonogramowi. Aby uzyskać ścisłą izolację, potrzebuję zatem połączenia powinowactw IRQ, powinowactwa procesora usług oraz, w razie potrzeby, izolowanych jąder. W ten sposób ścieżka danych i aplikacja pozostają wyraźnie oddzielone, a Obciążenie nie miesza się w sposób niekontrolowany.

Typowe błędy i sposoby ich uniknięcia

Nigdy nie wyłączam funkcji irqbalance w sposób ogólny, nie znając rozkładu obciążenia; w przeciwnym razie sygnały IRQ szybko skupiają się na kilku rdzeniach. Równie niekorzystne jest udostępnianie wszystkich rdzeni dla wszystkich sygnałów IRQ, mimo że wrażliwe wątki mają wyłączność Zasoby potrzebne. Kolejny błąd: brak izolowanego testowania zmian i pomiaru ich skutków; w ten sposób nie wiadomo, co faktycznie pomaga. Uwzględniam również pary w technologii Hyper-Threading: wątek aplikacji i powiązane IRQ nie powinny dzielić tego samego fizycznego rdzenia. Dokumentuję każdy krok i tworzę punkty przywracania, aby w razie problemów móc szybko powrócić do ostatniego dobry Wróć do konfiguracji.

Lista kontrolna dotycząca serwerów

Zawsze zaczynam od ustalenia stanu początkowego: włączam irqbalance, rejestruję obciążenie systemu, obserwuję katalog /proc/interrupts i mierzę opóźnienia; dopiero potem przystępuję do zmiany ustawień. W drugim kroku kończę, wykonując IRQBALANCE_BANNED_CPUS wybieram te jądra, które mają pozostać zarezerwowane dla wątków aplikacji; w ten sposób zapobiegam niepotrzebnym zakłóceniom spowodowanym przez IRQ. Następnie przypisuję krytyczne IRQ za pomocą smp_affinity na kilka dobrze dobranych rdzeni i zachowuję bliskość NUMA. Następnie sprawdzam wskaźniki RSS/RPS/RFS i XPS, a także opcje odciążania karty sieciowej (NIC), aby sensownie rozdzielić obciążenie. Na koniec przeprowadzam testy pod obciążeniem produkcyjnym, porównuję wskaźniki i zachowuję tylko te zmiany, które w sposób widoczny praca.

Pliki konfiguracyjne i polecenia systemd

Aktywuję tę usługę za pomocą systemctl enable --now irqbalance i sprawdź za pomocą systemctl status irqbalance czas trwania; tak więc ustawiam Usługa na pewno gotowe. W /etc/sysconfig/irqbalance lub /etc/default/irqbalance stawiam IRQBALANCE_BANNED_CPUS oraz opcjonalnie IRQBALANCE_BANNED_IRQS. Zmiany wprowadzam za pomocą systemctl restart irqbalance i jednocześnie obserwuję liczniki w /proc/interrupts. Do testów korzystam z trybu foreground programu irqbalance, aby na bieżąco śledzić podejmowane decyzje. Dopiero gdy zrozumiem to zachowanie, wprowadzam zmiany na stałe do pliku Konfiguracja.

Kiedy wyłączam irqbalance

W konfiguracjach działających w czasie rzeczywistym lub w przypadku aplikacji wyjątkowo wrażliwych na opóźnienia zatrzymuję usługę irqbalance i statycznie przypisuję sygnały IRQ, aby żadna redystrybucja nie zakłócała działania. Izoluję jądra dla tych obciążeń i celowo kieruję sygnały IRQ związane z ruchem sieciowym na inne jądra; dzięki temu wątki aplikacji pozostają możliwy do zaplanowania. Nawet w przypadku ściśle oddzielonych środowisk dzierżawców takie podejście się opłaca, ponieważ pozwala mi ograniczyć zakłócenia między maszynami wirtualnymi lub kontenerami. Jeśli pojawiają się sterowniki, które gorzej współpracują z automatyką, wykluczam ich sygnały IRQ za pomocą listy zablokowanych. Gdy wzorce obciążenia znów staną się bardziej zróżnicowane, ponownie włączam irqbalance i sprawdzam efekt przy pomocy świeżych Zmierzone wartości.

Krótkie podsumowanie

Zaczynam od irqbalance, oceniam efekt i wprowadzam selektywne poprawki, zamiast wtrącać się na oślep wszędzie; w ten sposób zachowuję całościowy obraz systemu i Przejrzystość. W przypadku wrażliwych obciążeń przypisuję odpowiednie numery IRQ, izoluję jądra dla poszczególnych aplikacji i uwzględniam bliskość NUMA. Za pomocą masek zakazu kontroluję, gdzie może działać irqbalance, i zapobiegam niepożądanym przesunięciom. Regularnie sprawdzam /proc/interrupts, opóźnienia i przepustowość, aby zmiany były poparte wiarygodnymi danymi. Kto postępuje w ten sposób, w pełni wykorzystuje potencjał IRQ Balance i zapewnia, że serwery pod obciążeniem sieciowym działają zauważalnie reaktywny.

Artykuły bieżące