...

Bilanciamento degli IRQ del server e prestazioni di rete per l'hosting ad alto carico

Il carico di rete elevato è determinato dall'elaborazione efficiente di IRQ del server segnali: Se si distribuiscono saggiamente gli interrupt tra i core della CPU, si riduce la latenza e si prevengono le cadute. In questa guida vi mostrerò come combinare il bilanciamento degli IRQ, l'RSS/RPS e l'affinità della CPU in modo pratico per rendere sostenibile l'hosting ad alto carico. performante per operare.

Punti centrali

  • Distribuzione IRQ impedisce la formazione di punti caldi sui singoli core della CPU.
  • Multi-queue più RSS/RPS parallelizza l'elaborazione dei pacchetti.
  • Attenzione NUMA riduce l'accesso e la latenza tra i nodi.
  • Governatore della CPU e il pinning dei thread riducono i tempi di risposta.
  • Monitoraggio Controlla pps, latenze, cadute e utilizzo dei core.

Gli IRQ spiegati brevemente: perché controllano il carico di rete

Per ogni pacchetto in arrivo, la scheda di rete segnala via IRQ, che il lavoro è in attesa, altrimenti il kernel dovrebbe eseguire un polling attivo. Se l'assegnazione rimane su un core, il suo utilizzo aumenta, mentre altri core inutilizzato rimangono. Questo è esattamente il momento in cui le latenze aumentano, i buffer dell'anello RX si riempiono e i driver iniziano a scartare i pacchetti. Distribuisco gli interrupt tra i core adatti per mantenere l'elaborazione dei pacchetti uniforme e prevedibile. In questo modo si eliminano i colli di bottiglia, i tempi di risposta sono più fluidi e le perdite di pacchetti sono ridotte al minimo.

Bilanciamento degli IRQ e affinità della CPU in Linux

Il servizio irqbalance distribuisce gli interrupt dinamicamente, analizza il carico e sposta automaticamente le affinità nel tempo. Per i profili di carico estremi, definisco manualmente le affinità tramite /proc/irq//smp_affinity e legare le indicazioni in modo specifico ai nuclei dello stesso NUMA-nodi. Questa combinazione di automatismo e regolazione fine mi aiuta a elaborare in modo pulito sia i carichi di base che i picchi. Un'introduzione approfondita a Gestione degli interrupt e ottimizzazione della CPU Li uso per aiutarmi nella pianificazione. Rimane importante: Collego costantemente la topologia dell'hardware, la distribuzione degli IRQ e i thread delle applicazioni tra loro.

Uso pratico di NIC multi-queue, RSS e RPS

Le moderne NIC forniscono diverse code RX/TX; ogni coda attiva la propria IRQ, e Receive Side Scaling (RSS) distribuisce i flussi ai core. Se le code hardware non sono sufficienti, aggiungo al kernel il Receive Packet Steering (RPS) e il Transmit Packet Steering (XPS) per ottenere un'ulteriore Parallelismo. Con ethtool -L ethX combinato N Adeguo il numero di coda al numero di core del nodo NUMA associato. Controllo con ettool -S e nstat, se si verificano cadute, polls occupati o picchi elevati di pps. Per un livellamento più fine del carico, uso anche Interruzione della coalescenza nella pianificazione, in modo che la NIC non generi troppi IRQ individuali.

La tabella seguente mostra i componenti centrali e i comandi tipici che utilizzo per una configurazione coerente:

Blocco di costruzione Obiettivo Esempio Suggerimento
irqbalance Distribuzione automatica systemctl enable --now irqbalance Punto di partenza per carichi di lavoro misti
Affinità Corregge il Pinning echo mask > /proc/irq/XX/smp_affinity Osservare l'assegnazione NUMA
Spunti Più parallelismo ethtool -L ethX combinato N Corrispondenza con i core del nodo
RSS/RPS Distribuzione del flusso sysfs: rps_cpus/rps_flow_cnt Utile per un numero ridotto di code NIC
XPS Nuclei ordinati del percorso TX sysfs: xps_cpus Evita il thrash della cache

Uso sensato del bilanciamento automatico degli IRQ

Per i server di hosting misti, spesso è sufficiente attivare irqbalance, perché il demone riconosce costantemente i cambiamenti di carico. Controllo lo stato tramite systemctl status irqbalance e dare un'occhiata a /proc/interruzioni, per vedere la distribuzione per coda e core. Se le latenze aumentano nei picchi, definisco dei core di prova che elaborano principalmente gli interrupt e confronto i valori misurati prima e dopo la modifica. Mantengo la configurazione semplice, in modo che le verifiche successive e i rollback siano rapidi. Solo quando gli schemi sono chiari, approfondisco il tema del pinning.

Affinità manuale della CPU per il massimo controllo

In caso di velocità di trasmissione molto elevate, collego le code RX a core selezionati dello stesso sistema. NUMA-e separo deliberatamente i thread dell'applicazione da essi. Isolo i singoli core per gli interrupt, eseguo i worker su core vicini e presto molta attenzione alla localizzazione della cache. In questo modo, riduco gli accessi cross-node e minimizzo i costosi passaggi di contesto nel percorso caldo. Per ottenere risultati riproducibili, documento chiaramente le maschere IRQ, l'assegnazione delle code e l'affinità dei thread dei servizi. Questa chiarezza consente di mantenere i tempi di esecuzione dei pacchetti costante e riduce i valori anomali.

Coordinamento pulito dell'ottimizzazione della CPU e delle applicazioni

Ho impostato il Governatore della CPU spesso impostato su „performance“ perché le variazioni di clock aumentano i salti di latenza. Lego i processi critici come Nginx, HAProxy o i database a core vicini ai core IRQ, oppure li separo deliberatamente se il profilo della cache lo richiede. Rimane importante limitare i cambiamenti di contesto e mantenere il kernel aggiornato in modo che le ottimizzazioni dello stack di rete abbiano effetto. Misuro gli effetti di ogni cambiamento invece di fare ipotesi e mi adatto passo dopo passo. Il risultato è una configurazione che funziona sotto carico prevedibile reagisce.

Impostare correttamente il monitoraggio e la misurazione

Senza valori misurati, la messa a punto rimane un gioco di ipotesi, quindi inizierò con sar, mpstat, vmstat, nstat, ss e ettool -S. Per i test di carico strutturati utilizzo iperf3 e analizzo throughput, pps, latenza, ritrasmissioni e utilizzo del core. Registro le tendenze a lungo termine utilizzando sistemi di monitoraggio standard per riconoscere modelli come i picchi serali, le finestre di backup o le campagne. Se si vuole comprendere il percorso dei dati in modo olistico, si può trarre vantaggio da una visione del Pipeline di elaborazione dei pacchetti dall'IRQ della NIC allo spazio utente. Solo la combinazione di questi segnali mostra se il bilanciamento e l'affinità IRQ hanno ottenuto l'effetto desiderato. Effetto portare.

Comprendere NAPI, Softirqs e ksoftirqd

Per gestire i picchi di latenza con carichi elevati di pps, tengo conto della NAPI-e l'interazione tra IRQ hard e IRQ soft. Dopo il primo IRQ hardware, NAPI recupera diversi pacchetti dalla coda RX in modalità poll per evitare le tempeste di IRQ. Se gli IRQ soft non vengono processati tempestivamente, vengono spostati in ksoftirqd/N Thread che vengono eseguiti solo con priorità normale: un motivo classico per aumentare le latenze di coda. Osservo /proc/softirqs e /proc/net/softnet_stat; un alto „tempo_schiacciamento“Il valore o i cali indicano che il budget è troppo limitato. Con sysctl -w net.core.netdev_budget_usecs=8000 e sysctl -w net.core.netdev_budget=600 Aumento il tempo di elaborazione per poll NIC e il budget dei pacchetti come test. Importante: aumento i valori gradualmente, misuro e verifico se si verifica un jitter della CPU o un'interferenza con i thread dell'applicazione.

Messa a punto dell'hash RSS e della tabella di indirezione

RSS distribuisce i flussi alle code tramite la tabella di indirezione (RETA). Verifico la chiave hash e la tabella con ethtool -n ethX rx-flow-hash tcp4 e, se necessario, impostare la distribuzione in modo simmetrico. Con ethtool -X ethX uguale N o specificamente per voce (ethtool -X ethX hkey ... hfunc toeplitz indir 0:1 1:3 ...), abbino le assegnazioni ai core preferiti di un nodo NUMA. L'obiettivo è Appiccicosità del flussoUn flusso rimane sullo stesso core, in modo che la localizzazione della cache e la conservazione dei blocchi nello stack rimangano minime. Per gli ambienti con molti flussi UDP brevi, aumento rps_flow_cnt per coda RX, in modo che la distribuzione del software abbia un numero sufficiente di bucket e non crei hotspot. Tengo presente che gli hash simmetrici aiutano con le topologie ECMP, ma nel contesto dei server l'equilibrio dei core è ciò che conta di più.

Scegliere in modo oculato gli scarichi, GRO/LRO e le dimensioni degli anelli

Gli offload hardware riducono il carico sulla CPU, ma possono modificare i profili di latenza. Verifico con ethtool -k ethX, se TSO/GSO/UDP_SEG su TX e GRO/LRO sono attivi su RX. GRO aggrega i pacchetti nel kernel ed è quasi sempre utile per il throughput; LRO può essere problematico nelle configurazioni di routing o filtraggio ed è meglio lasciarlo disattivato. Per le API critiche per la latenza, provo un'aggregazione GRO più piccola (o temporaneamente disattivata) se le latenze di p99 dominano. Regolo anche le dimensioni degli anelli tramite ethtool -G ethX rx 1024 tx 1024Anelli più grandi intercettano i burst, ma aumentano la latenza in caso di congestione; anelli troppo piccoli portano a rx_missed_errors. Mi affido ai valori misurati da ettool -S (es. rx_no_buffer_count, rx_dropped) e concordare questo con BQL (limiti delle code di byte, automatici sul lato kernel) in modo da non sovraccaricare le code di TX.

Virtualizzazione: IRQ nelle macchine virtuali e nell'hypervisor

Nelle configurazioni virtualizzate, controllo la distribuzione della NIC fisica sull'host e imposto Bilanciamento IRQ chiaramente. Le macchine virtuali ricevono abbastanza vCPU, ma evito l'overcommitment cieco in modo che i ritardi di pianificazione non aumentino la latenza. I moderni driver paravirtualizzati, come virtio-net o vmxnet3, mi forniscono i percorsi migliori per ottenere elevate velocità di trasmissione. All'interno della macchina virtuale, controllo di nuovo l'affinità e il numero di code in modo che il guest non diventi un collo di bottiglia. È fondamentale avere una visione coerente dell'host e del guest in modo che l'intero percorso dati vero.

Approfondimento della virtualizzazione: SR-IOV, vhost e OVS

Per velocità di trasmissione molto elevate, utilizzo l'hypervisor SR-IOVLego le funzioni virtuali (VF) della NIC fisica direttamente alle macchine virtuali e le collego ai core dei nodi NUMA appropriati. In questo modo si bypassano parti dello stack dell'host e si riduce la latenza. Dove SR-IOV non è adatto, faccio attenzione a vhost-rete e bloccare i thread del vhost, come gli application worker e i core IRQ, in modo che non si verifichino salti cross-NUMA. Nelle configurazioni overlay o switching, valuto i costi aggiuntivi di Linux bridge o OVS; per i profili estremi, utilizzo OVS-DPDK solo se lo sforzo operativo giustifica il vantaggio misurabile. Lo stesso vale in questo caso: misuro pps, latenza e distribuzione della CPU prima di prendere decisioni, non dopo.

Polling occupato e messa a punto dello spazio utente

Per i servizi critici per la latenza Sondaggio occupato ridurre il jitter. Ho attivato il seguente test sysctl -w net.core.busy_read=50 e net.core.busy_poll=50 (microsecondi) e impostare l'opzione socket SO_BUSY_POLL selettivamente per i socket interessati. Lo spazio utente esegue il polling poco prima del blocco e cattura i pacchetti prima che si spostino nelle code. Questo costa tempo alla CPU, ma spesso fornisce latenze p99 più stabili. Mantengo bassi i valori, monitoro l'utilizzo dei core e combino il polling occupato solo con una chiara affinità dei thread e un governatore fisso della CPU, altrimenti gli effetti si annullano a vicenda.

I costi di Parcel Filter, Conntrack e eBPF in sintesi

Il firewalling e il NAT fanno parte del percorso dei dati. Pertanto, verifico il nftables/iptables-e riordinare le regole morte o le catene profonde. Nelle configurazioni più impegnative, regolo la dimensione della tabella Conntrack (nf_conntrack_max, numero di hash bucket) o disattivare Conntrack specificamente per i flussi stateless. Se si utilizzano programmi eBPF (XDP, tc-BPF), misuro i loro costi di runtime per hook e do priorità a „early drop/redirect“ per alleggerire i percorsi costosi. È importante che la responsabilità sia chiara: l'ottimizzazione viene effettuata nell'offload della NIC, nel programma eBPF o nello stack classico - la duplicazione aumenta solo la latenza.

Isolamento della CPU e core di mantenimento

Per una latenza assolutamente deterministica, memorizzo il lavoro in background su CPU di manutenzione off. I parametri del kernel, come nohz_full=, rcu_nocbs= e irqaffinità= aiutano a mantenere i core dedicati ampiamente liberi dalla gestione dei tick, dai callback RCU e dagli IRQ esterni. Isolo un gruppo di core per gli application worker e un altro per gli IRQ e i softirq; i servizi di sistema e i timer vengono eseguiti su core separati. Questo assicura profili di cache puliti e riduce gli effetti di prelazione. L'hyper-threading può aumentare il jitter in singoli casi; verifico se la sua disattivazione per ogni coppia di core attenua le latenze di p99 prima di prendere una decisione globale.

Manuale di diagnostica e tipici anti-pattern

Quando si verificano cadute o picchi di latenza, seguo un approccio strutturato: 1) /proc/interruzioni Controllare che non vi sia una distribuzione non uniforme. 2) ettool -S su cadute RX/TX, errori FIFO, rx_no_buffer_count controllo. 3) /proc/net/softnet_stat a „tempo_schiacciamento" o "gocce“. 4) mpstat -P TUTTI e top per l'attività di ksoftirqd. 5) Metriche dell'applicazione (numero di connessioni attive, ritrasmissioni con ss -ti). Antipattern che evito: anelli RX enormi (congestione nascosta), accensione/spegnimento selvaggio di offload senza misurazioni, mescolanza di affinità fisse con irqbalance aggressivo, o RPS e RSS simultaneamente senza un'architettura target chiara. Ogni modifica viene confrontata con una misura prima/dopo e con un breve protocollo.

Concetti esemplificativi per l'hosting web e le API

Server di web hosting classico

Per molti piccoli siti web attivo irqbalance, Configuro diverse code e seleziono il governatore delle prestazioni. Misuro le latenze L7 durante i picchi e faccio attenzione ai picchi di pps, che si verificano principalmente con TLS e HTTP/2. Se le code hardware non sono sufficienti, aggiungo RPS per una distribuzione aggiuntiva a livello software. Questa regolazione mantiene i tempi di risposta costante, anche se l'utilizzo complessivo della capacità appare moderato. Controlli regolari di /proc/interruzioni mi mostra se i singoli nuclei si stanno inclinando.

Proxy inverso ad alto carico o gateway API

Per i frontend con un numero elevato di connessioni, applico le code RX in modo mirato a determinati core e posiziono i proxy worker sui core vicini. Decido consapevolmente se irqbalance rimane attivo o se il pinning fisso offre risultati più chiari. Se non ci sono code sufficienti, seleziono RPS/XPS e calibro Coalescenza, per evitare le tempeste di IRQ. Questo mi permette di ottenere una bassa latenza con una velocità di trasmissione molto elevata e di tenere sotto controllo le latenze di coda. La documentazione di ogni modifica facilita le verifiche successive e mantiene il comportamento prevedibile.

Scelta del fornitore e criteri di hardware

Presto attenzione alle NIC con Multi-queue, latenza affidabile nella spina dorsale e versioni aggiornate del kernel della piattaforma. La topologia bilanciata delle CPU e la netta separazione NUMA impediscono agli interrupt di rete di raggiungere le zone di memoria remote. Per i progetti con alti tassi di pps, la scelta dell'infrastruttura onora ogni ora di messa a punto perché l'hardware fornisce riserve. Nei confronti pratici, ho lavorato bene con i provider che rivelano i profili delle prestazioni e forniscono impostazioni predefinite IRQ-friendly, come ad esempio provider come webhoster.de. Tali configurazioni mi consentono di utilizzare efficacemente il bilanciamento degli IRQ, l'RSS e l'affinità e di ridurre al minimo i tempi di risposta. stretto per tenere.

Procedura passo-passo per la propria messa a punto

Fase 1: Determino lo stato attuale con iperf3, sar, mpstat, nstat e ettool -S, in modo da avere chiari i valori iniziali. Fase 2: Se irqbalance non è in esecuzione, attivo il servizio, attendo sotto carico e confronto latenza, pps e cadute. Fase 3: Adeguo il numero di coda e la configurazione RSS ai core del nodo NUMA associato. Passo 4: Ho impostato il governor della CPU su „performance“ e ho assegnato i servizi centrali ai core appropriati. Passo 5: Solo allora modifico l'affinità manuale e il pinning NUMA se i valori misurati mostrano ancora colli di bottiglia. Passo 6: Verifico le tendenze nel corso dei giorni per classificare in modo affidabile i picchi di eventi, i backup o i picchi di marketing.

Riassumendo brevemente

Efficace Bilanciamento IRQ distribuisce il lavoro di rete tra i core adatti, riduce le latenze e previene le cadute a velocità elevate. In combinazione con NIC multi-queue, RSS/RPS, un governor CPU adeguato e un'affinità di thread pulita, utilizzo in modo affidabile lo stack di rete. Valori misurati da ettool -S, nstat, sar e iperf3 mi guidano passo dopo passo verso il mio obiettivo, invece di brancolare nel buio. Se si pensa alla topologia NUMA, al pinning IRQ e al posizionamento delle applicazioni, è possibile ridurre al minimo i tempi di risposta. basso - anche durante i picchi di carico. Ciò significa che l'hosting ad alto carico rimane sensibilmente reattivo senza bruciare inutili riserve di CPU.

Articoli attuali