Server-IRQ-balansering och nätverksprestanda för hosting med hög belastning

Hög nätverksbelastning bestäms av den effektiva bearbetningen av Server IRQ signaler: Om du fördelar avbrotten på ett klokt sätt mellan CPU-kärnorna minskar du latensen och förhindrar avbrott. I den här guiden visar jag dig hur du kombinerar IRQ-balansering, RSS/RPS och CPU-affinitet på ett praktiskt sätt för att göra hosting med hög belastning hållbar. högpresterande för att fungera.

Centrala punkter

  • IRQ-fördelning förhindrar hotspots på enskilda CPU-kärnor.
  • Flera köer plus RSS/RPS parallelliserar paketbearbetningen.
  • NUMA Uppmärksamhet minskar åtkomst och fördröjning mellan noder.
  • CPU-guvernör och trådnålning jämnar ut svarstiderna.
  • Övervakning Kontrollerar pps, fördröjningar, avbrott och kärnanvändning.

Kort förklaring av IRQ:er: Varför de styr nätverksbelastningen

För varje inkommande paket rapporterar nätverkskortet via IRQ, att arbete pågår, annars skulle kärnan behöva göra en aktiv pollning. Om uppdraget ligger kvar på en kärna ökar dess utnyttjande, medan andra kärnor oanvänd kvar. Det är precis då som latenserna ökar, RX-ringens buffertar fylls och drivrutinerna börjar kassera paket. Jag fördelar avbrotten på lämpliga kärnor för att hålla paketbehandlingen jämn och förutsägbar. Detta minskar flaskhalsar, jämnar ut svarstider och håller paketförlusterna till ett minimum.

IRQ-balansering och CPU-affinitet under Linux

Tjänsten irqbalans distribuerar avbrott dynamiskt, analyserar belastningen och ändrar affiniteter automatiskt över tid. För extrema belastningsprofiler definierar jag affiniteter manuellt via /proc/irq//smp_affinity och binda ledtrådar specifikt till kärnor av samma NUMA-noder. Denna kombination av automatik och finjustering hjälper mig att hantera både basbelastningar och toppar på ett rent sätt. En djupgående introduktion till Interrupthantering och CPU-optimering Jag använder dem för att hjälpa mig med min planering. Det är fortfarande viktigt: Jag kopplar konsekvent ihop hårdvarutopologi, IRQ-fördelning och applikationstrådar med varandra.

Praktisk användning av NIC med flera köer, RSS och RPS

Moderna nätverkskort har flera RX/TX-köer, där varje kö triggar sin egen IRQ:er, och RSS (Receive Side Scaling) distribuerar flöden till kärnorna. Om det inte finns tillräckligt med hårdvaruköer lägger jag till Receive Packet Steering (RPS) och Transmit Packet Steering (XPS) i kärnan för ytterligare Parallellism. Med ethtool -L ethX kombinerad N Jag justerar könumret till kärnnumret för den associerade NUMA-noden. Jag kontrollerar med ethtool -S och nstat, om droppar, upptagna polls eller höga pps-toppar inträffar. För finare belastningsutjämning använder jag också Sammanslagning av avbrott i planeringen så att NIC:en inte genererar för många individuella IRQ:er.

I följande tabell visas centrala komponenter och typiska kommandon som jag använder för en sammanhängande installation:

Byggnadsblock Mål Exempel Ledtråd
irqbalans Automatisk distribution systemctl enable --now irqbalance Utgångspunkt för blandade arbetsbelastningar
Affinitet Åtgärdar Pinning echo mask > /proc/irq/XX/smp_affinity Observera NUMA-tilldelning
Ledtrådar Mer parallellism ethtool -L ethX kombinerad N Matchning till nodkärnor
RSS/RPS Flödesfördelning sysfs: rps_cpus/rps_flow_cnt Användbart för ett litet antal NIC-köer
XPS Ordnade TX-vägkärnor sysfs: xps_cpus Undviker att cachen töms

Förnuftig användning av automatisk IRQ-balansering

För servrar med blandad hosting räcker det ofta med att aktivera irqbalans, eftersom daemon hela tiden känner av belastningsförändringar. Jag kontrollerar statusen via systemctl status irqbalance och ta en titt på /proc/avbrott, för att se fördelningen per kö och kärna. Om latenserna ökar i toppar definierar jag testkärnor som främst bearbetar avbrott och jämför uppmätta värden före och efter förändringen. Jag behåller konfigurationen enkel, så att senare revisioner och rollbacks går snabbt. Först när mönstren är tydliga går jag djupare in i pinning.

Manuell CPU-affinitet för maximal kontroll

Vid mycket höga pps-hastigheter kopplar jag RX-köer till utvalda kärnor i samma NUMA-noder och separerar avsiktligt applikationstrådar från dem. Jag isolerar enskilda kärnor för avbrott, kör arbetare på närliggande kärnor och är noga med cache-lokalitet. På så sätt minskar jag åtkomsten mellan noderna och minimerar dyra kontextbyten i den heta vägen. För att resultaten ska vara reproducerbara dokumenterar jag tydligt IRQ-maskerna, kötilldelningen och tjänsternas trådtillhörighet. Denna tydlighet håller paketets körtider konstant och reducerar avvikande värden.

Ren samordning av CPU-optimering och applikationer

Jag ställde in CPU-guvernör ofta inställd på „prestanda“ eftersom klockförändringar ökar latenshoppen. Jag binder kritiska processer som Nginx, HAProxy eller databaser till kärnor som ligger nära IRQ-kärnorna, eller så separerar jag dem medvetet om cacheprofilen kräver det. Det är fortfarande viktigt att begränsa kontextförändringar och hålla kärnan uppdaterad så att optimeringar i nätstacken får effekt. Jag mäter effekterna av varje förändring i stället för att göra antaganden och anpassar mig steg för steg. Detta resulterar i en setup som fungerar under belastning förutsägbar reagerar.

Ställ in övervakning och mätning på rätt sätt

Utan uppmätta värden blir inställningen en gissningslek, så jag börjar med sar, mpstat, vmstat, nstat, ss och ethtool -S. För strukturerade belastningstester använder jag iperf3 och tittar på genomströmning, pps, latens, retransmissioner och kärnanvändning. Jag registrerar långsiktiga trender med hjälp av standardiserade övervakningssystem för att kunna känna igen mönster som kvällstoppar, backupfönster eller kampanjer. Om du vill förstå datavägen på ett holistiskt sätt har du nytta av en vy över Pipeline för paketbehandling från NIC IRQ till användarutrymmet. Det är bara kombinationen av dessa signaler som visar om IRQ-balansering och affinitet har uppnått önskad effekt. Effekt ta med.

Förståelse av NAPI, Softirqs och ksoftirqd

För att hantera fördröjningstoppar med höga pps-belastningar tar jag hänsyn till NAPI-mekanik och samspelet mellan hårda IRQ:er och mjuka IRQ:er. Efter den första hårdvaru-IRQ:n hämtar NAPI flera paket från RX-kön i poll-läge för att undvika IRQ-stormar. Om mjuka IRQ:er inte behandlas omedelbart flyttas de till ksoftirqd/N Trådar som bara körs med normal prioritet - ett klassiskt skäl till att öka svansfördröjningen. Jag observerar /proc/softirqs och /proc/net/softnet_stat; en hög „tid_squeeze“ värde eller sjunker indikerar att budgeten är för snäv. Med sysctl -w net.core.netdev_budget_usecs=8000 och sysctl -w net.core.netdev_budget=600 Jag ökar bearbetningstiden per NIC-poll och paketbudgeten som ett test. Viktigt: Jag ökar värdena gradvis, mäter och kontrollerar om CPU-jitter eller störningar i applikationstrådar uppstår.

Finjustera RSS-hash och indirektionstabell

RSS distribuerar flöden till köer via indirektionstabellen (RETA). Jag verifierar hashnyckel och tabell med ethtool -n ethX rx-flöde-hash tcp4 och ställ in fördelningen symmetriskt om så krävs. Med ethtool -X ethX equal N eller specifikt per post (ethtool -X ethX hkey ... hfunc toeplitz indir 0:1 1:3 ...) matchar jag tilldelningar till de föredragna kärnorna i en NUMA-nod. Målet är att Flöde-KlibbighetEtt flöde förblir på samma kärna så att cachelokalitet och låsretention i stacken förblir minimal. För miljöer med många korta UDP-flöden ökar jag rps_flöde_cnt per RX-kö så att programvarudistributionen har tillräckligt med skopor och inte skapar några hotspots. Jag har i åtanke att symmetriska hashes hjälper till med ECMP-topologier, men i serversammanhang är kärnbalans det som räknas mest.

Välj avlastning, GRO/LRO och ringstorlekar på ett förnuftigt sätt

Avlastning av hårdvara minskar belastningen på CPU, men kan ändra latensprofiler. Jag kontrollerar med ethtool -k ethX, om TSO/GSO/UDP_SEG på TX och GRO/LRO är aktiva på RX. GRO buntar paket i kärnan och är nästan alltid användbart för genomströmning; LRO kan vara problematiskt i routnings- eller filtreringsinställningar och är bättre att lämna där. För latens-kritiska API:er testar jag mindre GRO-aggregering (eller tillfälligt av) om p99-latens dominerar. Jag justerar också ringstorlekar via ethtool -G ethX rx 1024 tx 1024: Större ringar fångar upp bursts, men ökar fördröjningen vid överbelastning; ringar som är för små leder till rx_missade_fel. Jag förlitar mig på uppmätta värden från ethtool -S (t.ex. rx_no_buffer_count, rx_dropped) och godkänner detta med BQL (byteköbegränsningar, automatiska på kärnsidan) så att TX-köerna inte överbelastas.

Virtualisering: IRQ:er i virtuella datorer och på hypervisor

I virtualiserade konfigurationer kontrollerar jag den fysiska NIC-distributionen på värden och ställer in IRQ-balansering helt klart. De virtuella datorerna får tillräckligt med vCPU:er, men jag undviker blind överengagemang så att schemaläggningsförseningar inte ökar latensen. Moderna paravirtualiserade drivrutiner som virtio-net eller vmxnet3 ger mig de bättre vägarna för höga pps-hastigheter. Inom VM:n kontrollerar jag affinitet och köantal igen så att gästen inte blir en flaskhals. Det är viktigt att ha en konsekvent bild av värden och gästen så att hela datavägen sant.

Fördjupning i virtualisering: SR-IOV, vhost och OVS

För mycket höga pps-frekvenser använder jag hypervisor SR-IOVJag binder virtuella funktioner (VF) för det fysiska nätverkskortet direkt till virtuella datorer och kopplar dem till kärnor i lämpliga NUMA-noder. Detta förbigår delar av värdstacken och minskar latensen. Där SR-IOV inte passar in är jag uppmärksam på vhost-nät och fixera vhost-trådarna, t.ex. applikationsarbetare och IRQ-kärnor, så att inga cross-NUMA-hopp inträffar. I överlagrings- eller växlingskonfigurationer utvärderar jag extrakostnaderna för Linux Bridge eller OVS; för extrema profiler använder jag bara OVS-DPDK om den operativa ansträngningen motiverar den mätbara fördelen. Samma sak gäller här: jag mäter pps, latens och CPU-distribution innan jag fattar beslut, inte efteråt.

Upptagen pollning och tuning i användarutrymmet

För latenstidskritiska tjänster Upptagen polling minska jittern. Jag aktiverar följande som ett test sysctl -w net.core.busy_read=50 och net.core.busy_poll=50 (mikrosekunder) och ställ in socket-alternativet SO_BUSY_POLL selektivt för berörda uttag. Användarutrymmet pollar sedan strax innan blockering och fångar upp paket innan de flyttas djupare in i köerna. Detta kostar CPU-tid, men ger ofta mer stabila p99-latenstider. Jag håller värdena låga, övervakar kärnanvändningen och kombinerar endast upptagen polling med tydlig trådaffinitet och en fast CPU-guvernör, annars tar effekterna ut varandra.

En överblick över kostnaderna för paketfilter, Conntrack och eBPF

Brandväggar och NAT är en del av datavägen. Jag kontrollerar därför nftables/iptables-regler och rensar upp döda regler eller djupa kedjor. I upptagna uppställningar justerar jag Conntrack-bordets storlek (nf_conntrack_max, hash bucket number) eller avaktivera Conntrack specifikt för statslösa flöden. Om eBPF-program (XDP, tc-BPF) används mäter jag deras runtime-kostnader per hook och prioriterar „early drop/redirect“ för att avlasta dyra vägar. Det är viktigt med ett tydligt ansvar: antingen sker optimeringen i NIC-offloaden, i eBPF-programmet eller i den klassiska stacken - duplicering ökar bara latensen.

CPU-isolering och hushållskärnor

För absolut deterministisk fördröjning lagrar jag bakgrundsarbete på Hushålls-CPU:er av. Kernel-parametrar som t.ex. nohz_full=, rcu_nocbs= och irqaffinity= hjälper till att hålla dedikerade kärnor i stort sett fria från tickhantering, RCU-callbacks och externa IRQ:er. Jag isolerar en uppsättning kärnor för applikationsarbetare och en annan för IRQ:er och softirq:er; systemtjänster och timers körs på separata kärnor. Detta säkerställer rena cacheprofiler och minskar förköpseffekter. Hyper-threading kan öka jitter i enskilda fall; jag testar om avaktivering av det per kärnpar jämnar ut p99-latenserna innan jag fattar ett globalt beslut.

Diagnostisk spelbok och typiska anti-mönster

När dropp eller fördröjningstoppar inträffar använder jag ett strukturerat tillvägagångssätt: 1) /proc/avbrott Kontrollera om fördelningen är ojämn. 2) ethtool -S på RX/TX-fall, FIFO-fel, rx_no_buffer_count check. 3) /proc/net/softnet_stat till „tid_squeeze" eller "droppar“. 4) mpstat -P ALL och topp för ksoftirqd-aktivitet. 5) Applikationsmätvärden (antal aktiva anslutningar, återsändningar med ss -ti). Anti-mönster som jag undviker: stora RX-ringar (dold överbelastning), vild på- och avkoppling av avlastningar utan mätning, blandning av fasta affiniteter med aggressiv irq-balans, eller RPS och RSS samtidigt utan en tydlig målarkitektur. Varje förändring får en mätning före/efter jämförelse och ett kort protokoll.

Exempel på koncept för webbhotell och API:er

Klassisk server för webbhotell

För många små webbplatser aktiverar jag irqbalans, Jag sätter upp flera köer och väljer prestandaguvernören. Jag mäter L7-latenstider under toppar och är uppmärksam på pps-toppar, som främst inträffar med TLS och HTTP/2. Om hårdvaruköerna inte är tillräckliga lägger jag till RPS för ytterligare distribution på programvarunivå. Denna justering håller svarstiderna konstant, även om det totala kapacitetsutnyttjandet verkar måttligt. Regelbundna kontroller av /proc/avbrott visa mig om enskilda kärnor lutar.

Omvänd proxy eller API-gateway med hög belastning

För frontends med ett stort antal anslutningar pinar jag RX-köer till definierade kärnor och placerar proxyarbetare på närliggande kärnor. Jag fattar ett medvetet beslut om huruvida irqbalance ska förbli aktivt eller om fast pinning ger tydligare resultat. Om det inte finns tillräckligt med köer väljer jag RPS/XPS och kalibrerar Sammansmältning, för att undvika IRQ-stormar. Detta gör att jag kan uppnå låg latens vid en mycket hög pps-hastighet och hålla svanslatensen under kontroll. Dokumentation av varje förändring underlättar efterföljande revisioner och håller beteendet förutsägbar.

Val av leverantör och hårdvarukriterier

Jag är uppmärksam på NIC med Flera köer, tillförlitlig latens i backbone och uppdaterade kärnversioner av plattformen. Balanserad CPU-topologi och tydlig NUMA-separation förhindrar nätverksavbrott från att nå avlägsna minneszoner. För projekt med höga pps-frekvenser är valet av infrastruktur avgörande för varje timmes tuning, eftersom hårdvaran ger reserver. I praktiska jämförelser har jag arbetat bra med leverantörer som avslöjar prestandaprofiler och tillhandahåller IRQ-vänliga standardvärden, till exempel leverantörer som webhoster.de. Med sådana inställningar kan jag använda IRQ-balansering, RSS och affinitet på ett effektivt sätt och minimera svarstiderna. snäv att hålla.

Steg-för-steg-procedur för din egen tuning

Steg 1: Jag bestämmer den aktuella statusen med iperf3, sar, mpstat, nstat och ethtool -S, så att jag har tydliga initiala värden. Steg 2: Om irqbalance inte körs aktiverar jag tjänsten, väntar under belastning och jämför latens, pps och drops. Steg 3: Jag anpassar könumret och RSS-konfigurationen till kärnorna i den associerade NUMA-noden. Steg 4: Jag ställer in CPU-guvernören på „prestanda“ och tilldelar centrala tjänster till lämpliga kärnor. Steg 5: Först därefter justerar jag manuell affinitet och NUMA-pinning om de uppmätta värdena fortfarande visar på flaskhalsar. Steg 6: Jag kontrollerar trender under flera dagar för att på ett tillförlitligt sätt kunna kategorisera evenemangstoppar, säkerhetskopior eller marknadsföringstoppar.

Kortfattat sammanfattat

Effektiv IRQ-balansering fördelar nätverksarbetet över lämpliga kärnor, minskar latenserna och förhindrar avbrott vid höga pps-hastigheter. I kombination med NIC:er med flera köer, RSS/RPS, en lämplig CPU-guvernör och ren trådaffinitet använder jag nätverksstacken på ett tillförlitligt sätt. Uppmätta värden från ethtool -S, nstat, sar och iperf3 leda mig steg för steg till mitt mål istället för att famla i mörkret. Om du tänker på NUMA-topologi, IRQ-pinning och applikationsplacering tillsammans kan du hålla svarstiderna till ett minimum. låg - även under toppbelastningar. Detta innebär att hosting med hög belastning förblir märkbart responsiv utan att bränna onödiga CPU-reserver.

Aktuella artiklar