...

TCP Small Queues: ridurre in modo mirato la latenza nella rete Linux

TCP Small Queues limita, per ogni flusso TCP, il numero di byte in coda nel percorso di trasmissione di Linux, riducendo così Latenza riducendo in modo mirato anche il “bufferbloat”. Vi mostrerò come funziona questo meccanismo nel rete Linux Stack mostra come impostare limiti ragionevoli e quali interazioni si creano con il pacing, i QDisc e il controllo della congestione.

Punti centrali

  • Limite di portata: TSQ limita il numero di byte in sospeso per ogni socket TCP.
  • Meno "bufferbloat": Code più brevi riducono l'RTT.
  • Retropressione: Le applicazioni scrivono più lentamente quando viene applicato il limite.
  • Equità: Nessun singolo flusso occupa intere code.
  • Adattivo Controllo: il limite dipende dalla frequenza e dalla dimensione del segmento.

Come funziona TCP Small Queues

TSQ interviene nel punto in cui i segmenti TCP vengono QDisc e al driver. Quando scrivo dati in un socket, il kernel verifica, prima di ogni operazione di enqueue, i byte già allocati per quel flusso. Se il flusso raggiunge il limite, la logica contrassegna il socket come limitato e blocca ulteriori operazioni di enqueue. Solo quando la scheda di rete libera il buffer, il socket può tornare a trasmettere e io posso nuovamente inserire dati nello stack. Questa stretta limitazione mantiene la Code è breve e rende i tempi di reazione più prevedibili.

Perché le code lunghe aumentano i tempi di risposta

Creare code di driver e QDisc di grandi dimensioni Bufferbloat, soprattutto con TSO/GSO e volumi di trasmissione elevati. Un download di grandi dimensioni può riempire le code di uscita, mentre i flussi interattivi come SSH, le chiamate API o il VoIP vengono messi in secondo piano. La coda sovraffollata domina quindi la RTT anziché il tempo effettivo di connessione. Il controllo della congestione reagisce con lentezza, poiché gli ACK arrivano in ritardo, e prende decisioni cwnd meno efficaci. Il TSQ limita il numero di byte pre-bufferizzati per ogni flusso, in modo che i pacchetti piccoli e urgenti vengano inviati rapidamente sulla linea.

Uno sguardo “sotto il cofano”: cosa conta nel kernel

Sotto la superficie, il kernel non conta i „pacchetti“, bensì i byte; più precisamente: i byte di memoria già inseriti in coda dal socket. Ciò che conta è ciò che lo stack contiene in termini di strutture skbuff, comprese truesize è stato allocato ma non è stato ancora elaborato dal NIC. TSQ vi associa un Accelerazione/Decelerazione-Percorso: se un socket raggiunge il credito, lo stack imposta un flag di limitazione e richiama nuovamente solo dopo il completamento delle operazioni di trasmissione (NAPI/IRQ) write_space() in modo che l'applicazione possa inviare nuovamente i dati. Questo feedback è più veloce dei segnali basati esclusivamente sulle perdite provenienti dal controllo della congestione e agisce prima del QDisc. Con TSO/GSO il meccanismo rimane efficace, poiché il limite al prima di utilizza il budget di byte associato alla segmentazione: i super-frame di grandi dimensioni vengono ammessi nei QDisc solo se è disponibile credito sufficiente, il che consente di contenere i picchi di traffico.

Limiti dinamici e ritmo

Traggo vantaggio da TSQ perché il limite non rimane rigidamente statico, ma si adatta a Tasso e tiene conto della dimensione dei segmenti. L’obiettivo è di circa un millisecondo di dati nel percorso di trasmissione per ogni flusso, indipendentemente dal fatto che la velocità sia di 100 Mbit, 1 Gbit o 10 Gbit. Con una linea veloce, il credito di byte consentito aumenta, mentre con una linea lenta diminuisce. In combinazione con il TCP-Pacing, i burst rimangono piccoli e gli Ack vengono restituiti più rapidamente. In questo modo ottengo una riduzione tangibile Picchi di latenza, senza ridurre inutilmente la portata.

Interazione per socket e tra app

TSQ agisce solo se anche l'applicazione percepisce la contropressione. Prendo quindi in considerazione impostazioni quali SO_SNDBUF, TCP_NOTSENT_LOWAT e l'autocorking. Una finestra del buffer di trasmissione troppo grande può spingere molti byte nello stack in breve tempo; il TSQ rallenta, ma l'app se ne accorge solo quando send() viene bloccato o restituisce EAGAIN. Con TCP_NOTSENT_LOWAT regolo la quota „non inviata“ a livello di user space, integrando così il TSQ a livello del kernel. Autocorking (o esplicitamente TCP_CORK/MSG_MORE) aiuta a raggruppare le operazioni di scrittura di piccole dimensioni senza generare picchi di latenza. Limiti di pacing per socket (ad es. tramite SO_MAX_FREQUENZA_DI_ANDAMENTO) sono in sintonia con TSQ: la frequenza livella nel tempo, il limite di byte limita nello spazio. Importante: TCP_NODELAY Disattiva Nagle e può aumentare l'interattività, ma senza TSQ aumenta il rischio di burst; con TSQ ho entrambi sotto controllo.

Guida pratica: valori TSQ significativi

Definisco il quadro generale con net.ipv4.tcp_limit_output_bytes (Sysctl). I valori predefiniti standard oscillano tra 128 e 262 KB per flusso. Per molti carichi di lavoro web e API, scelgo valori più bassi affinché le risposte interattive rimangano veloci. Per i backup o la replica, aumento moderatamente il limite, purché l’RTT rimanga stabile. Chi desidera approfondire l’argomento delle code troverà le nozioni di base su Code di pacchetti nel server, che aiutano nella classificazione.

Scenario Tasso di collegamento Valore di riferimento tcp_limit_output_bytes Obiettivo
API/HTTP molto interattiva 100 Mbit – 1 Gbit 64–128 KB bassa RTT, punte corte
Carico misto: Web + download 1–10 Gbit 128–256 KB Equilibrio Produttività e latenza
Replica/Backup 1–10 Gbit 256–512 KB flusso di massa costante, accettabile Latenza
WAN con RTT elevato 10–100 Mbit 96–192 KB raffiche più brevi, più eque Spunti

QDisc e il controllo della congestione: come interagiscono

TSQ opera all'ingresso della QDisc, mentre algoritmi come fq_codel gestiscono la congestione sulla linea. Insieme riducono le code e garantiscono una distribuzione equa. Con TCP BBR ne traggo un ulteriore vantaggio, poiché misurazioni RTT più realistiche consentono una migliore gestione del pacing e del controllo cwnd. Anche CUBIC risponde in modo più fluido quando elimino tempi di accodamento eccessivi. In questo modo la velocità di trasmissione cresce in modo organico, mentre la Tempo di risposta rimane sotto controllo.

Virtualizzazione e stack cloud

Nelle macchine virtuali si sommano diversi livelli di buffer: QDisc dell’ospite, code virtio/vhost, QDisc dell’host e la scheda di rete fisica. Mantengo attivo il TSQ nell’ospite e imposto lì un limite prudente, in modo che non arrivino picchi di traffico ingenti all’host. A livello di hypervisor, garantisco catene di latenza brevi utilizzando QDisc equi, anelli TX moderati e un IRQ pinning pulito. L’SR-IOV può ridurre la latenza, ma trasferisce la responsabilità agli ospiti: senza il TSQ nell’ospite si rischia di avere code VF lunghe. Nei container, il TSQ interviene per NetNS come al solito; tramite il cgroup pacing e i limiti della CPU impedisco che un vicino rumoroso aumenti indirettamente la latenza. È importante anche prestare attenzione al coalescing e agli offload nel percorso virtio: un raggruppamento eccessivo allunga gli Ack, uno insufficiente riduce l’efficienza – io regolo in base all’obiettivo di latenza, senza essere dogmatico.

Wi-Fi e sistemi embedded: come gestire correttamente i casi particolari

Sui collegamenti Wi-Fi, ciò che conta è la Aggregazione nel livello MAC. Se lascio un numero insufficiente di byte nel percorso di trasmissione, il driver può raggruppare meno frame, riducendo così l’efficienza. In configurazioni di questo tipo, aumento con cautela il limite e verifico il grado di aggregazione. Le piattaforme OpenWrt ed embedded traggono inoltre vantaggio da percorsi snelli nei driver e da un numero ridotto di operazioni atomiche. Testo ogni modifica sotto carico di traffico radio reale prima di Profilo lo stendo bene.

Monitoraggio e metriche che contano davvero

Osservo il RTT- Distribuzione per socket e osservo i valori anomali, non solo le medie. Con ss, tc e gli esportatori leggo le lunghezze delle code, le ritrasmissioni e il pacing_rate. I programmi eBPF mi forniscono eventi quando i socket vengono limitati e poi liberati nuovamente. Il «time-to-first-byte» e i percentili 95° e 99° indicano se il TSQ sta funzionando. Senza valori di misurazione, ogni Ottimizzazione un volo alla cieca.

Test A/B e di carico significativi

Misuro gli effetti TSQ in modo riproducibile: prima la linea di base senza modifiche, poi le variazioni isolate dei parametri (ad es. 64, 96, 128, 192 KB). Per i carichi di lavoro misti eseguo flussi paralleli (bulk + molte richieste brevi) e confronto il 95° e il 99° percentile delle latenze, non solo la mediana. Anche se interrompo chiaramente le sessioni di test (warm-up, finestra di misurazione, cool-down), gli artefatti rimangono riconoscibili. Presto attenzione alle costanti: stessi modelli di payload, percorso/MTU identici, frequenze della CPU del server e del client identiche. Sulle tratte WAN simulo ritardo/jitter/perdita con tc netem, per verificare che i limiti TSQ non raggiungano il tetto massimo troppo presto in caso di BDP elevato. Solo quando i percentili si restringono e le ritrasmissioni/perdite rimangono stabili, inserisco i valori nella produzione.

Ottimizzazione hardware e dettagli sui driver

Verifico le impostazioni TSO/GSO, il buffer circolare della scheda di rete e il controllo degli IRQ, in modo che TSQ funziona in modo ottimale. Gli anelli TX troppo grandi allungano la coda in attesa sul dispositivo; quelli troppo piccoli riducono l’utilizzo delle risorse. Un raggruppamento grossolano degli interrupt ritarda gli Ack, mentre un raggruppamento fine aumenta il carico della CPU. Adatto la moderazione in base alle esigenze pratiche e, per iniziare, rimando a Interruzione della coalescenza. L'obiettivo rimane quello di garantire un servizio affidabile Latenza con una produttività sostenibile.

NUMA, RSS e affinità della CPU

Le code brevi servono a poco se i pacchetti attraversano continuamente i confini NUMA. Associo le code RX/TX tramite RSS/irqbalance ai core dello stesso dominio NUMA su cui gira l’applicazione. Con XPS/RPS controllo quali CPU si occupano del lavoro TX, evitando così i „cross-socket hopper“. Un minor numero di cache miss e una minore contesa sui lock aiutano indirettamente TSQ: i completamenti tornano più velocemente, il socket viene “sbloccato” prima e non si verificano picchi di latenza. In presenza di un numero molto elevato di flussi per host, pianifico un numero sufficiente di code ed evito che più flussi intensi entrino in collisione sullo stesso anello TX.

Passo dopo passo: verificare lo stato di TSQ

Inizio con uno sguardo a Sysctl: Il comando `sysctl net.ipv4.tcp_limit_output_bytes` mostra il limite attuale. Successivamente, utilizzo `ss -tin` per analizzare i singoli socket, prestando attenzione a `send-q` e `rtt`, e confronto le fasi di carico con e senza regolazione del limite. Con iperf3 genero un carico in background e misuro in parallelo i tempi di risposta delle API per rendere visibili le priorità. tc -s qdisc mi fornisce il numero di pacchetti e di drop della disciplina in uscita. Se il 95° e il 99° percentile rimangono ravvicinati e il CPU- Carico nel telaio, la scelta del limite è adeguata.

Errori comuni e anti-pattern

  • „Più buffer = più prestazioni“: vale per i test di throughput senza obiettivi di latenza, ma non funziona con i servizi interattivi. TSQ sostituisce le code sovradimensionate con un credito adeguato alle esigenze per ogni flusso.
  • „Il TSQ incide sulla produttività“: se impostato correttamente, il TSQ limita i picchi, non la velocità media. Per i carichi di lavoro di massa, aumento moderatamente il limite e misuro i percentili anziché limitarmi al picco in Mbit/s.
  • „Il pacing da solo è sufficiente“: la livellazione temporale è importante, ma senza un limite di byte i frame GSO di grandi dimensioni finiscono comunque nel QDisc. TSQ e pacing si completano a vicenda.
  • „Un valore unico per tutti“: i carichi di lavoro, i collegamenti e le schede di rete sono diversi. Lavoro con valori di intervallo e effettuo la convalida per ogni ambiente.
  • „Solo il TCP è interessato“: l'attenzione è rivolta al TCP, ma nel sistema ci sono altri parametri di regolazione (ad esempio per il carico UDP). Impedisco che i protocolli paralleli intasino in modo incontrollato le stesse code.

Conclusione: la latenza sotto controllo in modo mirato

TSQ trasferisce il controllo delle code dei driver al Presa riducendo così la congestione direttamente alla fonte. Limito i byte pre-bufferizzati per ogni flusso, garantendo così Ack rapidi, RTT più bassi e code equamente distribuite. In combinazione con fq_codel e un controllo della congestione all’avanguardia, il tempo di risposta rimane affidabile anche sotto carico. Tratto i casi particolari relativi al Wi-Fi e ai sistemi embedded con limiti adeguati e test in condizioni reali. Chi monitora gli indicatori e regola i limiti gradualmente, mantiene la Latenza costantemente basso, senza perdere inutili portate.

Articoli attuali

Server con TCP Small Queues ottimizzate per ridurre la latenza di rete
Server e macchine virtuali

TCP Small Queues: ridurre in modo mirato la latenza nella rete Linux

La funzione TCP Small Queues nel kernel Linux limita il numero di pacchetti TCP bufferizzati per flusso ed è uno strumento potente per l'ottimizzazione della latenza. Scopri come TSQ riduce il bufferbloat e migliora i tempi di risposta dei server.

Centro dati con rack di server e visualizzazione stilizzata dei dati per l’ottimizzazione delle prestazioni di MySQL
Banche dati

Istogrammi MySQL – Piani di query ottimizzati senza indici

Scopri come gli istogrammi di MySQL forniscono all’ottimizzatore statistiche precise, consentono di ottenere piani di query migliori e migliorano notevolmente l’ottimizzazione SQL senza bisogno di indici aggiuntivi.