Il bilanciamento NUMA in Linux determina se il Kernel Se gli accessi alla memoria vengono localizzati automaticamente o se sono io a controllarne il posizionamento in modo mirato. In questa guida vi mostrerò quando lasciare attivo il "numa balancing" e quando disattivarlo per Latenza-Disattiva la sicurezza.
Punti centrali
- Automatico È utile in presenza di carichi di lavoro misti senza ottimizzazione NUMA.
- Disattivare in caso di pinning, policy statiche o latenza elevata.
- Spese generali è il risultato di scansioni, errori e migrazioni.
- Configurazione controllare tramite sysctl o parametri di avvio.
- Test e misurare invece di tirare a indovinare, poi decidere.
NUMA in breve: latenze e località
Nei sistemi NUMA, l'hardware organizza la memoria in diversi nodi, i singoli CPU si trovano geograficamente vicini. Gli accessi locali richiedono meno tempo rispetto a quelli a distanza, cosa che ho notato immediatamente Latenza e la larghezza di banda. Se un processo è in esecuzione su un nodo, ma i dati si trovano su un altro, perdo preziosi microsecondi per ogni accesso. È proprio in questo punto che interviene il kernel per ottimizzare la Località in termini di pagine. Chi comprende l’idea di base se ne rende subito conto: la vicinanza tra i nuclei di calcolo e i dati è la via diretta per ottenere una Prestazioni.
Come funziona il bilanciamento automatico NUMA
Il kernel monitora da quali nuclei un processo accede alle pagine e interviene in modo mirato Suggerimento-Faults. In questo modo, il sistema individua quale nodo registra un numero maggiore di accessi e trasferisce quindi le pagine corrispondenti su quel nodo. Queste migrazioni riducono gli accessi da remoto e aumentano la velocità locale Tasso di successo. Ne noto l'effetto soprattutto nei carichi di lavoro dinamici, in cui i thread si spostano e la memoria cambia posizione. Chi desidera approfondire l'argomento può esaminare le relazioni tra la vicinanza della CPU e della memoria tramite Affinità CPU/memoria comprendere in modo pratico.
Quando lasciarlo attivo: carichi di lavoro tipici
Lascio la funzione attiva quando le applicazioni non dispongono di una propria logica NUMA e i processi spesso cambiamento. Tra i candidati più comuni figurano i server applicativi, i database con carico variabile e gli host con molti contenitori. In configurazioni di questo tipo, il sistema automatico avvicina le pagine e i thread senza che io debba fissarli manualmente. Soprattutto sugli host multi-socket, la percentuale di accessi locali aumenta in modo tangibile. Per gli amministratori con servizi eterogenei, ciò rappresenta un buon Compromesso in termini di tempo e impegno.
Quando disattivare: criteri chiari
Disattivo il pilota automatico non appena mi accorgo di aver perso il controllo o di essere in difficoltà Politiche impostare. Se utilizzo numactl, cgroups o MPOL_BIND/MPOL_PREFERRED, esiste già una scelta definitiva riguardo ai percorsi di memoria. In tal caso, gli hint fault e le migrazioni generano un inutile Spese generali. Lo stesso vale per gli scenari in tempo reale o di HFT, in cui ogni microsecondo conta e la prevedibilità è una priorità. Chi approfondisce la scelta delle regole di collocamento trarrà vantaggio da un’analisi delle opzioni più adatte Politiche di memoria.
Comprendere e misurare l'overhead
Il bilanciamento automatico comporta del lavoro: scansioni, Errori e le migrazioni tra pagine richiedono tempo di CPU. Ciò passa quasi inosservato quando gli accessi remoti diminuiscono drasticamente, ma non vale quasi la pena se il layout è già locale. Verifico quindi sempre l’effetto effettivo con numastat, perf e metriche significative Parametri di riferimento. Ciò che interessa è l'andamento nel corso dei minuti, non solo un breve picco. Solo quando i valori misurati indicano in modo costante che gli accessi locali aumentano e le latenze diminuiscono, mantengo quella modalità.
Configurazione: Sysctl e parametri di avvio
Controllo lo stato tramite /proc o Sysctl e, se necessario, lo modifico immediatamente, senza un Riavvio. Per i test bastano semplici comandi come quelli riportati di seguito, che eseguo nella console. In modo permanente, imposto il valore in un file sysctl, in modo che rimanga invariato dopo un riavvio. Chi preferisce impostarlo già all’avvio, utilizza il parametro del kernel numa_balancing=enable oppure disabilita. Documento ogni modifica e annoto in quale fase del carico di lavoro l'ho effettuata.
cat /proc/sys/kernel/numa_balancing
echo 0 > /proc/sys/kernel/numa_balancing
sysctl -w kernel.numa_balancing=1
# /etc/sysctl.d/90-numa.conf
# kernel.numa_balancing = 0
Scenari relativi ai container e alla virtualizzazione
Sugli host con molte macchine virtuali e container, l'automatizzazione Localizzazione spesso mettono in evidenza i loro punti di forza. I processi si avviano e terminano, i Cgroups ridistribuiscono il carico e il kernel mantiene la memoria più vicina ai nuclei attivi. Lo noto soprattutto su grandi server multi-socket con diversi Nodi. Distinguo chiaramente i casi particolari in cui è richiesto un pinning rigido di singole istanze e in tali casi disattivo in modo mirato la funzione automatica. Per una classificazione più approfondita, è utile dare un’occhiata agli esempi pratici Ottimizzazione NUMA in modalità host.
Tabella decisionale per la pratica
La seguente panoramica riassume gli scenari tipici, l'effetto atteso e la mia chiara Raccomandazione. Li uso come punto di partenza, ma non li sostituisco mai con i valori misurati sul sistema reale. Ogni ambiente presenta delle peculiarità, e prendo decisioni solo dopo aver ottenuto risultati riproducibili Risultati sicuro. Chi procede in modo sistematico risparmia tempo in seguito nella ricerca degli errori e nella messa a punto. Effettuare piccoli test prima di un lancio si rivela quasi sempre utile in Costanza e la prevedibilità.
| Scenario | Effetto tipico | Il mio consiglio |
|---|---|---|
| Carichi di lavoro standard senza ottimizzazione NUMA | Più accessi locali, meno accessi da lontano Letture | Lasciare attivo |
| Banche dati con carico variabile | Localizzazione dinamica delle pagine, moderata Scansioni | Lasciare attivo, testare |
| Trading in tempo reale o HFT | La latenza Hint-Fault è un problema Jitter-Obiettivi | Disattiva, fissa manualmente |
| Fissaggio manuale tramite numactl/cgroups | Il sistema automatico entra in collisione con gli elementi fissi Politiche | Disattivare |
| Politiche di memoria statiche (MPOL_BIND, ecc.) | Le migrazioni non apportano alcun reale Vantaggio | Disattivare |
| Ambiente di test/analisi | Buona visibilità sulla località e Effetti | Lasciare attivo, verificare le varianti |
Linee guida per i test e la convalida
Inizio con il Balancer attivato e registro i dati locali rispetto a quelli remoti Accessi tramite Numastat. Successivamente disattivo la funzione e ripeto le misurazioni in modo identico. Valuto le differenze non solo in termini di valori medi, ma anche in Percentili. I test di regressione con profili di carico provenienti dalla produzione forniscono i risultati più affidabili. Solo allora prendo la decisione definitiva in merito a host, VM o un determinato Servizio.
Ostacoli comuni e miti
Un errore comune è quello di ritenere che il sistema automatico sostituisca ogni Appuntatura. Non è vero, perché i budget di latenza rigidi non tollerano quasi nessun errore aggiuntivo. Altrettanto errata è l’ipotesi secondo cui le migrazioni siano sempre gratuito accadere. Soprattutto nel caso di layout già di per sé locali, il sovraccarico ha più spesso un effetto negativo che positivo. Chi evita i miti e effettua misurazioni accurate, prende decisioni con un livello di Precisione.
Limiti dell'automatismo e interazioni
AutoNUMA ha un forte impatto sulle pagine anonime allocate autonomamente da un processo. Tuttavia, non tutto può essere migrato in modo sensato. Le pagine fissate (mlock), la memoria DMA/dispositivo, le aree registrate DAX o RDMA rimangono dove sono. Anche le pagine condivise (ad es. librerie altamente condivise o la cache di pagina) offrono solo benefici limitati dalla migrazione, poiché più processi competono per l’accesso Modello di accesso produrre. Inoltre, tengo conto dei costi di Pagine trasparenti di grandi dimensioni (THP): la loro migrazione è più costosa rispetto alle pagine da 4 KiB e può causare picchi di carico. Chi persegue obiettivi di latenza rigorosi spesso combina THP=never o madvise con il bilanciamento disattivato e il pinning pulito, per evitare sorprese.
Un altro aspetto è l’interazione con lo scheduler della CPU. Lo scheduler cerca di collocare i thread dove si trovano i loro dati, mentre il bilanciatore sposta i dati dove sono in esecuzione i thread. I due meccanismi si completano a vicenda, ma in caso di carico instabile possono causare temporaneamente Oscillazioni portare. In pratica, gli intervalli di scansione attenuano questi effetti; chi riscontra profili di carico estremamente instabili può stabilizzare la situazione utilizzando periodi di scansione più lunghi o un thread pinning più stabile.
Messa a punto dei parametri di scansione
Oltre all'opzione globale, esistono dei parametri del kernel che mi consentono di regolare con precisione l'aggressività del sistema automatico. I nomi esatti possono variare leggermente a seconda della versione del kernel, ma lo scopo rimane lo stesso:
- kernel.numa_balancing_scan_delay_ms: tempo di attesa dopo l'avvio, un 'fork' o un 'exec' prima che inizi la prima scansione.
- kernel.numa_balancing_scan_period_min_ms / _max_ms: limite minimo e massimo della frequenza di scansione per ogni intervallo di indirizzi di processo.
- kernel.numa_balancing_rate_limit_mb: limite massimo per intervallo di tempo per le migrazioni di pagine, al fine di preservare la larghezza di banda della memoria.
- kernel.numa_balancing_scan_size_mb: quantità di memoria contrassegnata per ogni ciclo di scansione (se disponibile).
In configurazioni in cui la latenza è fondamentale, per prudenza aumento i periodi minimi e massimi e riduco i limiti di frequenza, invece di disattivare immediatamente la funzione automatica. Questo spesso offre un buon compromesso: meno errori di hint, meno migrazioni, ma una reazione comunque sufficiente in caso di posizionamenti errati effettivi.
Esempi # (temporanei, fino al riavvio)
sysctl -w kernel.numa_balancing_scan_period_min_ms=60000
sysctl -w kernel.numa_balancing_scan_period_max_ms=240000
sysctl -w kernel.numa_balancing_rate_limit_mb=64
Metriche e analisi diagnostica approfondita
Per prendere decisioni fondate, analizzo gli indicatori che mettono direttamente in luce il meccanismo. Utilizzo regolarmente tre fonti:
- numastat: rapporto tra accessi locali e remoti a livello di sistema e per processo.
- /proc//numa_maps: distribuzione delle pagine di memoria di un processo tra i nodi, inclusi flag quali active, file, anon.
- /proc/vmstat: contatori come numa_hint_faults, numa_hint_faults_local e numa_pages_migrated indicano se il bilanciatore è attivo e se Il successo ha.
Panoramica # per processo
numastat -p
Vista dettagliata #: dove si trovano le aree?
grep -E 'anon|file' /proc//numa_maps | head
#: panoramica a livello di kernel sull'attività AutoNUMA
grep -E 'numa_(hint_faults|pages_migrated)' /proc/vmstat
Nei risultati cerco delle tendenze: la percentuale di accessi locali sta aumentando in modo costante? Allo stesso tempo, gli “hint fault” stanno diminuendo? In tal caso, significa che il layout è efficace. Se la percentuale locale rimane stabile nonostante le numerose migrazioni, tendo a sprecare cicli. Per gli obiettivi di latenza, verifico inoltre il 95° e il 99° percentile dei tempi di risposta; piccoli miglioramenti nella media possono essere compensati da Jitter essere coperti.
Profili di carico di lavoro: cosa funziona in genere
Dall'esperienza pratica sono emersi alcuni modelli che indicano quando AutoNUMA è solitamente utile e quando invece non lo è:
- Servizi JVM e server applicativi: spesso ne traggono vantaggio, purché non sia attiva una strategia rigida di thread pinning né una logica NUMA propria troppo aggressiva. Alcuni runtime offrono opzioni NUMA; se le utilizzo in modo rigoroso, riduco l'automaticità o la disattivo.
- Banche dati relazionali: in caso di carico variabile con cache miste, il sistema automatico spesso funziona bene. Tuttavia, se impiego il pinning dedicato (da worker a nodo, buffer condivisi distribuiti in modo rigoroso), disattivo il bilanciamento per garantire una riproducibilità accurata.
- Memorie in-memory e cache: un set di dati di lavoro di grandi dimensioni e ad alta attività trae vantaggio dal posizionamento locale. Se l'istanza opera in modalità single-threaded o è rigorosamente fissata, evito migrazioni inutili disattivando la funzione.
- HPC/MPI e codici scientifici: nella maggior parte dei casi esistono regole chiare di posizionamento e di binding (OpenMP/numactl). In questo caso la prevedibilità è più importante dell’automatismo: tralascio il bilanciamento NUMA.
Virtualizzazione: vNUMA, pinning e migrazione live
Nell’interazione tra ospite e ospitante, prendo in considerazione entrambi i livelli:
- Se la topologia vNUMA dell'ospite corrisponde alla topologia NUMA fisica dell'host, il bilanciatore dell'ospite è in grado di prendere decisioni sensate. Se vi si discosta, si creano „vicindanze errate“ che AutoNUMA compensa solo in misura limitata.
- Se assegno in modo fisso le vCPU alle CPU dell'host e associo la memoria dell'ospite a nodi specifici, si tratta di una politica esplicita: a questo livello della macchina virtuale riduco o disattivo AutoNUMA per evitare migrazioni doppie.
- Dopo le migrazioni live, osservo una fase di assestamento: gli Hint-Fault aumentano fino a quando non si raggiunge un nuovo equilibrio. In questo periodo prevedo dei margini per Latenza-punte.
Su host di virtualizzazione ad alta densità, dove le istanze vengono avviate/arrestate e i Cgroup ridistribuiscono il carico, la gestione automatica a livello di host rappresenta spesso un vantaggio netto. Per le VM dedicate sensibili al fenomeno del „Noisy Neighbor“, isolo accuratamente le risorse e imposto le regole in modo statico.
Valori target pragmatici e criteri di accettabilità
Definisco in anticipo cosa significa „buono“, in modo da non dover continuare all’infinito a perfezionarlo:
- Servizi generali: 70–85% accessi locali sono spesso sufficienti, purché la varianza rimanga bassa.
- SLA sulla latenza: obiettivo >90% a livello locale, limiti massimi ben definiti per l'Hint-Fault-Rate e percentili al 99° stabili.
- Con carico sulla larghezza di banda: le migrazioni non devono saturare i canali di memoria – adeguare di conseguenza i limiti di velocità e i periodi.
Documento queste soglie e valuto i test A/B su diverse fasi di carico. Prendo una decisione solo quando i risultati sono ripetibili.
Lista di controllo per la risoluzione dei problemi
- Picchi improvvisi di latenza: verificare se vi sia una correlazione tra le migrazioni THP e i picchi in `numa_hint_faults`. Contromisura: aumentare i periodi di scansione, impostare THP su `madvise/never`, disattivare `Balance` se necessario.
- Effetto quasi nullo nonostante l'attivazione: i thread sono fortemente bloccati o esistono politiche di memoria fisse? In tal caso, il sistema automatico entra in conflitto con le impostazioni predefinite.
- Elevato ritmo di migrazione, ma comunque molti accessi da remoto: verificare e aumentare il limite di velocità; in alternativa, stabilizzare il carico di lavoro (thread pinning, mantenere le cache stabili dal punto di vista termico).
- Valori di misurazione poco chiari: utilizzare la vista per processo con numastat -p e /proc//numa_maps, non solo i valori complessivi del sistema.
Dettagli spesso trascurati
- Carichi di lavoro che fanno ampio ricorso alla cache delle pagine: AutoNUMA è particolarmente efficace con le pagine anonime. Chi opera principalmente in contesti vincolati dall'I/O non dovrebbe aspettarsi miracoli dal bilanciamento.
- Cgroups e cpusets: il file cpuset.mems limita i nodi a cui un gruppo può accedere. Si tratta di un quadro rigido entro il quale opera il sistema automatico.
- Hot-plug della memoria/disattivazione dei nodi: le topologie dinamiche modificano le distanze; dopo le modifiche è consigliabile eseguire un nuovo test e, se necessario, adeguare i parametri di scansione.
Riassumendo brevemente
Per i carichi di lavoro generici del server, lascio attiva la modalità automatica, perché senza intervento manuale si avvicina Dati che porta a core attivi. In caso di elaborazione in tempo reale, HFT, pinning manuale o policy fisse, li disattivo per evitare overhead e jitter. Nelle fasi di test lavoro in modo iterativo: misuro, decido, ripeto convalidare. Mantengo la configurazione semplice, documento ogni modifica e ne verifico l'efficacia tramite indicatori affidabili. In questo modo sfrutto i punti di forza dell'hardware NUMA senza inutili I rischi affrontare.


