Mostro come Server di bilanciamento NUMA sull'hardware di hosting ottimizza l'accesso alla memoria e riduce le latenze vincolando i processi e i dati al nodo NUMA appropriato. Il fattore decisivo è il Ottimizzazione dell'accesso alla memoria attraverso l'accesso locale, il posizionamento dei task e la migrazione mirata delle pagine su host Linux con molti core.
Punti centrali
- NUMA separa le CPU e la memoria in nodi; gli accessi locali forniscono basso Latenza.
- Automatico Il bilanciamento NUMA migra le pagine e posiziona i task vicino al nodo.
- Dimensione della macchina virtuale per nodo, altrimenti c'è il rischio Cestino NUMA.
- Strumenti come numactl, lscpu, numad mostrano Topologia e l'uso.
- SintonizzazioneStati C, Interleaving dei nodi da, Pagine enormi, affinità.
Cos'è NUMA e perché è importante per l'hosting
NUMA divide un sistema multiprocessore in Nodo, che contengono ciascuno la propria CPU e la propria memoria locale, rendendo gli accessi vicini più veloci di quelli remoti. Mentre UMA invia tutti i core a un percorso comune, NUMA previene i colli di bottiglia dovuti a locale canali di memoria per nodo. Negli ambienti di hosting con molte macchine virtuali parallele, ogni millisecondo di latenza si somma, quindi ogni richiesta ne trae un vantaggio misurabile. Se desiderate ulteriori informazioni di base, potete trovare maggiori informazioni su Architettura NUMA. Per me, una cosa è certa: se si comprendono e si utilizzano i nodi, si ottiene una maggiore larghezza di banda dallo stesso hardware.
Bilanciamento automatico NUMA nel kernel Linux - come funziona
Il kernel esegue periodicamente la scansione di parti dello spazio degli indirizzi e „disimpegna“ le pagine in modo che un errore di hinting possa ottimale nodo visibile. Se si verifica un errore, l'algoritmo valuta se vale la pena migrare la pagina o spostare il task ed evita spostamenti non necessari. Migrare su guasto porta Dati più vicino alla CPU in esecuzione, il posizionamento dei task NUMA avvicina i processi alla loro memoria. Lo scanner distribuisce il suo lavoro pezzo per pezzo in modo che l'overhead rimanga all'interno del rumore del carico normale. In questo modo si ottiene una continua messa a punto che riduce la latenza senza richiedere regole di pinning rigide.
Ottimizzazione dell'accesso alla memoria: locale batte remoto
Gli accessi locali utilizzano il metodo Controllore di memoria del proprio nodo e ridurre al minimo i tempi di attesa per l'interconnessione. Gli accessi remoti costano cicli tramite QPI/UPI o Infinity Fabric e quindi minimizzano il tempo di accesso effettivo. Larghezza di banda. Un numero elevato di core esacerba questo effetto perché sempre più core competono per le stesse connessioni. Per questo motivo, pianifico in modo che il codice caldo e i dati attivi si trovino insieme su un unico nodo. Se non si tiene conto di questo aspetto, si perdono punti percentuali che determinano il tempo di risposta o il timeout durante i picchi di carico.
Dimensioni delle macchine virtuali, cestino NUMA e ritaglio dell'host
Dimensiono le macchine virtuali in modo che le vCPU e la RAM si adattino a un nodo NUMA per evitare l'accesso trasversale ai nodi. Spesso 4-8 vCPU per nodo forniscono buone prestazioni. Tassi di successo, a seconda della piattaforma e della gerarchia della cache. Le pagine di grandi dimensioni sono utili anche perché il TLB funziona in modo più efficiente e le migrazioni di pagina sono meno frequenti. Se necessario, imposto Affinità della CPU per i processi critici dal punto di vista della latenza per associare i thread ai core adatti - per ulteriori informazioni vedere Affinità della CPU. Se si distribuiscono le macchine virtuali tra i vari nodi, si rischia il NUMA trashing, ovvero un ping-pong di dati e thread.
Strumenti in pratica: numactl, lscpu, numad
Con „lscpu“ leggo Topologia e i nodi NUMA, compresa l'assegnazione dei core. „numactl -hardware“ mostra la memoria per nodo e le distanze disponibili, rendendo più facile la valutazione dei percorsi. Il demone „numad“ monitora l'utilizzo e regola dinamicamente le affinità quando i centri di carico si spostano. Per gli scenari fissi, uso „numactl -cpunodebind/-membind“ per bloccare esplicitamente processi e memoria. In questo modo, combino il bilanciamento automatico con specifiche mirate e controllo il risultato tramite „perf“, „numastat“ e „/proc“.
Come misuro l'impatto: Cifre e comandi chiave
Valuto sempre la sintonizzazione NUMA tramite Serie di misure, non per istinto. Tre indicatori hanno dimostrato la loro validità: Rapporto tra visualizzazioni di pagine locali e remote, tasso di migrazione e distribuzione della latenza (P95/P99).
- A livello di sistemanumastat„ mostra gli accessi locali/remoti e le pagine migrate per nodo.
- Legato al processo: „/proc//numa_maps“ rivela dove si trova la memoria e come è stata distribuita.
- Vista del pianificatoreCpus_allowed_list„ e il vero “Cpus_allowed„ controllano se i vincoli sono applicabili.
# Vista a livello di sistema
numastat
numastat -m
# Distribuzione e binding relativi al processo
pid=$(pidof )
numastat -p "$pid"
cat /proc/"$pid"/numa_maps | head
cat /proc/"$pid"/status | grep -E 'Cpus_allowed_list|Mems_allowed_list'
taskset -cp "$pid"
# Contatore del kernel per l'attività NUMA
grep -E 'numa|migrate' /proc/vmstat
# Eventi di tracciamento per analisi approfondite (attivare per un breve periodo)
echo 1 > /sys/kernel/debug/tracing/events/mm/enable
sleep 5; cat /sys/kernel/debug/tracing/trace | grep -i numa; echo 0 > /sys/kernel/debug/tracing/events/mm/enable
Confronto in ogni caso A/BUnbound vs. bound, bilanciamento automatico on/off e diverse fette di macchine virtuali. L'obiettivo è una netta riduzione degli accessi remoti e del rumore di migrazione, nonché latenze P95/P99 più strette. Solo quando i valori misurati saranno stabilmente migliori, mi occuperò della messa a punto.
Impostazioni del BIOS e del firmware che funzionano davvero
Disattivo „Node Interleaving“ nel BIOS in modo che la struttura NUMA rimanga visibile e che il kernel locale può pianificare. La riduzione degli stati C stabilizza i picchi di latenza perché è meno probabile che i core cadano in stati di sonno profondo, risparmiando così il tempo di risveglio. Alloco i canali di memoria in modo simmetrico, in modo che ogni nodo possa utilizzare la sua capacità massima di memoria. Larghezza di banda raggiunto. Verifico i prefetcher e le funzionalità RAS con i profili di carico di lavoro, in quanto aiutano o danneggiano a seconda del modello di accesso. Misuro ogni modifica rispetto a una linea di base e solo allora adotto l'impostazione in modo permanente.
Parametri del kernel e di sysctl che fanno la differenza
La messa a punto del kernel mi aiuta, Spese generali e Tempo di risposta del bilanciatore per adattarlo al carico di lavoro. Inizio con valori predefiniti conservativi e procedo passo dopo passo.
- kernel.numa_balancingAttivazione/disattivazione del bilanciamento automatico. Lo lascio attivo per i carichi in movimento; lo spengo per i servizi speciali rigorosamente appuntati come prova.
- kernel.numa_balancing_scan_delay_msTempo di attesa prima della prima scansione dopo la creazione del processo. Selezionare un valore maggiore se sono in esecuzione molti task di breve durata; un valore minore per i servizi di lunga durata che richiedono una vicinanza rapida.
- kernel.numa_balancing_scan_period_min_ms / _max_msLarghezza di banda degli intervalli di scansione. Gli intervalli più stretti aumentano la reattività, ma anche il carico della CPU.
- kernel.numa_balancing_scan_size_mbPercentuale dello spazio degli indirizzi per scansione. Se troppo grande genera tempeste di hint-fault, se troppo piccola reagisce con lentezza.
- vm.zone_reclaim_modeQuando la memoria è scarsa, il kernel privilegia il recupero locale rispetto all'allocazione remota. Per i carichi di lavoro generali dell'hosting di solito lascio 0; Per i servizi di memoria locale strettamente sensibili alla latenza, verifico attentamente valori più elevati.
- Pagine enormi trasparenti (THP)Sotto „/sys/kernel/mm/transparent_hugepage/{enabled,defrag}“ di solito ho impostato su madvise e la deframmentazione conservativa. I profili „sempre“ hard portano vantaggi al TLB, ma rischiano di andare in stallo a causa della compattazione.
- sched_migration_cost_nsStima dei costi per la migrazione dei task. Valori più alti attenuano la ridistribuzione degli schedulatori aggressivi.
- cgroups cpusetCon cpuset.cpus e cpuset.mems Separo i servizi in modo pulito per nodo e mi assicuro che Primo tocco rimane all'interno dei nodi consentiti.
# Esempio: bilanciamento conservativo ma reattivo
sysctl -w kernel.numa_balancing=1
sysctl -w kernel.numa_balancing_scan_delay_ms=30000
sysctl -w kernel.numa_balancing_scan_period_min_ms=60000
sysctl -w kernel.numa_balancing_scan_period_max_ms=300000
sysctl -w kernel.numa_balancing_scan_size_mb=256
# Usare THP con attenzione
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
echo defer > /sys/kernel/mm/transparent_hugepage/defrag
Rimane importante: Cambiare solo una vite di regolazione per ogni giro di prova e verificare l'effetto con la stessa curva di carico. È così che distinguo la causa dall'effetto.
Posizionare correttamente i carichi di lavoro: Database, cache, container
I database traggono vantaggio quando i buffer pool rimangono locali per ogni nodo NUMA e i thread sono legati ai loro heap. Nelle cache in memoria ho impostato lo sharding su Nodo per evitare i recuperi remoti. Le piattaforme di container ricevono limiti e richieste in modo che i pod non saltino da un nodo all'altro. Per le riserve di memoria, uso Huge Pages, che rende più facile memorizzare gli hotset in Cache adatta. La tabella seguente riassume le strategie e gli effetti tipici in forma compatta.
| Strategia | Utilizzo | Effetto previsto | Suggerimento |
|---|---|---|---|
| Primo tocco | Database, heap della JVM | Assegnazione lato locale | Eseguire l'inizializzazione sul nodo di destinazione |
| Interleave | Carico ampiamente distribuito | Distribuzione uniforme | Non ottimale per gli hotspot |
| Appuntamenti dei compiti | Servizi critici per la latenza | Latenza costante | Meno flessibile durante le variazioni di carico |
| Bilanciamento automatico | Carichi di lavoro misti | Prossimità dinamica | Pesare le spese generali rispetto ai profitti |
| Pagine enormi | Grandi cumuli, cache | Meno errori TLB | Pianificare prenotazioni pulite |
Virtualizzazione: NUMA virtuale, scheduler e personalizzazione del guest
Virtual NUMA passa la topologia dell'host al sistema operativo guest in una forma semplificata, in modo che il first-touch e il Allocatore lavorare in modo sensato. Gli schedulatori dell'Hypervisor prestano attenzione alla vicinanza dei nodi quando distribuiscono le vCPU e migrano le macchine virtuali. Raramente allineo VM di grandi dimensioni su più nodi, a meno che il carico di lavoro non sia ampiamente distribuito e benefici dell'interleave. Nel guest, personalizzo gli heap delle JVM o dei database in modo che rimangano locali sui nodi NUMA visibili. Per la gestione della memoria nel guest, date un'occhiata a Memoria virtuale, per controllare le dimensioni delle pagine e lo swapping.
Prossimità PCIe: NVMe e NIC nei nodi giusti
Se possibile, assegno le unità SSD NVMe e le NIC veloci al nodo su cui si trova l'applicazione. Carico di lavoro è in esecuzione. In questo modo si evita che le richieste di I/O attraversino l'interconnessione e aggiungano latenza. Lego le NIC multiqueue ai core set di un nodo con RSS/RPS in modo che gli IRQ rimangano locali. Per gli stack di archiviazione, vale la pena di dividere i pool di thread nodo per nodo. Se si presta attenzione a questo aspetto, si ridurranno sensibilmente le latenze di P99 e si creerà spazio per i picchi di carico.
Affinità IRQ e di coda in pratica
Per prima cosa verifico quale Nodo NUMA dispositivi e di assegnare gli IRQ e le code in modo appropriato. In questo modo viene mantenuta la localizzazione del percorso dei dati.
# Mappatura da dispositivo a nodo
cat /sys/class/net/eth0/device/numa_node
cat /sys/block/nvme0n1/dispositivo/numa_node
# Impostare l'affinità IRQ in modo specifico (esempio: core 0-7 di un nodo)
irq=
echo 0-7 > /proc/irq/$irq/smp_affinity_list
# Legare le code NIC ai core (RPS/RFS)
per q in /sys/class/net/eth0/queues/rx-*; fare echo 0-7 > "$q"/rps_cpus; fatto
sysctl -w net.core.rps_sock_flow_entries=32768
per q in /sys/class/net/eth0/queues/rx-*; fare echo 4096 > "$q"/rps_flow_cnt; fatto
# Migliorare l'affinità della coda NVMe
echo 2 > /sys/block/nvme0n1/queue/rq_affinity
cat /sys/block/nvme0n1/queue/scheduler # "none" preferito
„Eseguo “irqbalance" con la consapevolezza del nodo o lo imposto su Eccezioni per gli interrupt hot-path. Il risultato è una maggiore stabilità delle latenze, un minor numero di salti IRQ tra i nodi e un aumento misurabile degli hit I/O locali.
Legame statico vs. bilanciamento dinamico - la via di mezzo
Uso „taskset“ e cgroups per impostare regole rigide quando è deterministico Latenza conta. Lascio attivo il bilanciamento automatico NUMA quando il carico si sposta e ho bisogno di una vicinanza adattiva. Spesso funziona meglio un mix: pin rigidi per i percorsi caldi, confini più aperti per il lavoro ausiliario. Verifico regolarmente se le migrazioni aumentano in modo evidente, perché questo è un segnale di cattiva pianificazione. L'obiettivo rimane quello di scegliere le posizioni dei dati e dei thread in modo che le migrazioni siano rare ma possibili.
NUMA nei container e Kubernetes
Porto un contenitore cpuset e Pagine enormi in linea. Assegno pod/container a un nodo NUMA memorizzando quantità coerenti di CPU e memoria. Nelle orchestrazioni, imposto politiche che favoriscono l'assegnazione a un singolo nodo, rispettando così il first touch.
- Tempo di esecuzione del contenitore: „-cpuset-cpus“ e „-cpuset-mems“ tengono insieme task e memoria; assegnano pagine enormi come risorse.
- Gestore di topologia/CPULe assegnazioni rigorose o preferenziali garantiscono l'allocazione di core e aree di memoria correlate.
- QoS garantitaLe richieste/limiti fissi riducono al minimo la ridistribuzione da parte dello scheduler.
Ho deliberatamente suddiviso le sidecar e i processi ausiliari su altri core all'interno dello stesso nodo, in modo che il percorso caldo rimanga indisturbato ma non entri nella gara tra nodi.
Comprendere le topologie di CPU: CCD/CCX, SNC e Cluster-on-Die
Le attuali CPU server suddividono i socket in Sottodomini con le proprie cache e i propri percorsi. Ne tengo conto quando taglio i core/heap:
- AMD EPYCCCD/CCX e „NUMA per socket“ (NPS=1/2/4) influenzano la precisione con cui NUMA viene tagliato. Un numero maggiore di nodi (NPS=4) aumenta la localizzazione, ma richiede un pinning pulito.
- IntelSub-NUMA Clustering (SNC2/4) divide LLC in cluster. Ottimo per i carichi di memoria, a condizione che il sistema operativo e il carico di lavoro siano consapevoli dei nodi.
- Prossimità L3: lego i thread che usano gli stessi heap nello stesso cluster L3 per risparmiare il traffico di coerenza e i salti tra cluster.
Queste opzioni si comportano come un moltiplicatore: se utilizzate correttamente, aumentano Località Inoltre, se non configurati correttamente, aumentano la frammentazione e il traffico remoto.
Introduzione e piano di rollback passo dopo passo
Non ho mai introdotto il tuning NUMA „big bang“. Un resiliente Piano evita le sorprese:
- Linea di baseTopologia hardware, latenze P50/P95/P99, throughput, acquisizione della velocità numastatica.
- IpotesiFormulare un obiettivo specifico (ad esempio, accesso remoto -30%, P99 -20%).
- Un passoModificare solo una vite di regolazione (ad es. taglio VM, cpuset, politica THP, intervalli di scansione).
- CanarinoEseguire il test su 5-10% del parco macchine con carico reale, tenere pronto il rollback.
- ValutazioneConfrontare i valori misurati, definire le finestre di regressione, registrare gli effetti collaterali.
- LancioSrotolare albero per albero, misurando nuovamente dopo ogni albero.
- ManutenzioneRipetere la misurazione trimestralmente (gli aggiornamenti del kernel, del firmware e del carico di lavoro modificano l'optimum).
Ciò garantisce che i miglioramenti siano riproducibili e che possano essere annullati in pochi minuti in caso di errore.
Errori comuni e come evitarli
Un tipico passo falso è quello di attivare l'interleaving dei nodi nel BIOS, che nasconde la topologia NUMA e la Bilanciamento più difficile. Altrettanto sfavorevoli: le macchine virtuali con un numero di vCPU superiore a quello offerto da un nodo e le pagine enormi riservate in modo non pulito. Alcuni amministratori si affidano a tutto ciò che è rigido, perdendo così ogni flessibilità quando i carichi di lavoro cambiano. Altri si affidano completamente al kernel, anche se i punti caldi richiedono regole chiare. Io registro le serie di misurazioni, riconosco tempestivamente i valori anomali e regolo la configurazione e le politiche passo dopo passo.
- THP „sempre“ senza controllo: la compattazione non pianificata disturba la latenza. Preferisco usare „madvise“ e riservare in modo specifico le pagine più grandi.
- vm.zone_reclaim_mode troppo aggressivo: il recupero locale può fare più male che bene nel momento sbagliato. Prima misurare, poi affinare.
- irqbalance ciecoGli IRQ non critici si spostano tra i nodi. Ho impostato eccezioni o maschere fisse per gli hotpath.
- Miscela di interleave + hard pinningPolitiche contraddittorie creano un ping-pong. Sono favorevole a una linea chiara per ogni servizio.
- Cospetti non pulitiI contenitori vedono un nodo, ma mappano la memoria su altri nodi. Impostare sempre „cpuset.mems“ in modo coerente con la CPU impostata.
- Caratteristiche del Sub-NUMA attivati ma non utilizzati: Più nodi senza pianificazione aumentano la frammentazione. Attivare solo dopo i test.
Riassumendo brevemente
NUMA Balancing Server riunisce processi e dati in modo mirato, rendendo gli accessi locali più frequenti e più efficienti. Latenze diventano più brevi. Con una dimensione adeguata della macchina virtuale, una configurazione pulita del BIOS e strumenti come numactl, viene creata una topologia chiara che il kernel utilizza. NUMA virtuale, pagine enormi e affinità integrano il bilanciamento automatico invece di sostituirlo. Il collegamento dei dispositivi di I/O in prossimità dei nodi e l'uso di hotpath eliminano il costoso accesso remoto. In questo modo, l'hardware dell'hosting scala in modo affidabile e ogni secondo di CPU fornisce più carico utile.


