Skalowanie po stronie odbiorczej rozdziela ruch sieciowy na łączach 10 i 25 Gbit/s między kilka rdzeni, dzięki czemu serwery z systemem Linux mogą osiągać wysoką przepustowość przy niskim opóźnieniu. Pokażę w praktyce, jak aktywuję RSS, które Wskazówki w mapie rdzeni, unikając w ten sposób wąskich gardeł związanych z przerwaniami i trafieniami w pamięć podręczną.
Punkty centralne
Krótko podsumuję najważniejsze kwestie, abyś mógł szybko zaplanować kolejne kroki.
- Rozkład obciążenia: Pakiety trafiają do wielu rdzeni poprzez kilka kolejek.
- Lokalizacja pamięci podręcznej: Przepływ pozostaje niezmienny w tej samej kolejce.
- Hashing: Funkcja skrótu czwórkowego równomiernie rozdziela przepływy między kolejkami.
- Affinität: Precyzyjne mapowanie IRQ zmniejsza opóźnienia.
- Skalowanie: Od 10/25 Gbit/s technologia RSS zapewnia wysoką przepustowość.
Te kwestie są ze sobą powiązane i stanowią podstawę Wydajność w oparciu o rzeczywiste obciążenia. Najpierw skupiam się na ustaleniu właściwej liczby kolejek, a następnie na CPU-Zgodność. Następnie sprawdzam parametry skrótu i ustawienia zaawansowane.
Jak działa Receive Side Scaling
RSS dzieli proces odbioru pakietów na kilka etapów Kolejki odbiorcze, które przypisuję do konkretnych rdzeni procesora, aby żaden pojedynczy rdzeń nie stał się wąskim gardłem. Zmniejsza to gwałtowne skoki liczby przerwań twardych i wyrównuje przetwarzanie za pomocą przerwań miękkich (SoftIRQ), co ogranicza skoki opóźnień i zwiększa przepustowość. Każda kolejka wyzwala własne przerwania, które na stałe przypisuję do rdzeni, aby zapewnić spójność ścieżek danych. Ta spójność sprzyja Schowek-Lokalizacja, ponieważ przepływ zawsze napotyka ten sam rdzeń. Właśnie ta współdziałanie przekłada się bezpośrednio na wymierną wydajność przy wysokich wskaźnikach PPS.
Tak działa RSS z technicznego punktu widzenia
NIC tworzy na podstawie adresu IP źródłowego i docelowego oraz portu źródłowego i docelowego Hash i wykorzystuje go jako indeks dla tablicy pośredniej, która wskazuje na kolejki. W ten sposób pakiety z danego przepływu zawsze trafiają do tej samej kolejki i pozostają w ten sposób przypisane do tego samego jądra. Różne przepływy rozkładają się równomiernie, o ile klucze skrótu i pola protokołu są odpowiednio skonfigurowane. W ten sposób praca przebiega blisko Sprzęt, dzięki czemu jądro musi wykonywać mniej operacji równoważenia, a obciążenie systemowe maleje. Właśnie tego potrzebuję, aby przy prędkościach 10G/25G utrzymać niskie obciążenie każdego jądra związane z przetwarzaniem pakietów.
Dlaczego RSS ma znaczenie przy prędkościach od 10 do 25 Gbit/s
Przy prędkości 1 Gbit/s często wystarcza jeden Rdzeń obciążenie pakietami, jednak już przy 10 Gbit/s równowaga szybko się zachwiewa. Małe pakiety powodują wzrost liczby PPS, przez co rdzeń szybko osiąga 100-procentowe obciążenie i pojawiają się utraty pakietów. Właśnie wtedy RSS działa jak mnożnik użytecznej przepustowości. Rozkładam obciążenie na kilka Rdzenie, ograniczają zmiany kontekstu i zapewniają większą stabilność krzywych opóźnień. Wynik: rzeczywista przepustowość zbliża się do szybkości łącza dopiero przy czystym RSS.
Konfiguracja RSS na serwerze z systemem Linux
W systemie Linux zarządzam kanałami RSS przede wszystkim za pomocą narzędzie, opcje sterownika i sysfs, aby w pełni wykorzystać możliwości karty sieciowej. Najpierw odczytuję maksymalną liczbę kanałów odbiorczych (RX), a następnie ustawiam liczbę kolejek dostosowaną do procesora. Następnie sprawdzam skrót RSS dla protokołów TCP/UDP oraz opcjonalnie dla sieci VLAN lub tunelowania, aby profile obciążenia pozostawały prawidłowo rozłożone. W przypadku podstawowego szumu związanego z rozdzielaniem przerwań pomaga mi Równoważenie IRQ, choć krytyczne kolejki wolę przypinać ręcznie. W ten sposób łączę Wskazówki ściśle dostosować się do topologii hosta i zapobiegać niepożądanym przemieszczeniom.
Tabela pośredniczenia, klucz RSS i precyzyjne dostosowywanie skrótu: konkretne polecenia
Najpierw sprawdzam aktualny rozkład i klucz karty sieciowej:
ethtool -x eth0 # Wyświetl tabelę pośrednictwa (kolejki odbiorcze) i klucz RSS
ethtool -n eth0 rx-flow-hash tcp4
ethtool -n eth0 rx-flow-hash udp4
Aby zapewnić równomierny rozkład, ustawiam tablicę pośredniczącą na żądaną liczbę kolejek. W przypadku 16 kolejek wybieram równomierne przyporządkowanie:
ethtool -X eth0 equal 16 Rozkład # równomiernie na 16 kolejek
W razie potrzeby dostosowuję pola skrótu. Dla TCP4 z czwórkami (s = adres IP źródłowy, d = adres IP docelowy, f = port źródłowy, n = port docelowy):
ethtool -N eth0 rx-flow-hash tcp4 sdfn
ethtool -N eth0 rx-flow-hash udp4 sdfn
ethtool -N eth0 rx-flow-hash tcp6 sdfn
ethtool -N eth0 rx-flow-hash udp6 sdfn
Niektóre sterowniki umożliwiają również ustawienie własnego klucza RSS (np. w celu lepszego rozproszenia w szczególnych przypadkach):
ethtool -X eth0 hkey # – tylko jeśli obsługują to sterowniki/karta sieciowa
Prawidłowe ustawienie afinicji procesora i NUMA
Mapuję każdą kolejkę RX za pomocą Powinowactwo IRQ przypisuj je do dedykowanych rdzeni, uwzględniając architekturę NUMA, aby dane przechodziły przez kontroler pamięci na krótkim odcinku. Jeśli karta sieciowa działa na węźle 0, przypisuję również główne kolejki do rdzeni na węźle 0 i umieszczam obciążenia w pobliżu. Ta bliskość ogranicza dostępy zdalne i znacznie zmniejsza opóźnienia pamięci. Przydatny jest w tym celu profil dla kolejek produkcyjnych, a także oddzielne rdzenie dla zadań związanych z zarządzaniem i odciążaniem. Osoby, które chcą zagłębić się w ten temat, znajdą wskazówki dotyczące precyzyjnego dostosowania pod adresem Powinowactwo IRQ, jeśli chodzi o planowanie na Rdzeń uproszczone.
Podręcznik dotyczący powinowactwa IRQ: od IRQ do stabilnego przypisania do rdzeni
Najpierw sprawdzam, które sygnały IRQ należą do kolejek odbiorczych (RX), a następnie przypisuję je na stałe:
grep -E "eth0.*Rx" /proc/interrupts
cat /sys/class/net/eth0/device/numa_node
Przypisanie ustawiam za pomocą smp_affinity_list, żebym nie musiał obliczać masek Hex. Przykład: kolejki RX 0–7 na rdzeniach 2–9:
Przykład #: Przypisanie sygnałów IRQ do rdzeni 2–9 (jedna linia na każdy sygnał IRQ)
echo 2 > /proc/irq//smp_affinity_list
echo 3 > /proc/irq//smp_affinity_list
echo 4 > /proc/irq//smp_affinity_list
...
echo 9 > /proc/irq//smp_affinity_list
Ważne: funkcja MSI-X musi być włączona, aby każda kolejka miała własne przerwania. Jeśli stosuję ręczne przypisywanie pinów, blokuję irqbalance dla tych IRQ (np. poprzez czarną listę) lub wyłącz tę usługę selektywnie na hostach o statycznym układzie. Dodatkowo sprawdzam NUMA za pomocą lscpu oraz przypisania PCIe, aby nie tworzyć ścieżek między węzłami.
Konfiguracja funkcji skrótu i protokoły
Pola skrótu definiuję w taki sposób, aby prawdziwe Ruch uliczny-Rozprowadzać wzorce równomiernie, zamiast skupiać je w kilku kolejkach. W przypadku protokołów TCP/UDP stosuję czwórkę, podobnie w przypadku IPv6, natomiast w przypadku VXLAN lub GRE uwzględniam dodatkowe pola kapsułkowania. Niektóre karty sieciowe oferują konfigurowalne klucze skrótu, które dostosowuję do dominującego obciążenia. Gdy tylko zauważę skupienie obciążenia w poszczególnych kolejkach, koryguję wybór skrótu. Ten krok zajmuje niewiele czasu, ale zapobiega niewyważenie przy dużej liczbie połączeń.
Łączenie przerwań i PPS
Łączę RSS z umiarkowanym Koalescencja przerwań, aby pogrupować ruch generujący duże obciążenie PPS w łatwe do opanowania partie. Zmniejsza to obciążenie związane z przerwaniami, ale nie może pogorszyć opóźnień w usługach wrażliwych. Dlatego mierzę czasy przesyłu w obie strony i stopniowo dostosowuję wartości koalescencji. W przypadku obciążeń związanych z pamięcią masową lub tworzeniem kopii zapasowych można stosować bardziej intensywne grupowanie niż w przypadku interfejsów API warstwy 7 lub VoIP. Podsumowując, równoważę Opóźnienie w stosunku do przepustowości, aż obie wartości będą zgodne.
Koalescencja w praktyce: profile i punkty pomiarowe
Zaczynam od umiarkowanych ustawień domyślnych i stopniowo dostosowuję je do optymalnych wartości dla poszczególnych obciążeń. Trzy sprawdzone profile wyjściowe:
- API/niskie opóźnienie:
rx-usecs 2–6,ramki rx 16–32, adaptacyjne wyłączone - Wszechstronność:
rx-usecs 8–16,ramki rx 32–64, adaptacyjne do - Towary luzem/magazynowanie:
24–48 rx-usecs,ramki rx 128–256, adaptacyjne do
ethtool -c eth0
ethtool -C eth0 rx-usecs 12 rx-frames 64 adaptive-rx on
W tym celu mierzę opóźnienia p95/p99, PPS, obciążenie procesora na rdzeń oraz liczbę retransmisji. Gdy tylko zauważę rosnącą wariancję w przypadku API/VoIP, przechodzę do rx-mikrosekund z powrotem w dół. W przypadku pamięci masowej wolę skalować w górę za pomocą klatek, aby oszczędzać przerwania.
RSS w środowiskach 10 Gb/s
Na kartach sieciowych 10G zazwyczaj pracuję z prędkością od 8 do 16 Wskazówki na port, o ile procesor udostępnia wystarczającą liczbę rdzeni. Dzięki temu serwery WWW, bramy pamięci masowej i hosty wirtualizacji skalują się płynnie przy wielu połączeniach równoległych. Przypisuję główne kolejki do wolnych rdzeni, a następnie mierzę liczbę pakietów na sekundę (PPS), opóźnienie oraz liczbę retransmisji. Jeśli występują utraty pakietów, sprawdzam koalescencję, hash oraz wykorzystanie poszczególnych kolejek. Następnie dostosowuję Affinität, aż obciążenie będzie wyglądało na równomierne.
RSS w konfiguracjach 25 Gbit oraz Multi-25G
Przy prędkości 25 Gbit/s wzrastają wartości PPS i obciążenie magistrali, dlatego NUMA- zwracam większą uwagę na świadomość, wystarczającą liczbę kolejek i mechanizmów odciążania. Funkcje Large Receive Offload (LRO) lub RSC mogą zmniejszyć obciążenie stosu pakietami, o ile aplikacje to tolerują. Ponadto sprawdzam linie PCIe, aby wykluczyć wąskie gardła poza siecią. W hostach z wieloma łączami 25G ściśle rozdzielam kolejki i powinowactwo w zależności od zadań i węzłów. W ten sposób wykorzystuję Szerokość pasma oraz jądra w sposób wydajny, bez powodowania ruchu międzywęzłowego.
Szczegóły dotyczące sprzętu i sterowników: na co zwracam uwagę
Nie każda karta sieciowa działa tak samo. Generacje procesorów Intel (np. ixgbe, i40e, ice) oferują funkcje takie jak Flow Director/ATR, które w sposób ukierunkowany przypisują strumienie do kolejek – jest to pomocne, gdy chcę wyrównać obciążenia w newralgicznych punktach. Karta Mellanox mlx5 może obsługiwać aRFS na poziomie sprzętowym, co zmniejsza obciążenie procesora, gdy stos obsługuje wiele gniazd. W zależności od sytuacji decyduję, czy włączyć te funkcje, i sprawdzam, czy poprawiają one rozkład obciążenia. W systemach routingu/NAT często wyłączam LRO i stosuję GRO, aby zachować spójność nagłówków; w przypadku czysto serwerowych obciążeń LRO/GRO może pomóc w złagodzeniu presji PPS. Ważne są również wystarczająca liczba wektorów MSI-X na każdą kolejkę oraz prawidłowe wersje oprogramowania układowego.
RSS w wirtualizacji i kontenerach
W hiperwizorze łączę fizyczne RSS-Kolejki z kartami sieciowymi vNIC obsługującymi wiele kolejek, np. virtio-net, aby goście nie napotykali sztucznych wąskich gardeł. Zwracam uwagę na przypisanie procesorów (CPU-Pinning) maszyn wirtualnych i ustalam ich bliskość vCPU-NUMA względem fizycznej karty sieciowej. Dzięki temu dane pozostają lokalnie, a host ponosi mniejsze koszty związane z dostępem do pamięci. W przypadku kontenerów przypisuję krytyczne pody do odpowiednich rdzeni i utrzymuję kolejki hosta wolne od obciążenia zakłócającego. Taki porządek zwiększa Wydajność w przypadku mikrousług, gdzie powstaje wiele małych przepływów.
Jak prawidłowo korzystać z SR-IOV i VF-RSS
Dzięki SR-IOV przypisuję maszynom wirtualnym własne VF, które z kolei mogą udostępniać wiele kolejek i RSS. Planuję wystarczającą liczbę VF na każdy port, zwracam uwagę na pojemność MSI-X i przypisuję sygnały IRQ VF w maszynie wirtualnej odpowiednio do jej procesorów vCPU. W systemach-gościach opartych na Linuksie wyraźnie włączam obsługę wielu kolejek, w przeciwnym razie karta vNIC często pozostaje jednostopniowa:
# w trybie gościa (przykład virtio-net)
ethtool -l eth0
ethtool -L eth0 combined 4
Serwery z wieloma partycjami wirtualnymi (VF) rozdzielam ściśle według węzłów NUMA i obciążeń, aby maszyny wirtualne nie zakłócały sobie nawzajem pracy w tych samych fizycznych ścieżkach odbiorczych (RX).
Monitorowanie i rozwiązywanie problemów
Monitoruję obciążenie na Kolejka, poszczególne jądra, utratę pakietów i retransmisje, aby wcześnie wykryć nieprawidłowości. Jeśli jedno jądro się wyróżnia, a pozostałe pozostają wolne, często oznacza to, że nie jest prawidłowa wartość powinowactwa lub liczba kolejek. W takich przypadkach sprawdzam kolejno pola hash, maski IRQ i wartości koalescencji. Ponadto sprawdzam Obciążenie SoftIRQ, ponieważ dostarcza ona wskazówek dotyczących efektów wypierania. Dopiero gdy sygnały te wydają się stabilne, zwiększam ruch lub rozszerzam Wskazówki kontynuować.
RPS, RFS i XPS: rozszerzenia oprogramowania do RSS
Jeśli karta sieciowa ma tylko kilka kolejek lub korzystam z funkcji łączenia kart sieciowych (bonding) lub tunelowania, uzupełniam RSS o RPS (kierowanie odbiorem pakietów) oraz RFS (Receive Flow Steering). RPS rozdziela sygnały SoftIRQ między rdzenie, a RFS przypisuje strumienie do rdzenia, na którym aktywny jest odpowiedni gniazdo. Aktywuję obie te funkcje w sposób ukierunkowany:
# Zwiększenie globalnej liczby wpisów przepływu (RFS)
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
# Ustawienie liczby procesorów dla RPS na każdą kolejkę odbiorczą (przykładowa maska, dostosować!)
for f in /sys/class/net/eth0/queues/rx-*/rps_cpus; do echo ffff > "$f"; done
Ustawienie tabeli przepływów dla kolejki odbiorczej # Pro w systemie RFS
for f in /sys/class/net/eth0/queues/rx-*/rps_flow_cnt; do echo 4096 > "$f"; done
Po stronie TX korzystam z XPS (Transmit Packet Steering), aby pakiety wychodzące były wysyłane z tego rdzenia, który je wygenerował:
for f in /sys/class/net/eth0/queues/tx-*/xps_cpus; do echo ffff > "$f"; done
RPS/RFS/XPS zużywają nieco mocy procesora, ale są pomocne, gdy brakuje mi kolejek po stronie sprzętowej lub gdy chcę ściśle przestrzegać lokalizacji gniazd.
Wydajność w trybie Single-Flow, GRO/TSO i Busy-Polling
Pojedynczy strumień pozostaje powiązany z jednym rdzeniem z ważnego powodu. Jeśli chcę zwiększyć przepustowość pojedynczego strumienia, stawiam na odciążanie (GRO/TSO), wysoką częstotliwość rdzenia i odpowiednie scalanie. W przypadku ścieżek, w których opóźnienie ma kluczowe znaczenie, można Zajęte odpytywanie pomóc:
Ustawić niską wartość # i dokonać pomiaru
sysctl -w net.core.busy_read=25
sysctl -w net.core.busy_poll=25
Metoda „busy-polling” ogranicza zmiany kontekstu, ale zajmuje czas procesora. Włączam ją tylko tam, gdzie liczą się opóźnienia p99, i zawsze sprawdzam jej wpływ na ogólne obciążenie oraz opóźnienie ogonowe. Zazwyczaj wyłączam GRO na serwerach, a LRO stosuję w zależności od roli; w przypadku urządzeń pośredniczących zachowuję ostrożność, aby nie zakłócać przetwarzania nagłówków i spójności skrótów.
Zalecenia i przykłady: kolejki, powinowactwo, polecenia
Jako punkt wyjścia wybieram liczbę kolejek, która odpowiada CPU dopasuj, a następnie obserwuj obciążenie w poszczególnych kolejkach i dostosowuj je stopniowo. W przypadku 10G często wystarcza 8–16 kolejek, przy 25G często ustalam wyższą liczbę, o ile dostępne są odpowiednie jądra. W przypadku powinowactwa stosuję przejrzyste maski dla poszczególnych IRQ, aby później łatwiej analizować ścieżki. Poniższa tabela zawiera zwięzłe wartości orientacyjne, które następnie weryfikuję poprzez pomiary. Dopiero wyniki pomiarów decydują o tym, czy więcej zwiększyć lub zmniejszyć.
| Prędkość łącza | Typowe kolejki RX | Przykładowe polecenia | Uwagi |
|---|---|---|---|
| 10 Gbit/s | 8-16 | ethtool -l eth0 | ethtool -L eth0 rx 16 | Koalescencja utrzymywać na umiarkowanym poziomie, sprawdzić opóźnienie L7 |
| 25 Gbit/s | 16–32+ | grep . /proc/interrupts | Maski IRQ za pomocą echo | NUMA należy zwrócić uwagę, sprawdzić linie PCIe |
| Multi-25G | Osobno za każdą porcję | Włącz funkcję vNIC Multi-Queue (np. virtio) | Kole na rdzenie i Obciążenia podział |
Te wartości orientacyjne stanowią jedynie punkt wyjścia, a nie cel, ponieważ obciążenia znacznie się od siebie różnią. Rejestruję zmiany, dokonuję pomiarów przed i po dostosowaniu, a poza tym nie wprowadzam żadnych zmian w środowisku. Gdy tylko system zachowa stabilność pod obciążeniem produkcyjnym, zamrażam konfigurację. Później ponawiam pomiary po aktualizacjach jądra lub sterowników. W ten sposób trzymam się RSS precyzyjne działanie i pewne, powtarzalne wyniki.
Typowe przeszkody i sposoby ich pokonywania
Zbyt mało Wskazówki Przeładowują poszczególne rdzenie, a zbyt duża ich liczba zwiększa nakład administracyjny i obniża współczynnik trafień w pamięci podręcznej. Niewłaściwa afinność powoduje przekierowywanie przerw do rdzeni, które są już obciążone, lub do niewłaściwych węzłów NUMA. Również nieodpowiedni hash prowadzi do tego, że dominujące przepływy zatykają kolejki. Rozwiązuję to krok po kroku: dostosowuję liczbę kolejek, koryguję przynależność, rozszerzam pola haszujące, precyzyjnie dostrajam koalescencję. Każdą zmianę dokumentuję za pomocą Metryki, zanim przejdę do następnej dźwigni.
Scenariusze oparte na praktyce
Serwer pamięci masowej z łączem 10G szybko czerpie korzyści z 8–12 Wskazówki oraz umiarkowanym koalescowaniem, aby zapewnić płynną realizację transferów masowych. Serwer API obsługujący dużą liczbę połączeń często wymaga bardziej precyzyjnych pól hashowych i mniejszych opóźnień przy przerwaniach. Hosty wirtualizacyjne zyskują znacznie, gdy funkcja vNIC Multi-Queue jest aktywna po stronie gościa i pasuje do układu hosta. Obciążenia kontenerowe działają płynniej, gdy krytyczne pody działają blisko karty sieciowej i pamięci NUMA. W zależności od sytuacji rozszerzam te wzorce, stosując PPS, porównaj retransmisje i rozdzielanie kolejek.
Wydajne platformy jako atut
Konfiguracje hostingowe z konsekwentnie skonfigurowanym RSS, karty sieciowe z obsługą wielu kolejek oraz prawidłowo skonfigurowana afinność zapewniają odczuwalne rezerwy wydajności w okresach szczytowego obciążenia. Osoby oceniające oferty serwerowe powinny celowo pytać o obsługę wielu kolejek, przypisanie NUMA oraz monitorowanie. Dostawca, który w widoczny sposób wdraża te rozwiązania, często osiąga zauważalnie lepsze krzywe przepustowości. Jeśli chodzi o wydajne rozwiązania serwerowe i hostingowe, zdecydowanie polecam tutaj webhoster.de. Takie podejście opłaca się w Wydajność oraz stabilność, zwłaszcza przy dużej liczbie równoległych przepływów.
Podsumowanie dla praktyki
Aktywuję Odbiór Skalowanie boczne: ustal rozsądną liczbę kolejek, przypisz sygnały IRQ do odpowiednich rdzeni i sprawdź konfigurację funkcji hash. Następnie optymalizuję koalescencję pod kątem opóźnienia, zwracam uwagę na bliskość w architekturze NUMA i spójnie rozdzielam obciążenia. W wirtualizacji stosuję obsługę wielu kolejek aż do poziomu systemów-gości oraz synchronizuję pinning i powinowactwo. Pomiary dotyczące PPS, obciążenia kolejek, retransmisji i opóźnień decydują o kolejnym kroku. Kto postępuje w ten sposób, w pełni wykorzystuje przepustowość 10G i 25G oraz utrzymuje Opóźnienie w ramach tego i niezawodnie osiąga zysk z sieci.


