Risoluzione dei Problemi di Esaurimento delle Risorse Linux: CPU, Memoria e Spazio su Disco

Risolvi i problemi di esaurimento di CPU, memoria e disco su Linux con comandi pratici, passaggi di pulizia sicuri e controlli delle cause profonde.

Risoluzione dei Problemi di Esaurimento delle Risorse Linux: CPU, Memoria e Spazio su Disco

Quando un server Linux esaurisce CPU, memoria o spazio su disco, il primo sintomo è solitamente vago: il sito è lento, SSH si blocca dopo il login, i deployment falliscono o un servizio continua a riavviarsi. Il modo più rapido per gestire l'incidente è identificare quale risorsa è esaurita, quindi trovare il processo o il filesystem responsabile.

Esegui prima i controlli meno rischiosi. Comandi di sola lettura come top, free, df, du, vmstat e journalctl ti forniscono un quadro senza modificare la macchina. Uccidere processi ed eliminare file può essere necessario, ma non è una diagnosi.

Identificare il Colpevole: Monitoraggio delle Risorse di Sistema

Prima di poter risolvere un problema di esaurimento delle risorse, devi individuare quale risorsa è sovrautilizzata e quale processo è responsabile. Linux fornisce un ricco set di strumenti da riga di comando per questo scopo.

Monitoraggio dell'Utilizzo della CPU

Un utilizzo elevato della CPU può rendere il sistema lento e poco reattivo. Spesso è causato da un processo incontrollato, un'applicazione impegnativa o uno script inefficiente.

  • top: Questo è un monitor di sistema in tempo reale indispensabile. Mostra un elenco dinamico dei processi, ordinati per utilizzo della CPU per impostazione predefinita. Puoi vedere l'utilizzo complessivo della CPU, l'utilizzo della memoria e i dettagli dei singoli processi.

    top
    

    All'interno di top, premi 1 per vedere l'utilizzo dei singoli core della CPU. Premi P per ordinare per utilizzo della CPU. Cerca i processi che consumano costantemente una percentuale elevata di CPU.

  • htop: Una versione interattiva migliorata di top. È spesso preferito per la sua facilità d'uso, l'output colorato e la navigazione più semplice.

    htop
    

    Simile a top, htop consente di ordinare per utilizzo della CPU e fornisce informazioni dettagliate sui processi.

  • mpstat: Parte del pacchetto sysstat, mpstat fornisce statistiche dettagliate della CPU, inclusi l'utilizzo per processore, i conteggi degli interrupt e i cambi di contesto.

    mpstat -P ALL 1
    

    Questo comando mostrerà le statistiche della CPU per tutti i core ogni secondo.

Controlla anche il carico medio rispetto al numero di CPU:

uptime
nproc

Un carico medio di 8 significa qualcosa di molto diverso su una VM a 2 core rispetto a un host a 32 core. Il carico include anche le attività in attesa di I/O non interruptibile, quindi un carico medio elevato con un basso utilizzo della CPU potrebbe effettivamente indicare un problema con il disco o l'archiviazione di rete.

Monitoraggio dell'Utilizzo della Memoria

Quando un sistema esaurisce la RAM disponibile e lo spazio di swap, inizia a utilizzare lo spazio su disco come memoria virtuale, che è significativamente più lenta, portando a un grave degrado delle prestazioni.

  • free -h: Mostra la quantità totale di memoria fisica e di swap libera e utilizzata nel sistema, insieme ai buffer e alle cache utilizzati dal kernel. Il flag -h rende l'output leggibile dall'uomo (ad esempio, MB, GB).

    free -h
    

    Presta attenzione alla memoria disponibile e allo spazio di swap utilizzato. Un utilizzo elevato dello swap indica RAM insufficiente.

  • top / htop: Sia top che htop mostrano l'utilizzo della memoria per processo. Cerca i processi con un valore %MEM elevato.

  • vmstat: Riporta le statistiche della memoria virtuale. Può mostrare informazioni su processi, memoria, paginazione, I/O su blocchi, trap e attività della CPU.

    vmstat 5
    

    Questo comando riporterà le statistiche ogni 5 secondi. Osserva le colonne si (swap-in) e so (swap-out); valori elevati indicano un significativo swapping della memoria.

Per possibili kill OOM, controlla il log del kernel:

dmesg -T | grep -i 'killed process'
journalctl -k --since "1 hour ago" | grep -i oom

Un kill OOM cambia l'incidente. La domanda immediata diventa quale processo è stato ucciso, perché ha superato la memoria disponibile e se systemd o un orchestrator lo ha riavviato.

Monitoraggio dello Spazio su Disco

Una partizione del disco piena può impedire alle applicazioni di scrivere dati, causare errori e persino impedire l'avvio del sistema.

  • df -h: Riporta l'utilizzo dello spazio su disco del filesystem. Il flag -h rende l'output leggibile dall'uomo.

    df -h
    

    Questo comando elencherà tutti i filesystem montati e mostrerà la loro dimensione totale, lo spazio utilizzato, lo spazio disponibile e il punto di mount. Cerca le partizioni al 100% o quasi.

  • du -sh <directory>: Stima l'utilizzo dello spazio su file per una determinata directory. Il flag -s riassume e -h lo rende leggibile dall'uomo.

    du -sh /var/log/*
    

    Usalo per trovare quali sottodirectory consumano più spazio su disco.

Controlla anche l'utilizzo degli inode:

df -ih

Un filesystem può avere gigabyte liberi ed essere comunque impossibilitato a creare file se ha esaurito gli inode. Questo accade con milioni di file piccoli: voci di cache, code di posta, file di sessione, artefatti di build o log mal ruotati.

Risolvere i Problemi di Esaurimento delle Risorse

Una volta identificata la risorsa problematica e il processo incriminato, puoi adottare misure per risolvere il problema.

Affrontare l'Utilizzo Elevato della CPU

  1. Identificare il Processo: Usa top o htop per trovare l'ID del processo (PID) che consuma molta CPU.
  2. Investigare il Processo: Determina cos'è il processo. È un'applicazione utente, un servizio di sistema o qualcosa di inaspettato?
    • Utilizzo Elevato Legittimo: Se un'applicazione legittima utilizza molta CPU (ad esempio, compilazione di software, codifica video), potresti dover attendere che finisca, programmarla per le ore non di punta o aggiornare l'hardware.
    • Processo Incontrollato: Se un processo è bloccato in un ciclo o consuma CPU eccessiva involontariamente, puoi provare a riavviarlo. Se non funziona, potresti doverlo terminare.
  3. Terminare il Processo (Usare con Cautela!): Puoi usare il comando kill per inviare segnali ai processi. I segnali più comuni sono:
    • SIGTERM (15): Chiede gentilmente al processo di terminare.
    • SIGKILL (9): Termina forzatamente il processo immediatamente. Dovrebbe essere l'ultima risorsa poiché non consente al processo di eseguire la pulizia.
    # Termina gentilmente il processo con PID 1234
    kill 1234
    
    # Termina forzatamente il processo con PID 1234
    kill -9 1234
    
  4. Controllare i Log: Esamina i log di sistema (ad esempio, /var/log/syslog, /var/log/messages, log specifici dell'applicazione) per errori relativi al processo problematico.
  5. Ottimizzare Applicazioni/Script: Se l'utilizzo elevato della CPU è dovuto a un'applicazione o uno script inefficiente, considera di ottimizzare il codice o la configurazione.

La CPU elevata non è sempre negativa. Un job batch che utilizza tutti i core per un breve periodo può andare bene. Un processo single-thread bloccato al 100% di un core mentre le richieste si accodano dietro è diverso. Osserva la durata, l'impatto sull'utente e se ci si aspetta che il processo sia occupato.

Se hai bisogno di più contesto prima di riavviare un servizio, cattura un'istantanea:

ps -fp <pid>
sudo lsof -p <pid> | head
sudo strace -p <pid> -tt -T -f

Usa strace con attenzione sui sistemi di produzione. Può aggiungere overhead, ma un breve campione spesso ti dice se il processo è in loop, in attesa su file, sta fallendo chiamate di rete o sta aprendo ripetutamente la stessa risorsa.

Risolvere Perdite di Memoria ed Esaurimento

Una perdita di memoria si verifica quando un programma non rilascia la memoria di cui non ha più bisogno, consumando gradualmente tutta la RAM disponibile. Questo può portare a swapping eccessivo e a un sistema non reattivo.

  1. Identificare il Processo: Usa top o htop per trovare i processi con memoria elevata (%MEM) o valori RSS (resident set size) che aumentano costantemente nel tempo.
  2. Investigare il Processo: Determina la natura dell'applicazione. È un'applicazione nota con potenziali problemi di memoria o qualcosa di personalizzato?
  3. Riavviare l'Applicazione/Servizio: Spesso, il semplice riavvio dell'applicazione o del servizio può risolvere temporaneamente una perdita di memoria liberando la memoria accumulata.
    # Esempio: Riavvio del server web Apache
    sudo systemctl restart apache2
    
  4. Controllare il Monitoraggio Specifico dell'Applicazione: Molte applicazioni (ad esempio, server web, database) hanno i propri strumenti di monitoraggio o log che possono aiutare a diagnosticare i problemi di memoria.
  5. Analizzare i Core Dump: Per le applicazioni critiche, potresti dover abilitare i core dump e utilizzare strumenti di debug (come gdb) per analizzare lo stato della memoria quando si verifica la perdita. Questo è un passaggio di risoluzione dei problemi avanzato.
  6. Aumentare lo Spazio di Swap (Misure Temporanee): Se non puoi risolvere immediatamente la perdita, puoi aumentare lo spazio di swap per fornire più memoria virtuale. Tuttavia, questa è una soluzione alternativa, non una soluzione.
  7. Aggiornamento Hardware: Se il tuo sistema esaurisce costantemente la memoria per il suo carico di lavoro, potresti dover aggiungere più RAM fisica.

Un'indagine migliore sulla memoria osserva il cambiamento nel tempo. Uno screenshot di top dice solo chi è grande ora. Una perdita è una tendenza.

while true; do
  date
  ps -eo pid,comm,rss,%mem --sort=-rss | head -15
  sleep 60
done

Se lo stesso processo sale costantemente tra i campioni senza scendere dopo che il traffico cala, hai un segnale di perdita più forte. Se molti processi crescono insieme durante il traffico di punta, il carico di lavoro potrebbe semplicemente superare la capacità o i limiti di concorrenza.

Per i servizi systemd, controlla se esistono già limiti di memoria:

systemctl show <service> -p MemoryCurrent -p MemoryMax

Per i container, free -h a livello di host potrebbe sembrare a posto mentre un container raggiunge il proprio limite. Controlla docker stats, kubectl top pod o gli eventi dell'orchestrator per kill OOM.

Gestire Partizioni Disco Piene

Quando una partizione del disco si riempie, può causare vari guasti al sistema. Di solito è richiesta un'azione immediata.

  1. Identificare la Partizione Piena: Usa df -h per individuare la o le partizioni al 100% di capacità.
  2. Trovare File/Directory Grandi: Usa du -sh o du -h --max-depth=1 <directory> per navigare nell'albero delle directory e trovare cosa consuma spazio.
    # Trova le directory più grandi nella partizione root
    sudo du -h --max-depth=1 / | sort -rh
    
    I colpevoli comuni includono file di log (/var/log), file temporanei (/tmp), cache dei pacchetti e dati utente.
  3. Pulire i File di Log: I file di log possono diventare molto grandi. Spesso puoi eliminare in sicurezza i vecchi log o configurare la rotazione dei log (logrotate) per gestire automaticamente le loro dimensioni.
    • Eliminare Vecchi Log: Fai attenzione e assicurati di non eliminare log attualmente attivi. Puoi usare find per eliminare file più vecchi di un certo numero di giorni.
      # Elimina file .log più vecchi di 30 giorni in /var/log/myapp
      sudo find /var/log/myapp -name "*.log" -type f -mtime +30 -delete
      
    • Rotazione dei Log: Assicurati che logrotate sia configurato correttamente per i tuoi servizi. Di solito viene eseguito quotidianamente e gestisce l'archiviazione e l'eliminazione dei vecchi log.
  4. Pulire la Cache del Gestore di Pacchetti: I gestori di pacchetti spesso conservano i file dei pacchetti scaricati. Pulirli può liberare spazio significativo.
    • Debian/Ubuntu (apt):
      sudo apt autoremove
      sudo apt clean
      
    • CentOS/RHEL/Fedora (yum/dnf):
      sudo yum autoremove  # o dnf autoremove
      sudo yum clean all   # o dnf clean all
      
  5. Rimuovere Pacchetti Inutilizzati: Disinstalla il software che non ti serve più.
    • Debian/Ubuntu: sudo apt remove <nome_pacchetto>
    • CentOS/RHEL/Fedora: sudo yum remove <nome_pacchetto> o sudo dnf remove <nome_pacchetto>
  6. Controllare le Directory Temporanee: I file in /tmp sono spesso sicuri da eliminare, specialmente dopo un riavvio, ma fai attenzione se le applicazioni li stanno usando attivamente.
  7. Svuotare il Cestino: Se stai usando un ambiente desktop, controlla i cestini degli utenti.
  8. Considerare il Ridimensionamento delle Partizioni: Se lo spazio è costantemente un problema e la pulizia non è sufficiente, potresti dover ridimensionare le partizioni o aggiungere più storage. Questa è un'operazione più avanzata che potrebbe richiedere lo smontaggio delle partizioni o l'avvio da un ambiente live.

Fai attenzione ai file eliminati che sono ancora aperti. df potrebbe mostrare un filesystem pieno anche dopo aver rimosso un file di log di grandi dimensioni, perché un processo in esecuzione ha ancora l'handle del file aperto.

sudo lsof +L1

Se un file eliminato è ancora tenuto aperto, il riavvio o il ricaricamento del servizio proprietario rilascia lo spazio. Fallo intenzionalmente; non riavviare un database o un servizio critico nel bel mezzo di un incidente senza comprenderne l'impatto.

Per i log di journal, preferisci la pulizia con journalctl rispetto all'eliminazione manuale dei file:

journalctl --disk-usage
sudo journalctl --vacuum-time=14d

Per gli host Docker, controlla i log dei container e le immagini inutilizzate:

docker system df
docker ps --size

Non eseguire comandi di pulizia generici alla cieca su un host di produzione. Possono rimuovere immagini, cache di build, container fermati e reti che qualcuno si aspettava di mantenere.

Un Ordine di Triage che Funziona Sotto Pressione

Quando tutto è lento, usa un ordine fisso in modo da non saltare tra teorie.

  1. Conferma che l'host è raggiungibile e non in sola lettura:

    uptime
    date
    mount | grep ' ro,'
    
  2. Controlla CPU e carico:

    top
    uptime
    
  3. Controlla memoria e swap:

    free -h
    vmstat 1 5
    
  4. Controlla spazio su disco e inode:

    df -h
    df -ih
    
  5. Controlla errori recenti del kernel e dei servizi:

    journalctl -p warning..alert --since "30 minutes ago"
    journalctl -k --since "30 minutes ago"
    

Questo ordine cattura rapidamente i guasti comuni: saturazione della CPU, tempeste di swap, filesystem pieni, esaurimento degli inode, kill OOM ed errori di archiviazione.

Scegliere la Soluzione Immediata Meno Peggiore

Durante un'interruzione, potresti aver bisogno di una soluzione a breve termine prima che la soluzione permanente sia pronta.

Per l'esaurimento della CPU, un riavvio graduale del servizio può essere più sicuro di kill -9, specialmente per software che scrive stato. Se un job batch sta affamando il traffico utente, abbassa la sua priorità:

sudo renice +10 -p <pid>
sudo ionice -c2 -n7 -p <pid>

Per l'esaurimento della memoria, ridurre la concorrenza è spesso più sicuro che aggiungere swap e sperare. Abbassa i conteggi dei worker web, metti in pausa i job batch o disabilita temporaneamente le funzionalità costose. Lo swap può far guadagnare tempo, ma uno swap pesante di solito trasforma un guasto chiaro in un guasto lento.

Per l'esaurimento del disco, elimina o ruota i file che conosci. Buoni candidati sono i vecchi log compressi, le cache dei pacchetti, gli artefatti di build obsoleti e i file temporanei di job fermati. Cattivi candidati sono i file di database, i log attivi, i file sconosciuti nelle directory dei dati dell'applicazione e qualsiasi cosa tu non possa spiegare.

Note sulla Causa Radice da Catturare

Dopo che il sistema è stabile, scrivi cosa è cambiato. Le note utili sono concrete:

  • Il filesystem o la risorsa esatta che era esaurita.
  • Il processo, l'utente, il servizio, il container o il cron job coinvolto.
  • L'output del comando che lo ha dimostrato.
  • L'azione immediata intrapresa.
  • La correzione permanente necessaria.

Questa non è burocrazia fine a se stessa. Il prossimo incidente è molto più facile quando sai che /var si è riempito perché i log di debug sono cresciuti dopo un deploy, o che la pressione della memoria è iniziata quando il numero di worker è raddoppiato.

Best Practice per la Prevenzione

  • Monitoraggio Regolare: Implementa il monitoraggio regolare di CPU, memoria e spazio su disco utilizzando strumenti come top, htop, free, df e soluzioni di monitoraggio dedicate (ad esempio, Nagios, Zabbix, Prometheus).
  • Automatizzare la Rotazione dei Log: Assicurati che logrotate sia configurato correttamente per tutti i servizi che generano log.
  • Ottimizzare le Configurazioni delle Applicazioni: Ottimizza le impostazioni dell'applicazione per essere più efficienti in termini di risorse. Ad esempio, ottimizza i processi worker del server web, i pool di connessione del database, ecc.
  • Impostare Avvisi: Configura avvisi per utilizzo elevato sostenuto, crescita rapida, kill OOM, pienezza del filesystem, esaurimento degli inode e riavvii dei servizi. Avvisa sulle tendenze, non solo sui limiti rigidi.
  • Aggiornamenti di Sistema: Mantieni aggiornati il sistema e le applicazioni, poiché i miglioramenti delle prestazioni e le correzioni di bug sono spesso inclusi nelle versioni più recenti.
  • Limiti delle Risorse: Per i sistemi multiutente o gli ambienti containerizzati, considera l'impostazione di limiti delle risorse (ad esempio, usando ulimit o cgroups) per impedire a un singolo processo di affamare gli altri.

La risoluzione dei problemi di esaurimento delle risorse è principalmente un restringimento disciplinato. Trova la risorsa limitata, identifica il proprietario, apporta la modifica stabilizzante più piccola, quindi correggi il motivo per cui è successo. Gli strumenti di base sono sufficienti per la maggior parte degli incidenti se li usi in quest'ordine e resisti all'impulso di eliminare o uccidere prima di capire cosa stai toccando.