La frammentazione della memoria nel funzionamento dei server significa che blocchi grandi e contigui non sono più disponibili nonostante la RAM libera e le allocazioni critiche falliscono. Mostro le cause, i sintomi tipici e le contromisure mirate in modo che Server reagire in modo calcolabile e le assegnazioni possono essere affidabili. funzione.
Punti centrali
- Interno e esterno Differenziare e affrontare in modo specifico la frammentazione.
- Buddy-Allocator capire: Ordini, suddivisioni, fusioni mancanti.
- Sciatore di fondo-Impostare correttamente i carichi di lavoro, l'overhead dell'hypervisor e il THP.
- Diagnosi con buddyinfo, vmstat e metriche di compattazione.
- Schema di allocazione migliorare: Pool, preassegnazione, durata di vita separata.
Cosa significa frammentazione della memoria nell'uso quotidiano dei server?
Mi riferisco a Memoria La frammentazione è lo stato in cui la memoria di lavoro libera si frammenta in tanti piccoli spazi e le richieste di grandi dimensioni non ricevono più un'area contigua. La frammentazione interna si verifica quando un blocco allocato è più grande del fabbisogno effettivo e vengono lasciati dei byte inutilizzati nel blocco, il che può portare alla Efficienza si riduce. La frammentazione esterna si verifica quando le sezioni libere sono distribuite e non si uniscono più per formare un'area grande, anche se la RAM libera è sufficiente. È proprio in questo caso che i buffer di grandi dimensioni, le prenotazioni JIT o i driver che privilegiano la memoria contigua falliscono a causa della scarsità apparentemente paradossale di blocchi di grandi dimensioni. Negli ambienti di hosting, i carichi paralleli elevati, i lunghi tempi di attività e gli stack software eterogenei aggravano questo problema. Dinamica percepibile.
Come il Linux-Buddy-Allocator crea la frammentazione
Il kernel di Linux gestisce la memoria fisica attraverso un sistema di Amico-che organizza le pagine in classi di dimensioni (ordini), a partire da 4 KB. Se i processi richiedono aree più grandi, il kernel divide i blocchi di grandi dimensioni in compagni fino a quando non è disponibile una dimensione adeguata; quando si rilascia, tenta di riunire i compagni. Tuttavia, le diverse lunghezze delle richieste, i tempi di vita variabili e il rilascio disomogeneo impediscono il riassemblaggio e incoraggiano l'uso di risorse esterne. Frammentazione. Nel corso del tempo, lo stock di ordini di grandi dimensioni si svuota, mentre gli ordini piccoli si ingrossano: /proc/buddyinfo mostra quindi numeri alti negli ordini bassi e zeri negli ordini alti. Da questo momento in poi, la compattazione ed eventualmente il comportamento OOM intervengono più frequentemente, creando latenze e aumentando le interruzioni.
Cause in ambienti di hosting e virtualizzazione
I carichi di lavoro web e di database di lunga durata creano un modello variabile di allocazioni che spezza i blocchi di grandi dimensioni e permette di Unire impedito. I framework e le librerie che rilasciano la memoria in ritardo o in modo non coordinato lasciano spazi vuoti in cui possono essere accolte solo piccole richieste. La virtualizzazione aggiunge il proprio overhead e sposta le allocazioni al guest e all'ipervisore, il che significa che le richieste esterne Frammentazione viene creato più rapidamente. I valori vm.min_free_kbytes impostati in modo errato aumentano la pressione perché il kernel ha troppo pochi buffer per le allocazioni atomiche o li conserva in eccesso. Maggiore trasparenza su Memoria virtuale mi aiuta a organizzare in modo ordinato l'interazione tra allocatore di guest, THP, Huge Pages e hypervisor.
Effetti sulle prestazioni e sull'esperienza dell'utente
Se il serbatoio di accumulo è suddiviso in tante piccole isole, la Latenze, perché il kernel si comprime e si sposta più frequentemente prima di poter gestire richieste di grandi dimensioni. Le applicazioni che richiedono aree continue, come database, cache o pipeline multimediali, vacillano più rapidamente. Nonostante la RAM „libera“, le allocazioni di grandi dimensioni falliscono e generano messaggi di errore, riavvii o cancellazioni difficili, il che può causare sessioni e Transazioni compromesso. Le attività in background, come la compattazione, aumentano il carico della CPU e la pressione dell'I/O, facendo apparire più lenti anche i carichi di lavoro altrimenti leggeri. Negli scenari di hosting, ciò si manifesta con tempi di risposta lunghi, timeout sporadici e una minore scalabilità durante i picchi di carico.
Diagnostica: da buddyinfo alle metriche di compattazione
Per prima cosa controllo /proc/buddyinfo per vedere quale Ordini vmstat e sar mostrano la frequenza con cui il kernel compatta o se il percorso OOM è diventato attivo, il che indica la pressione esercitata da allocazioni di grandi dimensioni. Uso perf e strace per riconoscere se i thread sono in attesa di compattazione diretta e quindi i tempi di risposta fluttuano, il che si nota nei log e nelle metriche. Negli ambienti con server Windows, visualizzo gli heap frammentati con strumenti di debug per verificare la presenza di ampi spazi vuoti e mettere a punto i parametri dell'heap. regolare. Misuro anche il blocco libero più grande, perché la somma della RAM libera non è sufficiente come diagnosi.
Messa a punto del kernel e della macchina virtuale in pratica
Ho impostato vm.min_free_kbytes moderatamente più alto, spesso nell'ordine di 5-10 % di RAM, in modo che il kernel disponga di grandi quantità di RAM atomica. Richieste di informazioni può essere utilizzato in modo affidabile. Attivo con cautela le pagine enormi trasparenti: su richiesta o tramite madvise, a seconda del profilo di carico e del rischio di frammentazione. Le pagine enormi statiche offrono una certa prevedibilità, ma richiedono una pianificazione adeguata per non causare problemi altrove. Colli di bottiglia per creare ordine. La compattazione crea ordine nel breve termine, ma non sostituisce una soluzione strutturale per i modelli permanenti e instabili. Includo le topologie NUMA nella messa a punto, in modo che le allocazioni di grandi dimensioni rimangano locali e non si disperdano tra i nodi.
| Impostazione | Obiettivo | Benefici | Suggerimento |
|---|---|---|---|
| vm.min_free_kbytes | Riserva per grandi assegnazioni | Meno picchi di OOM/compattazione | Aumentare gradualmente e misurare il valore |
| THP (su/consiglia) | Privilegiare le pagine più grandi | Meno frammentazione, migliore tasso di TLB | Attenzione alle latenze del carico di lavoro |
| Pagine enormi (statico) | Riserva di aree continue | Blocchi di grandi dimensioni prevedibili | Pianificare la capacità in anticipo |
| Compattazione | Riunire le aree libere | Blocchi temporaneamente più grandi | Aumenta la CPU/I&O nel breve termine |
| NUMA-Politica | Assegnazione locale sicura | Latenza più bassa, meno traffico incrociato | Configurare il bilanciamento |
Zone di archiviazione, tipi di migrazione e perché „unmovable“ blocca tutto
L'allocatore di pagine non funziona solo con gli ordini, ma anche con zone (DMA, DMA32, normale, mobile) e Migrare i tipi (MOBILI, INAMOVIBILI, RECUPERABILI). I granuli per questo sono i „pageblock“. Non appena le pagine non spostabili (ad esempio le strutture del kernel, le pagine appuntate dai driver) entrano in un pageblock, il kernel contrassegna questo blocco come difficile da spostare. Sono proprio questi blocchi „contaminati“ che impediscono alla compattazione di combinare le aree libere in grandi aree contigue. Aree moduli. Pertanto, pianifico consapevolmente la capacità in ZONE_MOVABLE (ove possibile) e mi assicuro che i dati delle applicazioni siano prevalentemente allocati come MOVABLE. In questo modo è più probabile che rimangano disponibili riserve ampie e contigue. Per i carichi di lavoro con elevati requisiti DMA, utilizzo riserve mirate in modo che le pagine UNMOVABLE non distruggano l'ampia zona normale.
Design pulito del modello di allocazione
Raggruppo i requisiti di stoccaggio in base a Vita utileGli oggetti a breve vita in pool, quelli a lunga vita in regioni separate, in modo che i rilasci non distruggano tutto. Raggruppo le dimensioni frequenti in pool fissi per ridurre la fluttuazione degli ordini e alleggerire il buddy allocator. Pre-pianifico i buffer di grandi dimensioni all'inizio, invece di richiederli nel bel mezzo del traffico, per evitare picchi di carico durante l'assemblaggio. Adeguo le richieste di allineamento alle esigenze reali, perché gli allineamenti eccessivi sprecano spazio e incoraggiano l'uso interno di Frammentazione. Nelle pipeline di creazione e distribuzione, verifico i percorsi di archiviazione con scenari di carico prima che il traffico arrivi in diretta.
Selezione dell'allocatore nello spazio utente: glibc, jemalloc, tcmalloc
Non tutte le frammentazioni sono un problema del kernel. Il Spazio utente-Glibc malloc utilizza arene per thread; su molti core questo può portare a un'elevata frammentazione interna. Io limito il numero di arene e ritaglio in modo più aggressivo, in modo che le aree inutilizzate tornino al sistema operativo più rapidamente. Alternative come jemalloc o tcmalloc offrono classi di dimensioni più fini e modelli di condivisione più coerenti, che possono ridurre sensibilmente la frammentazione esterna. Il fattore decisivo è: Misuro sotto carico di produzione, perché ogni allocatore ha diversi compromessi in termini di latenza, throughput e ingombro di memoria. Per i servizi con throughput elevato e dimensioni uniformi degli oggetti, le arene dedicate o i pool di tipo slab offrono spesso le prestazioni più stabili. Latenze.
Misure dal lato dell'applicazione: Java, PHP, cache e database
In Java uso Arene o un allocatore di regioni e scegliere profili GC che favoriscano prenotazioni grandi e contigue, invece di rompere costantemente l'heap in pezzi sottili. Bilancio Xms/Xmx in modo che l'heap non cresca e si restringa continuamente, perché questo pompaggio favorisce i buchi. Per gli stack PHP e MySQL, utilizzo pool di memoria fissi, limito gli oggetti sovradimensionati e ottimizzo le dimensioni dei buffer con l'obiettivo di ottenere modelli di allocazione coerenti; una conoscenza pratica più approfondita è contenuta nella pagina su Ottimizzazione PHP/MySQL. Organizzo i sistemi di caching (ad esempio, cache di oggetti o pagine) per avere dimensioni omogenee, in modo che i rilasci non lascino sempre grandi spazi vuoti. Se non altro, pianifico riavvii controllati nelle finestre di manutenzione, invece di rischiare eventi OOM non pianificati che possono distruggere l'intero sistema. Servizi per annullare.
Pratica di container e Kubernetes
I contenitori non modificano la funzionalità del Amico-Gli allocatori segmentano solo le viste e i limiti. La frammentazione rimane quindi un problema dell'host, ma si manifesta nei pod attraverso sfratti, latenze fluttuanti o costi di suddivisione THP. Raggiungo la stabilità con:
- Impostare le classi QoS (Guaranteed/Burstable) in modo che i pod critici ricevano riserve fisse e non crescano e si riducano allo stesso tempo.
- in modo realistico, in modo che il trimming e il reclaim non violino in modo permanente i limiti di memoria. Confini si scontrano.
- THP/Hugepages sono coerenti a livello di host e forniscono ai pod che necessitano di pagine di grandi dimensioni pool riservati staticamente.
- Utilizzare strategie di riscaldamento (pre-faulting, pre-allocazione) in modo che i blocchi di grandi dimensioni vengano occupati presto e non vengano richiesti successivamente sotto carico.
Monitoro i nodi containerizzati come se fossero bare metal: buddyinfo, eventi di compattazione, uccisioni OOM - solo che li metto in relazione con i riavvii e gli sfratti dei pod per separare le cause in modo pulito.
Virtualizzazione, NUMA e influenze hardware
Tra gli hypervisor, verifico come interagiscono l'allocatore del guest, il ballooning e il THP dell'host perché la stratificazione può aumentare la frammentazione e creare grandi Blocchi la rende scarsa. Osservo costantemente le topologie NUMA: l'allocazione locale riduce la latenza e impedisce che le richieste di grandi dimensioni vengano distribuite tra i nodi e quindi ridotte. Laddove ha senso, applico i carichi di lavoro ai nodi NUMA e osservo l'effetto sui page fault e sugli accessi al TLB. Per un controllo più accurato, stabilisco delle linee guida per i nodi di archiviazione e tiro fuori i carichi di lavoro. Bilanciamento NUMA in modo mirato. Includo anche gli aggiornamenti del firmware e del microcodice, in modo da poter escludere effetti collaterali imprevisti e garantire la prevedibilità con i grandi sistemi. Requisiti ricevere.
Driver di dispositivo, DMA e CMA
I conducenti che sono fisicamente coerente (ad esempio, alcuni motori DMA, multimedia, schede di acquisizione) esacerbano la frammentazione esterna. In questo caso intendo utilizzare l'allocatore di memoria contigua (CMA) o riservare blocchi di grandi dimensioni all'inizio del processo di avvio. In questo modo si evita che molte piccole allocazioni „rosicchino“ lo spazio degli indirizzi prima che il driver ottenga i suoi buffer. Allo stesso tempo, isolo le pagine appuntate (ad esempio usando RDMA/DPDK) dalla memoria generale dell'applicazione, in modo che il loro carattere UNMOVABLE non renda inutilizzabili interi blocchi di pagine. Dovrei anche verificare se le configurazioni IOMMU virtualizzano sufficientemente le aree più grandi e non contigue, altrimenti ho bisogno di riserve specifiche e di limiti di tempo chiari. Finestre per queste assegnazioni.
Routine operativa: utilizzare in modo intelligente le finestre di monitoraggio e manutenzione
Ho incorporato gli snapshot di buddyinfo, i contatori di compattazione e gli eventi OOM nel mio Monitoraggio, per vedere le tendenze invece dei singoli eventi. Riduco le distribuzioni rolling in modo che le fluttuazioni della memoria si concentrino in finestre temporali e il resto della settimana scorra più agevolmente. Durante le finestre di manutenzione, attivo manualmente la compattazione se necessario, pulisco le cache e riavvio i servizi prima che la frammentazione causi problemi produttivi. Metto in relazione i log e le metriche con i picchi di traffico per riconoscere gli schemi ricorrenti e regolare i buffer di conseguenza. Per le modifiche più importanti, eseguo prima un test in staging per evitare di scoprire cambiamenti sorprendenti. Effetti collaterali in funzione dal vivo.
Runbook: Quando le grandi allocazioni falliscono oggi
Se ci sono messaggi di errore acuti del tipo „l'assegnazione dell'ordine X non è riuscita“, lavoro per passi chiari:
- Quadro della situazione: Salvare buddyinfo, controllare vmstat (allocstall/compact), cercare in dmesg le voci Compaction/OOM. Stimare il blocco libero più grande (ordine più alto con >0).
- Sollievo a breve termine: Sospendere i servizi non critici, limitare il carico, cancellare le cache in modo mirato. Attivare manualmente la compattazione e disattivare temporaneamente THP Defrag se sta causando danni.
- Liquidazione mirata: Ricostruzione di buffer grandi e contigui in servizi definiti (riavvio controllato) prima che si verifichi il picco successivo.
- Aumento della riserva: vm.min_free_kbytes e watermark con attenzione per garantire le allocazioni atomiche per le prossime ore; gli effetti sono stretti monitor.
- Rimedio permanente: Correggere i modelli di allocazione, introdurre i pool, spostare la preallocazione all'inizio, controllare la localizzazione NUMA e regolare correttamente THP/Huge Pages.
Variabili misurate, SLO e allarmi
Non mi limito a misurare i totali della RAM, ma definisco anche SLO per l'allocabilità: „ordine più alto con disponibilità“, „tempo fino al successo dell'allocazione di grandi dimensioni“, „percentuale di stallo della compattazione“. Da ciò derivano allarmi che colpiscono precocemente, prima che gli utenti vedano i timeout. I dati chiave utili sono
- Numero di blocchi liberi in ordini elevati (ad esempio ≥ Ordine 9) al minuto.
- Frequenza e durata dei tempi di attesa per la compattazione diretta o la bonifica.
- Percentuale di pagine appuntate/non appuntate rispetto alla memoria totale.
- Tasso di successo delle allocazioni di grandi dimensioni nei test di carico e dopo le implementazioni.
Collego queste metriche ai tempi di rilascio, ai picchi di traffico e alle modifiche di configurazione. In questo modo, riconosco gli schemi in base ai quali posso agire in modo proattivo. scala o riprogrammare la finestra di assegnazione.
Pianificazione della capacità e consapevolezza dei costi
Calcolo i margini di stoccaggio in modo tale che sia Funzionamento normale e le fasi di manutenzione con l'aumento delle allocazioni sono adeguatamente coperte. Invece di effettuare l'upgrade su tutta la linea, controllo prima le correzioni dei modelli, perché una buona messa a punto spesso porta più di una RAM aggiuntiva. Quando espando la capacità, prevedo delle riserve per THP/pagine enormi, in modo che le pagine di grandi dimensioni non si scontrino con i picchi delle applicazioni. Il consolidamento su un numero minore di host, ma più potenti, può ridurre la frammentazione, a patto di impostare in modo appropriato i profili NUMA e di allocazione. In definitiva, quando riduco la frammentazione risparmio sui costi in euro, perché riduco i picchi di CPU e la congestione dell'I/O e utilizzo le licenze in modo più efficiente. utilizzo.
Riassumendo brevemente
La frammentazione della memoria si verifica quando molte allocazioni di lunghezza e dimensioni diverse sono collegate tra loro. Aree e grandi richieste di informazioni che poi non portano a nulla. Risolvo il problema su tre fronti: Messa a punto del Kernel/VM (vm.min_free_kbytes, THP/Huge Pages), migliori modelli di allocazione (pool, preallocazione, tempi di vita separati) e gestione pulita delle operazioni (monitoraggio, potatura programmata, disciplina NUMA). Per la diagnostica mi affido a /proc/buddyinfo, ai contatori di compattazione e alla misurazione del blocco libero più grande, perché i totali della RAM sono ingannevoli. Presto esplicita attenzione alla virtualizzazione e agli hypervisor, in modo che il guest e l'host non lavorino l'uno contro l'altro e che i grandi blocchi di RAM non siano in grado di gestire il traffico. Blocchi riservato in una fase iniziale. La combinazione di questi elementi costruttivi aumenta la prevedibilità, previene i guasti dovuti all'OOM e fornisce risposte più rapide, soprattutto quando il traffico e i dati sono in crescita.


