Receive Side Scaling fordeler netværkstrafikken målrettet på flere kerner via 10- og 25-Gbit/s-forbindelser, så Linux-servere kan håndtere høje gennemstrømningshastigheder med lav latenstid. Jeg viser i praksis, hvordan jeg aktiverer RSS, som Stikord på Cores mappe og dermed undgår flaskehalse ved interrupts og cache-hits.
Centrale punkter
Jeg vil kort opsummere de vigtigste punkter, så du hurtigt kan planlægge de næste skridt.
- Fordeling af belastning: Pakker fordeles via flere køer til flere kerner.
- Cache-placering: En flow forbliver konsekvent på den samme kø.
- Hashing: 4-tupel-hash fordeler flows jævnt over køerne.
- affinitet: Målrettet IRQ-mapping reducerer ventetiderne.
- Skalering: Fra 10/25 Gbit/s sikrer RSS en høj gennemstrømning.
Disse punkter hænger sammen og understøtter Ydelse om reelle arbejdsbelastninger. Jeg prioriterer først det korrekte antal køer, derefter CPU-affinitet. Derefter tjekker jeg hash-parametre og finjusteringer.
Hvad Receive Side Scaling kan
RSS opdeler modtagelsen af pakker i flere Modtagelseskøer, som jeg tildeler specifikke CPU-kerner, så ingen enkelt kerne bliver en flaskehals. Det mindsker kraftige interrupt-spidser og udjævner behandlingen via SoftIRQ’er, hvilket reducerer latenstidsspidser og øger gennemstrømningen. Hver kø udløser sine egne interrupts, som jeg binder fast til bestemte kerner for at holde dataveje konsistente. Denne konsistens fremmer Cache-Lokalitet, fordi en strøm altid rammer den samme kerne. Netop dette samspil bidrager direkte til målbar effektivitet ved høje PPS-hastigheder.
Sådan fungerer RSS rent teknisk
NIC danner ud fra kilde-/destinations-IP samt kilde-/destinationsport en Hash og bruger den som indeks for indirektionstabellen, der peger på køer. På denne måde ender pakker fra en strøm altid i den samme kø og forbliver dermed knyttet til den samme kerne. Forskellige strømme fordeles jævnt, forudsat at hash-nøgler og protokolfelter er konfigureret korrekt. Arbejdet flyttes dermed tæt på Hardware, hvilket betyder, at kernen skal udføre færre afvejninger, og at overheadet reduceres. Det er netop det, jeg ønsker, for at holde pakkeforarbejdningen pr. kerne lav ved 10G/25G.
Hvorfor RSS fra 10 og 25 Gbit/s er vigtigt
Ved 1 Gbit/s er det ofte en enkelt Kerne pakkebelastningen, men fra 10 Gbit/s ændrer balancen sig hurtigt. Små pakker får PPS-tallet til at stige, hvilket betyder, at en kerne hurtigt når 100 procent belastning, og der opstår tab. Netop da fungerer RSS som en multiplikator for den anvendelige båndbredde. Jeg fordeler belastningen på flere Kerner, mindsker kontekstskift og holder latenstidskurverne mere stabile. Resultatet: Den reelle gennemstrømning nærmer sig først linkhastigheden, når RSS fungerer korrekt.
Opsætning af RSS på Linux-serveren
Under Linux styrer jeg RSS primært via ethtool, driverindstillinger og sysfs, så NIC-funktionerne virkelig kommer til deres ret. Først læser jeg de maksimale RX-kanaler ud, derefter indstiller jeg et antal køer, der passer til CPU’en. Derefter tjekker jeg RSS-hash for TCP/UDP og eventuelt for VLAN eller tunneling, så belastningsprofilerne forbliver jævnt fordelt. Til at håndtere støj i interrupt-fordelingen hjælper mig IRQ-balancering, selvom jeg foretrækker at fastsætte kritiske køer manuelt. Sådan kobler jeg Stikord tæt på værtsens topologi og forhindrer forstyrrende vandringer.
Indirection-Table, RSS-Key og finjustering af hash: konkrete kommandoer
Først tjekker jeg den aktuelle fordeling og nøglen for NIC’en:
ethtool -x eth0 # Vis indirektionstabel (RX-køer) og RSS-nøgle
ethtool -n eth0 rx-flow-hash tcp4
ethtool -n eth0 rx-flow-hash udp4
For at sikre en jævn fordeling indstiller jeg Indirection-Table til det ønskede antal køer. Ved 16 køer vælger jeg en jævn fordeling:
ethtool -X eth0 equal 16 # Fordeling jævnt på 16 køer
Hvis det er nødvendigt, tilpasser jeg hash-felterne. For TCP4 med 4-tupler (s=src-ip, d=dst-ip, f=src-port, n=dst-port):
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
Nogle drivere giver også mulighed for at angive en egen RSS-nøgle (f.eks. for at opnå en bedre spredning i særlige tilfælde):
ethtool -X eth0 hkey # kun hvis driveren/NIC'en understøtter det
Indstil CPU-affinitet og NUMA korrekt
Jeg kortlægger hver RX-kø ved hjælp af IRQ-affinitet til dedikerede kerner og tag højde for NUMA, så data kun kører en kort vej gennem hukommelseskontrolleren. Hvis netværkskortet kører på node 0, knytter jeg også hovedkøerne til kerner på node 0 og placerer arbejdsbelastninger i nærheden. Denne nærhed reducerer fjernadgang og sænker hukommelseslatensen markant. Her er det nyttigt at have en profil til produktive køer samt separate kerner til administrations- og offload-opgaver. Hvis du vil gå mere i dybden, finder du vejledning til finjustering under IRQ-affinitet, hvad angår planlægningen pr. Kerne forenklet.
IRQ-affinitet-vejledning: fra IRQ’er til stabil kernebinding
Først finder jeg ud af, hvilke IRQ'er der hører til RX-køerne, og derefter binder jeg dem fast:
grep -E "eth0.*Rx" /proc/interrupts
cat /sys/class/net/eth0/device/numa_node
Jeg foretager tildelingen via smp_affinity_list, så jeg ikke behøver at regne med Hex-masker. Eksempel: RX-køer 0–7 på kerner 2–9:
# Eksempel: Tildel IRQ’er til kerner 2–9 (én linje pr. 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
Vigtigt: MSI-X skal være aktiveret, for at hver kø kan have sine egne interrupts. Hvis jeg bruger manuel pinning, blokerer jeg irqbalance for disse IRQ’er (f.eks. via en sortliste) eller deaktiverer tjenesten målrettet på værter med statisk layout. NUMA tjekker jeg desuden med lscpu og PCIe-tildelingen, så jeg ikke opretter tværgående stier mellem noder.
Hash-konfiguration og protokoller
Jeg definerer hash-felterne på en sådan måde, at ægte Trafik-Fordel mønstrene jævnt i stedet for at de ender i få køer. Til TCP/UDP bruger jeg 4-tuplen, til IPv6 gør jeg det på samme måde, mens jeg ved VXLAN eller GRE tager højde for yderligere felter i indkapslingen. Nogle NIC'er tilbyder konfigurerbare hash-nøgler, som jeg tilpasser til den dominerende arbejdsbelastning. Så snart jeg ser belastningskluster på enkelte køer, justerer jeg hash-valget. Dette trin tager kun lidt tid, men forhindrer en Ubalance ved et højt antal forbindelser.
Interrupt-Coalescing og PPS
Jeg kombinerer RSS med moderat Sammenlægning af afbrydelser, for at samle PPS-intensiv trafik i håndterbare batcher. Det reducerer interrupt-overhead, men må ikke forringe latenstiden for følsomme tjenester. Derfor måler jeg round-trip-tider og justerer coalescing-værdierne trinvist. Hvis man kører storage- eller backup-belastning, kan man samle i større omfang end ved L7-API’er eller VoIP. Alt i alt afbalancerer jeg Forsinkelse mod gennemstrømningen, indtil begge dele stemmer overens.
Coalescing i praksis: Profiler og målepunkter
Jeg starter med moderate standardindstillinger og arbejder mig frem mod det optimale for hver enkelt arbejdsopgave. Tre gennemprøvede startprofiler:
- API/lav latenstid:
rx-usecs 2–6,rx-rammer 16–32, adaptiv fra - Allround:
rx-usecs 8–16,rx-rammer 32–64, adaptiv til - Bulk/Opbevaring:
24–48 rx-usecs,rx-rammer 128–256, adaptiv til
ethtool -c eth0
ethtool -C eth0 rx-usecs 12 rx-frames 64 adaptive-rx on
Til det formål måler jeg p95/p99-latenser, PPS, CPU-belastning pr. kerne og genudsendelser. Så snart jeg ser en stigende varians ved API/VoIP, går jeg videre med rx-usecs ned igen. Når det gælder lagring, foretrækker jeg at skalere op via frames for at spare på interrupts.
RSS i 10-Gbit-miljøer
På 10G-NIC’er arbejder jeg som regel med 8 til 16 Stikord pr. port, forudsat at CPU’en stiller tilstrækkeligt med kerner til rådighed. Webservere, lagringsgateways og virtualiseringsværter kan dermed skaleres problemfrit over mange parallelle forbindelser. Jeg knytter hovedkøerne til ledige kerner og måler derefter PPS, latenstid og retransmissioner. Hvis der opstår tab, tjekker jeg coalescing, hash og udnyttelsen pr. kø. Derefter finjusterer jeg affinitet, indtil belastningen ser jævn ud.
RSS i 25-Gbit- og Multi-25G-konfigurationer
Med 25 Gbit/s stiger PPS og busbelastningen, og derfor vil jeg NUMA-Vær mere opmærksom på bevidsthed, tilstrækkelige køer og offloads. Large Receive Offload (LRO) eller RSC kan mindske pakketrykket på stakken, forudsat at applikationerne kan tåle det. Derudover tjekker jeg PCIe-baner for at udelukke flaskehalse uden for netværket. På værter med flere 25G-forbindelser adskiller jeg køer og affinitet strengt efter opgaver og noder. Således bruger jeg Båndbredde og kerner effektivt, uden at det udvikler sig til trafik på tværs af noder.
Detaljer om hardware og drivere: hvad jeg lægger mærke til
Ikke alle netværkskort fungerer på samme måde. Intel-generationer (f.eks. ixgbe, i40e, ice) tilbyder funktioner som Flow Director/ATR, der målrettet knytter datastrømme til køer – hvilket er nyttigt, når jeg ønsker at udjævne hotspots. Mellanox mlx5 kan understøtte aRFS i hardware, hvilket reducerer CPU-belastningen, når stakken betjener mange sockets. Jeg beslutter fra sag til sag, om jeg vil aktivere disse funktioner, og måler, om de forbedrer fordelingen. På routing-/NAT-systemer deaktiverer jeg ofte LRO og bruger i stedet GRO for at opretholde header-konsistens; på rene server-workloads kan LRO/GRO hjælpe med at dæmpe PPS-presset. Det er desuden vigtigt at have tilstrækkeligt med MSI-X-vektorer pr. kø og korrekte firmwareversioner.
RSS inden for virtualisering og containere
I hypervisoren kombinerer jeg fysiske RSS-Køer med vNIC’er, der understøtter flere køer, f.eks. virtio-net, så gæsterne ikke oplever kunstige flaskehalse. Jeg sørger for CPU-pinning af de virtuelle maskiner og fastlægger deres vCPU-NUMA-nærhed til det fysiske netværkskort. På den måde forbliver dataene lokalt, og værten betaler mindre for hukommelsesadgang. For containere binder jeg kritiske pods til passende kerner og holder værtskøerne fri for støjbelastning. Denne orden øger Effektivitet i forbindelse med mikrotjenester, hvor der opstår mange små processer.
Sådan bruger du SR-IOV og VF-RSS korrekt
Med SR-IOV tildeler jeg VM’er deres egne VF’er, som igen kan stille flere køer og RSS’er til rådighed. Jeg planlægger et tilstrækkeligt antal VF'er pr. port, holder øje med MSI-X-kapaciteten og tildeler VF-IRQ'erne i den virtuelle maskine i overensstemmelse med dens vCPU'er. I Linux-gæster aktiverer jeg eksplicit Multi-Queue, ellers forbliver vNIC'en ofte et-trins:
# som gæst (virtio-net-eksempel)
ethtool -l eth0
ethtool -L eth0 combined 4
Jeg fordeler værter med flere virtuelle maskiner strengt efter NUMA-node og arbejdsbelastning, så de virtuelle maskiner ikke forstyrrer hinanden i de samme fysiske RX-stier.
Overvågning og fejlfinding
Jeg overvåger udnyttelsesgraden pr. Kø, enkelte kerner, pakketab og retransmissioner for at opdage uregelmæssigheder i tide. Hvis en kerne tager over, mens andre forbliver ledige, er affiniteten eller antallet af køer ofte ikke korrekt. I sådanne tilfælde tjekker jeg hashfelter, IRQ-masker og coalescing-værdier én efter én. Derudover kigger jeg på SoftIRQ-belastning, fordi den giver tegn på fortrængningseffekter. Først når disse signaler ser stabile ud, øger jeg trafikken eller udvider Stikord Fortsæt.
RPS, RFS og XPS: Softwareudvidelser til RSS
Hvis et netværkskort kun har få køer, eller hvis jeg bruger bonding/tunneling, supplerer jeg RSS med RPS (Receive Packet Steering) og RFS (Receive Flow Steering). RPS fordeler SoftIRQ’er på kernerne, mens RFS knytter datastrømme til den kerne, hvor den tilhørende socket er aktiv. Jeg aktiverer begge funktioner målrettet:
# Øg antallet af globale flow-poster (RFS)
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
# Indstil CPU'er pr. RX-kø til RPS (eksempelmaske, tilpas!)
for f in /sys/class/net/eth0/queues/rx-*/rps_cpus; do echo ffff > "$f"; done
Indstil # pr. RX-kø flow-tabel for RFS
for f in /sys/class/net/eth0/queues/rx-*/rps_flow_cnt; do echo 4096 > "$f"; done
På TX-siden bruger jeg XPS (Transmit Packet Steering), så udgående pakker sendes fra den kerne, der har genereret dem:
for f in /sys/class/net/eth0/queues/tx-*/xps_cpus; do echo ffff > "$f"; done
RPS/RFS/XPS belaster CPU’en en smule, men er nyttige, hvis jeg mangler køer på hardwaresiden, eller hvis jeg vil sikre en streng socket-lokalitet.
Single-Flow-kapacitet, GRO/TSO og Busy-Polling
En enkelt datastrøm forbliver af gode grunde bundet til en kerne. Hvis jeg ønsker at øge båndbredden for en enkelt datastrøm, satser jeg på offloads (GRO/TSO), en høj kernefrekvens og harmonisk coalescing. For latenstidsfølsomme stier kan Optaget polling hjælpe:
Indstil # til en lav værdi og mål
sysctl -w net.core.busy_read=25
sysctl -w net.core.busy_poll=25
Busy-polling reducerer kontekstskift, men optager CPU-tid. Jeg aktiverer det kun der, hvor p99-latenser er afgørende, og jeg vurderer altid virkningerne på den samlede belastning og tail-latensen. GRO holder jeg som regel slået til på servere, mens jeg anvender LRO afhængigt af rollen; på middleboxes forholder jeg mig konservativt for ikke at forstyrre header-behandlingen og hash-konsistensen.
Anbefalinger og eksempler: Køer, affinitet, kommandoer
Som udgangspunkt vælger jeg et antal køer, der passer til CPU Juster, overvåg derefter belastningen pr. kø og juster trinvist. Ved 10G er 8–16 køer ofte tilstrækkelige, ved 25G sætter jeg ofte antallet højere, forudsat at der er kerner til rådighed. Til affinitet bruger jeg klare masker pr. IRQ, så jeg senere lettere kan analysere stierne. Den følgende tabel giver overskuelige retningslinjer, som jeg derefter verificerer ved hjælp af målinger. Først målingerne afgør, om jeg mere forhøj eller reducer.
| Linkhastighed | Typiske RX-køer | Eksempelkommandoer | Noter |
|---|---|---|---|
| 10 Gbit/s | 8-16 | ethtool -l eth0 | ethtool -L eth0 rx 16 | Sammensmeltning Hold det på et moderat niveau, kontroller L7-latens |
| 25 Gbit/s | 16–32+ | grep . /proc/interrupts | IRQ-masker via ekko | NUMA Vær opmærksom på dette, kontroller PCIe-baner |
| Multi-25G | Separat pr. portion | Aktivér vNIC Multi-Queue (f.eks. virtio) | Køer på kerner og Arbejdsbyrder dele sig |
Disse retningslinjer udgør kun udgangspunktet, ikke målet, da arbejdsbelastningerne varierer meget. Jeg logger ændringer, foretager målinger før og efter justeringen og holder ellers miljøet uændret. Så snart systemet forbliver stabilt under produktionsbelastning, låser jeg konfigurationen fast. Senere gentager jeg målingerne efter opdateringer af kernen eller driverne. På den måde holder jeg mig til RSS Præcis kurs og sikre, reproducerbare resultater.
Typiske forhindringer og modforanstaltninger
For få Stikord Overbelaster enkelte kerner, mens for mange øger administrationsbyrden og forringer cache-hitraten. En uheldig affinitet flytter interrupts til kerner, der allerede er belastede, eller til forkerte NUMA-noder. Også en uhensigtsmæssig hash fører til, at dominerende flows tilstopper køerne. Jeg løser dette trin for trin: justere antallet af køer, korrigere affinitet, udvide hash-felter, finjustere coalescing. Hver ændring dokumenterer jeg med Metrikker, før jeg går videre til den næste håndtag.
Praksisnære scenarier
En lagringsserver med 10G får hurtigt fordel af 8–12 Stikord samt moderat coalescing for at sikre, at bulk-overførsler forløber problemfrit. En API-server med et stort antal forbindelser har ofte brug for finere hash-felter og lavere latenstid ved interrupts. Virtualiseringsværter opnår betydelige fordele, når vNIC-Multi-Queue er aktiveret på gæstesiden og passer til værtslayoutet. Container-workloads fungerer bedre, når kritiske pods kører tæt på NIC og NUMA-hukommelse. Jeg udvider disse mønstre efter situationen ved at PPS, sammenlign retransmissioner og køfordeling.
Effektive platforme som en fordel
Hosting-opsætninger med konsekvent konfigureret RSS, Multi-Queue-NIC'er og præcis affinitet giver mærkbare reserver ved spidsbelastning. Når man vurderer serverløsninger, bør man specifikt spørge ind til Multi-Queue-funktion, NUMA-pinning og overvågning. En udbyder, der tydeligt implementerer disse punkter, opnår ofte markant bedre gennemstrømningskurver. Når det gælder højtydende server- og hostingløsninger, vil jeg her klart anbefale webhoster.de. Denne fokusering betaler sig i Ydelse og stabilitet, især når der kører mange parallelle flows.
Resumé til brug i praksis
Jeg aktiverer Modtag Side-scaling: Indstil et rimeligt antal køer, tildel IRQ’er til passende kerner, og kontroller hash-konfigurationen. Derefter optimerer jeg coalescing med henblik på at minimere latenstiden, sikrer NUMA-nærhed og fordeler arbejdsbelastningen ensartet. I virtualisering bruger jeg multi-kø helt ind i gæsterne og holder pinning og affinitet synkroniseret. Målinger af PPS, købelastning, retransmissioner og latenstid afgør det næste skridt. Hvis man går frem på denne måde, udnytter man 10G og 25G fuldt ud og holder Forsinkelse inden for rammerne og opnår pålideligt afkast fra netværket.


