La “memory pressure” nel kernel di Linux ha un impatto diretto sui sistemi di hosting: se la pressione aumenta, il tempo di CPU e l’I/O si spostano verso operazioni più onerose Reclaim, i tempi di risposta aumentano e i rischi di OOM crescono. Spiego chiaramente come individuare, misurare e mitigare la pressione sulla memoria, in modo che Ospitare-Rispondere in modo costante ai carichi di lavoro.
Punti centrali
Mi concentro sui fattori chiave che, negli ambienti di hosting, determinano le prestazioni e i guasti. I punti seguenti costituiscono il filo conduttore su cui baso la diagnosi e l’ottimizzazione. Grazie a questa panoramica, evito interpretazioni errate del messaggio „RAM piena“ e individuo i veri Pressione per tempo.
- Metriche PSI Mostrano i tempi di attesa anziché la semplice occupazione e individuano tempestivamente eventuali ritardi.
- Carico di swap segnala problemi di reclaim che aggravano gli I/O e le latenze.
- Limiti dei cgroup Gestire la limitazione, la protezione e il comportamento in caso di OOM per ogni servizio.
- Sostituzione della cache influisce direttamente sulle prestazioni del sito web e del database.
- Pianificazione della capacità e il tuning mantengono l'headroom ed evitano il thrashing.
In questo modo strutturo le mie analisi, dal kernel all’applicazione, e attuo le misure adeguate secondo un ordine di priorità. L’attenzione rimane concentrata su aspetti misurabili Effetti, non al lavoro a cottimo.
Cosa significa "memory pressure" nel kernel di Linux?
La „memory pressure“ significa che il kernel dedica una quantità di tempo percepibile a liberare memoria, invece di proseguire l'elaborazione dei processi utente; la CPU si dedica quindi maggiormente alle operazioni di scansione, scrittura ed espulsione, mentre le richieste rimangono in attesa. Distinguo chiaramente tra „RAM piena" e "mancanza di memoria utilizzabile" spazio libero“: Una cache „piena“ è un fenomeno normale; i colli di bottiglia si verificano solo quando gli investimenti in Reclaim aumentano. Il kernel esegue una scansione delle liste inattive, scrive sporco-elimina le pagine, svuota la cache dei file e sposta le pagine anonime non appena si scende al di sotto delle soglie di watermark. Il fattore determinante è il tempo impiegato per queste attività, che si riflette nei tempi di attesa delle attività e nei tempi di risposta prolungati. Un host può funzionare in modo silenzioso con un utilizzo del 95% %, purché la cache sia facilmente recuperabile, ma può bloccarsi pesantemente a basso carico di lavoro se le pagine anonime attive devono essere sostituite.
Comprendere e misurare il PSI
Pressure Stall Information (PSI) rende tangibile la pressione sulla memoria, poiché non misuro l'occupazione, ma i ritardi. In /proc/pressione/memoria Vedo „some“ e „full“: „some“ descrive i momenti in cui almeno un’attività è in attesa di memoria, mentre „full“ indica le fasi in cui tutte le attività sono bloccate. Esempio: „some avg10=4.67“ significa che negli ultimi 10 secondi si sono verificati 4,67 % di stallo dovuti a colli di bottiglia della memoria; „full avg10=0.30“ indica rari casi di blocco totale. Correlando tempestivamente i valori crescenti di „some“ con i tempi di risposta, provvedo a ridimensionare, ottimizzare o alleggerire il carico prima che si verifichino gravi OOM. Questa prospettiva mi impedisce di farmi ingannare da una RAM apparentemente „libera“, poiché le pagine libere senza un accesso rapido Reclaim-Ne approfittano pochi.
| Variabile misurata | Valore indicativo | Sintomo | Azione |
|---|---|---|---|
| Memoria PSI (media 10) | > 2–3 % prolungato | I tempi di risposta aumentano | Verificare il margine della RAM, regolare con precisione i limiti dei cgroup |
| Memoria PSI piena (avg10) | > 0,1 % percepibile | Tempi di inattività brevi | Identificare la causa, porre fine al thrashing |
| MemDisponibile | < 10 % di RAM | Margine ridotto | Alleggerire la cache/il carico di lavoro, pianificare la capacità |
| vmstat si/so | costante > 0 | Pressione di swap | Swappiness/Personalizza lo swap, proteggi l'Hotset |
Sintomi negli ambienti di hosting
Sugli host molto trafficati noto innanzitutto picchi di latenza, mentre il carico della CPU sembra rimanere moderato; il kernel è bloccato in cicli di reclaim, l’I/O si accumula e le richieste rimangono in attesa. Il carico medio sale, anche se i core sembrano liberi, perché molte attività sono bloccate dalla memoria o dall’I/O; questo è un segno distintivo di un aumento Stampa. Valori si/so persistenti in vmstat indicano che il sistema sta effettuando attivamente lo swap, il che rallenta gli handshake TLS, i contenuti dinamici e i percorsi di query. Se la situazione non viene risolta, il sistema entra in fase di thrashing: la CPU trascorre gran parte del tempo in paging e swapping, invece di svolgere attività utili. In caso di escalation, interviene l’OOM-Killer e termina i processi con un punteggio elevato; un intervento mirato Analisi dell'OOM-Killer mi aiuta a individuare schemi ricorrenti e configurazioni errate.
Rilevanza per i carichi di lavoro di hosting e i cgroup
Negli ambienti gestiti in modo condiviso, bastano poche applicazioni che consumano molte risorse di memoria per aumentare le latenze per molti clienti; i cgroup attenuano l'impatto, ma non risolvono il problema di un dimensionamento errato Istanze. Nei VPS e nelle istanze cloud, una quantità di RAM insufficiente o una strategia di swap inadeguata porta più rapidamente a picchi di carico; l’isolamento protegge gli altri servizi, ma non il proprio. I database si basano su grandi pool di buffer; se Reclaim li sostituisce o interviene lo swap, i tempi di query aumentano e la velocità di elaborazione diminuisce in modo significativo. Le orchestrazioni dei container utilizzano memory.low, memory.high e memory.max per proteggere i servizi importanti, limitare i blocchi e, in caso di emergenza, terminarli in modo mirato. Scelgo quindi i limiti in modo consapevole e monitoro il PSI per ogni servizio, per intervenire tempestivamente e garantire riserve per i servizi critici Carichi di lavoro tenere libero.
Strategia di monitoraggio e metriche
Controllo i valori di MemAvailable, Buffers e Cached per capire quanta memoria sia recuperabile nell’immediato; i valori di MemFree da soli possono facilmente indurre in errore. Contemporaneamente controllo vmstat: valori si/so persistenti indicano una pressione sullo swap, che accelera enormemente l’I/O e fa aumentare le latenze; per ulteriori approfondimenti su Utilizzo dello swap Utilizzo modelli diagnostici collaudati. PSI mi fornisce l’elemento mancante, poiché „some“ e „full“ quantificano i ritardi effettivi; genero allarmi al superamento delle soglie e distinguo i picchi di carico dai colli di bottiglia cronici. Le serie temporali ottenute tramite sar o lo stack di osservabilità rendono visibili gli schemi e mi aiutano a confermare i risultati dell’ottimizzazione. dmesg rivela gli eventi OOM che indicano limiti rigidi o configurazioni errate; in questo modo costruisco un quadro coerente dal punto di vista del kernel, del comportamento I/O e Applicazione.
Carichi di lavoro tipici sotto pressione
I server web come Nginx o Apache forniscono i contenuti più lentamente quando Reclaim e Swap sono in esecuzione in background; le connessioni Keep-Alive rimangono aperte più a lungo, il che aggrava le code. Gli stack PHP e Python occupano RAM a causa delle cache dei framework, delle parti JIT e dei dati di sessione; in caso di sovrascrittura, questi dati oscillano tra la RAM e lo storage, allungando notevolmente i tempi di risposta. I database perdono velocità non appena i pool di buffer si riducono o parti di essi finiscono nello swap; anche una minima latenza aggiuntiva per ogni operazione di I/O si somma in presenza di molte Domande. I servizi di caching come Redis o Memcached necessitano di accessi alla RAM; se le aree delle chiavi finiscono nello swap, il vantaggio viene meno e aumenta il rischio di essere terminati in caso di carico elevato. In tutti i casi, le metriche relative alla PSI e allo swap forniscono le indicazioni più chiare del fatto che la memoria è diventata il collo di bottiglia e non la CPU.
Ottimizzazione del sistema e parametri del kernel
Comincio da vm.swappiness: un valore moderatamente ridotto impedisce un ricorso eccessivo allo swap, senza però bloccare il reclaim necessario; misuro costantemente gli effetti con PSI. Successivamente ottimizzo vm.dirty_ratio e i limiti correlati, in modo da non innescare lunghe ondate di flush senza però provocare un’eccessiva scrittura di dati di piccole dimensioni; entrambi questi aspetti hanno effetti tangibili Effetti sulle latenze. Su Cgroups v2 imposto memory.low per i servizi critici, memory.high per la limitazione in caso di sovraccarico e memory.max come limite massimo con OOM controllabili. Presto particolare attenzione alle topologie NUMA: può verificarsi una pressione locale anche se a livello globale c’è ancora RAM libera; il binding di processi e memoria mitiga tali insidie. Infine, verifico il comportamento della cache di pagina; lo spostamento superfluo riduce i tassi di hit e comporta una perdita di tempo immediata nei carichi di lavoro web e database, a cui si aggiunge il Ottimizzazione della cache delle pagine fornisce spunti utili.
Uno sguardo approfondito ai percorsi di recupero
Per scegliere le misure più adeguate, distinguo tra kswapd e Recupero diretto. kswapd opera in modo asincrono quando si scende al di sotto dei livelli di soglia; il suo funzionamento è relativamente delicato fintanto che è disponibile una quantità sufficiente di cache facilmente recuperabile. Direct Reclaim interviene in modo sincrono nei contesti di esecuzione quando i thread hanno un bisogno urgente di pagine: è qui che si verificano i rallentamenti percepibili dagli utenti. Osservo se il reclaim colpisce maggiormente la cache dei file o le pagine anonime: se il kernel sostituisce principalmente la cache dei file, aumentano i cache miss; se sostituisce la memoria anonima (ad es. l’heap), si rischiano arresti bruschi e attività di swap. I moderni meccanismi di working set tengono conto delle distanze di refault per mantenere più a lungo le pagine utili; se nonostante ciò osservo molti refault ripetuti, so che gli hotset sono più grandi dello spazio disponibile spazio libero sono diventati.
Inoltre, tengo conto della compattazione e della deframmentazione: kcompactd cerca di creare aree contigue, ad esempio per grandi allocazioni o THP. Se la compattazione rimane indietro, noto un aumento dell’utilizzo della CPU da parte di kcompactd, latenze crescenti e un aumento della percentuale di PSI „full“ durante i picchi di carico. In questi casi, spesso è più sensato ridurre la pressione o adeguare le politiche THP, anziché limitarsi ad aumentare lo „swap“.
Le strategie di swap nel dettaglio
Lo swap non è un nemico, ma uno strumento; se utilizzato in modo errato, però, aumenta la latenza. Faccio una distinzione:
- Nessuno swap: Sicuro contro gli swap lag, ma rischioso in caso di picchi – gli OOM si verificano prima, Reclaim non dispone di un buffer di riserva.
- Swap moderato su un SSD veloce: ottimo per spostare in swap le pagine fredde e anonime; protegge gli hotset nella RAM, se i valori di swappiness e i limiti dei cgroup sono impostati in modo oculato.
- zswap/zram: La compressione alleggerisce il carico di I/O; è indicata per host con un carico di I/O ridotto o come buffer contro picchi di carico di breve durata. Verifico il budget della CPU e il rapporto di compressione per evitare che la CPU diventi un collo di bottiglia.
Non imposto il valore di swappiness su un livello basso in modo generalizzato; in caso di carichi di lavoro con una cache di file di grandi dimensioni, è opportuno impostare un valore di swappiness leggermente più alto per eliminare le pagine anonime inattive e mantenere stabile la cache di file. Proteggo i servizi critici (ad es. i database) con `memory.low` e, se necessario, bloccando i loro hotset nella RAM, in modo che lo swap non colpisca gli elementi sbagliati. È fondamentale che vmstat si/so e i valori PSI diminuiscono in modo costante quando adeguo la strategia; in caso contrario, procedo a una correzione.
THP, compattazione e frammentazione
Pagine enormi trasparenti (THP) riducono gli accessi alla TLB e aiutano le applicazioni che sollecitano la CPU e richiedono un uso intensivo della memoria. In condizioni di carico elevato, tuttavia, generano operazioni di compattazione; l’impostazione „always“ può quindi causare lunghi tempi di stallo. Utilizzo „madvise“ in modo mirato per i carichi di lavoro che ne traggono vantaggio (ad es. determinati motori in-memory) e, nel caso di stack web sensibili alla latenza, preferisco disattivare THP in modo mirato o abilitarlo solo tramite madvise. Inoltre, osservo vm.compaction_proactiveness e verifica se la compattazione proattiva posticipa la formazione di stalle o le riduce effettivamente. Se le facce THP vengono spesso tagliate o se la compattazione si surriscalda, ciò indica una quantità insufficiente di spazio libero oppure modelli di allocazione inadeguati nell'applicazione.
Trappole NUMA e pressione locale
Sugli host NUMA, la „RAM libera“ globale è ingannevole: un socket può essere sotto pressione, mentre un altro rimane inutilizzato. Controllo le statistiche NUMA e ancoro i processi a livello locale (vincolo CPU/memoria), in modo che gli hotset rimangano vicini al carico di calcolo. Il Direct Reclaim su un nodo, nonostante le riserve globali, segnala squilibri NUMA; in questo caso sono utili le allocazioni interleaved per servizi ampiamente distribuiti o il binding rigoroso per carichi di lavoro monolitici. Il PSI per cgroup, combinato con le statistiche NUMA, mi mostra se è un singolo nodo a generare le code.
Misure relative alle applicazioni
Analizzo i profili di memoria con ps, top, htop e strumenti di profilazione per individuare i veri “divoratori” di memoria e le perdite; nel farlo, osservo come cambiano gli hotset nel corso del tempo. Scelgo con attenzione le cache delle applicazioni: troppo grandi generano pressione, troppo piccole compromettono la velocità; effettuo le regolazioni tenendo conto dei valori PSI e dei tempi di risposta, non basandomi sull’istinto. Quando vengono rilevati segnali di pressione, l’applicazione può liberare volontariamente cache meno critiche o dati temporanei; in questo modo riduco i blocchi senza intervenire sui limiti globali. Adatto i parametri di avvio e l’ottimizzazione del GC (ad es. per le JVM) in modo che i working set rimangano ben contenuti nella RAM; smorzo i modelli di allocazione aggressivi tramite il batching. Tengo d’occhio anche gli artefatti di build e i simboli di debug, poiché i residui trascurati comportano costi nascosti Memoria e aumentano il rischio di stallo in seguito.
Funzionalità avanzate di Cgroups v2 e strategie OOM
Con Cgroups v2 separo chiaramente protezione, limitazione e limiti rigidi: memoria.bassa Riserva headroom per i servizi critici; il resto del reclaim viene assegnato ai gruppi meno importanti. memoria.alta in caso di superamento dei limiti, limita l'utilizzo in modo mirato e costringe le applicazioni a liberare memoria prima che il sistema ne risenta. memoria.max è l'ultima linea di difesa: se viene superata, si verifica un OOM in un contesto controllato. Impostare PSI per ogni cgroup, in modo che gli allarmi scoccino proprio dove si verificano gli stalli; il PSI globale rimane stabile mentre un singolo servizio va in crash – è proprio questo schema che voglio individuare. Insieme alle priorità OOM, stabilisco regole di sacrificio chiare: i worker batch non essenziali vengono terminati per primi, mentre le API di base mantengono la loro spazio libero.
Virtualizzazione: ballooning, KSM e overcommit
Negli ambienti virtualizzati mi trovo di fronte a una doppia pressione: l’ospite vede una RAM apparentemente libera, mentre l’hypervisor tramite Mongolfiera sottrae. Questa operazione aumenta i costi di reclaim per entrambe le parti. Misuro il PSI nell'ospite e lo metto in correlazione con le metriche dell'hypervisor; se il PSI aumenta durante gli eventi di ballooning, la VM necessita di maggiore capacità garantita o di politiche Cgroup più efficaci nell'host. KSM Consente di risparmiare RAM grazie alla deduplicazione delle pagine identiche, ma comporta un carico sulla CPU; nelle configurazioni di hosting con molte VM simili può essere vantaggioso, purché il carico aggiuntivo sulla CPU non comprometta gli SLO. Prevedo l’overcommit (ad es. l’assegnazione aggressiva di molte VM di piccole dimensioni) solo con riserve SLO fisse e una rigorosa memoria.bassa per sistemi in cui la latenza è un fattore critico.
Scelte architetturali nell'hosting
Punto sulla distribuzione orizzontale, in modo che le singole istanze subiscano meno picchi di carico; i pool scalabili attenuano i picchi anomali e mantengono le latenze più contenute. Distinguo chiaramente i ruoli: database, applicazioni e caching dispongono di pool di risorse dedicati, in modo che i processi di reclaim non generino effetti collaterali imprevisti oltre i confini del sistema. Scelgo lo storage tenendo conto della latenza di scrittura, poiché i flush delle pagine sporche incidono direttamente sui tempi di risposta; un percorso veloce riduce sensibilmente i tempi di reclaim. Nei cluster prevedo riserve di RAM per ogni nodo e intervengo tramite politiche di scheduler, in modo che il carico e il consumo di memoria rimangano distribuiti in modo più uniforme. Automatizzo il ridimensionamento con soglie PSI, in modo che l’aumento dei valori „some“ inneschi azioni prima che si verifichino brusche frenate e Uccidere-si verificano eventi.
Pianificazione della capacità e modelli di margine di manovra
Definisco l’headroom in termini misurabili: mantengo riserve sufficienti affinché il valore „some“ PSI rimanga al di sotto di soglie definite durante i picchi normali e il valore „full“ non si verifichi praticamente mai. A tal fine utilizzo i percentili (ad es. il 99° percentile del carico orario) e pianifico 10–30 % di RAM aggiuntiva a seconda della volatilità del carico di lavoro. Ai database vengono assegnate riserve fisse maggiori, mentre i front-end web scalano in modo più dinamico. Calibro i tempi di rimbalzo: con quale rapidità scendono il PSI e si/so dopo un picco? Se rimangono elevati, è segno di riserve insufficienti o di una strategia di swap/dirty inadeguata. In questo modo, la pianificazione della capacità diventa un processo continuo anziché una stima annuale.
Allarme e regolazione controllata da SLO
Collegherò PSI agli SLO degli utenti: se „some avg10“ aumenta contemporaneamente alle latenze dell’API, interverrò. Classifico gli allarmi in „giallo“ (persistente 2–3 % „some“, „full“ vicino a 0) e „rosso“ (oltre 5 % „some“ o „full“ > 0,1 %). Gli allarmi basati su cgroup aiutano a isolare la minoranza rumorosa. Inoltre, imposto allarmi per l’aumento delle code dirty e dei tempi di attesa in scrittura, in modo da poter livellare tempestivamente le onde dirty. L’obiettivo è che le misure di ottimizzazione (swappiness, memory.high, dimensioni della cache) siano monitorabili e reversibili; implemento le modifiche gradualmente e confronto i dati «prima» e «dopo» utilizzando le stesse metriche.
Diagnosi passo dopo passo nella vita quotidiana
Per prima cosa controllo `free -h` e `MemAvailable`: se il valore cala in modo significativo, cerco le cache che possono essere liberate in modo sensato e i servizi con hotset in crescita. Successivamente eseguo `vmstat` a intervalli brevi per individuare eventuali tendenze; uno swapping prolungato conferma la pressione e mi conduce al percorso I/O. Successivamente leggo /proc/pressure/memory e valuto i valori „some“ e „full“ su intervalli di 10, 60 e 300 secondi; collego direttamente i valori medi in aumento alle latenze osservate. dmesg mi mostra tracce di OOM e rivela quali processi hanno recentemente causato o subito crisi di memoria; da ciò deduco limiti e priorità per i Cgroup. Da tutto ciò formulo un’ipotesi, implemento piccoli interventi di ottimizzazione, verifico tramite PSI e mantengo la Tempo di risposta in sintesi.
Runbook e catene di cause tipiche
Ci sono alcuni schemi che mi capitano spesso:
- I processi di backup o di scansione sostituiscono la cache delle pagine: Improvvisamente i tassi di cache hit calano, il web e il database rallentano. Misura: limitare i job (priorità I/O), spostare le finestre temporali, impostare `memory.high` per il cgroup dei job, proteggere il budget della cache di pagina dei servizi critici.
- Vulnerabilità nei processi worker: Aumento graduale della memoria anonima; il PSI „some“ continua a salire nel corso delle ore. Misure da adottare: identificare la perdita di memoria, introdurre politiche di riavvio automatico e riciclaggio della memoria, impostare limiti di memoria affinché le perdite non mettano a rischio l’intero host.
- Stalli causati dal THP: Il carico di kcompactd aumenta durante i picchi di traffico. Misura: impostare THP su „madvise“, adeguare i servizi interessati, verificare i parametri di compattazione, aumentare il margine di sicurezza.
- Stampa locale NUMA: Un socket va in thrash nonostante ci sia RAM libera a livello globale. Misura: correggere le affinità, impostare l'interleave per carichi di lavoro molto distribuiti, regolare la distribuzione del carico nello scheduler.
- Swap su dischi lenti: se aumenta, i tempi di risposta salgono alle stelle. Misura: spostare lo swap su uno storage più veloce, valutare zswap/zram, ottimizzare lo swappiness e le politiche dei cgroup.
Ogni runbook si conclude con una fase di convalida: i valori „some/full“ diminuiscono e le latenze si stabilizzano? Se la risposta è no, significa che l’ipotesi era errata o incompleta – in tal caso, continuo a iterare.
Strumenti e tracciamento durante il funzionamento
Oltre agli strumenti classici, mi affido a un’analisi più approfondita: osservo i rapporti tra cache di pagina e Anon, i tassi di page fault, i modelli di refault e le code di writeback. Gli approcci eBPF e di tracciamento mi indicano con precisione dove si verificano i tempi di attesa – ad esempio lungo i percorsi di reclaim, nel writeback o durante l’allocazione di blocchi di grandi dimensioni. Per me è importante disporre di una strumentazione leggera e adatta all’ambiente di produzione: finestre di attivazione brevi, campionamento anziché monitoraggio continuo e una chiara correlazione con le metriche dell’applicazione. In questo modo riesco a individuare le cause prima di procedere a modifiche su larga scala dei parametri.
Punti chiave e prossimi passi
Il termine “memory pressure” descrive il tempo perso a causa della carenza di memoria, non solo della RAM occupata; lo misuro con PSI, individuo tempestivamente le tendenze e agisco sulla base dei dati. Chi analizza insieme MemAvailable, vmstat si/so, PSI e dmesg, individua le vere cause dei picchi di latenza e del thrashing. Grazie all’ottimizzazione di swappiness, dirty e cgroup, riduco in modo mirato i blocchi e garantisco ai servizi importanti il loro spazio libero. A livello di architettura, la distribuzione orizzontale, la chiara suddivisione dei ruoli e i percorsi di archiviazione veloci attenuano le conseguenze di ogni picco di carico. Alla fine, ciò che conta è che io colleghi continuamente la diagnosi alle contromisure: misurare, adeguare, misurare nuovamente – fino a quando le prestazioni e Stabilità di nuovo a posto.


