In alcuni scenari ad alto carico o in presenza di problemi lato backend, Apache può degradare progressivamente fino a diventare lento, saturare le risorse o smettere di rispondere correttamente.
Per mitigare questo tipo di problemi è possibile implementare un watchdog leggero in Bash che:
- monitora periodicamente lo stato del sistema;
- verifica alcune metriche critiche;
- esegue automaticamente un
reloado unrestartdi Apache; - registra gli eventi tramite
syslogejournalctl.
Questo approccio è particolarmente utile in ambienti:
- con reverse proxy Apache;
- con backend applicativi instabili;
- con leak di connessioni;
- dove è necessario un meccanismo di self-healing semplice e trasparente.
Obiettivo dello script
Lo script controlla:
- RAM disponibile;
- numero di PID usati dal servizio Apache;
- connessioni TCP in stato
close-waitverso un backend specifico; - health check HTTP locale;
In base alle soglie configurate:
- esegue un
reloaddi Apache; - oppure un
restartcompleto; - scrive i dettagli nel journal di systemd.
Script completo
#!/bin/bash
# --- PARAMETRI DI SOGLIA ---
SOGLIA_RAM_FREE_MB=100
SOGLIA_PIDS_PERCENT=60
SOGLIA_close-wait=300
# --- RACCOLTA DATI ---
# Usiamo percorsi assoluti per cron e variabili pulite
RAM_DISPONIBILE_MB=$(/usr/bin/free -m | grep Mem | awk '{print $7}')
# Conteggio in tempo reale delle connessioni orfane in close-wait
close-wait_COUNT=$(/usr/bin/ss -H -tanp state close-wait | /usr/bin/wc -l)
# Gestione PIDs con controllo esistenza file (evita errori se Apache è spento)
PIDS_FILE="/sys/fs/cgroup/system.slice/apache2.service/pids.current"
MAX_FILE="/sys/fs/cgroup/system.slice/apache2.service/pids.max"
if [ -f "$PIDS_FILE" ]; then
CURRENT_APACHE_PIDS=$(cat "$PIDS_FILE")
MAX_APACHE_PIDS=$(cat "$MAX_FILE")
# Se MAX è la stringa "max", o è 0, o è vuoto -> la percentuale è 0 (limite infinito)
if [ "$MAX_APACHE_PIDS" = "max" ] || [ -z "$MAX_APACHE_PIDS" ] || [ "$MAX_APACHE_PIDS" -eq 0 ] 2>/dev/null; then
PERCENTUAL_PIDS=0
else
PERCENTUAL_PIDS=$(( 100 * CURRENT_APACHE_PIDS / MAX_APACHE_PIDS ))
fi
else
PERCENTUAL_PIDS=0
fi
# --- LOGICA DI CONTROLLO ---
AZIONE_NECESSARIA=false
TIPO_AZIONE="reload" # Default
if [ "$RAM_DISPONIBILE_MB" -lt "$SOGLIA_RAM_FREE_MB" ]; then
MOTIVO="RAM bassa (${RAM_DISPONIBILE_MB}MB)"
AZIONE_NECESSARIA=true
TIPO_AZIONE="restart" # Se la RAM è finita, il reload è troppo lento
elif [ "$PERCENTUAL_PIDS" -gt "$SOGLIA_PIDS_PERCENT" ]; then
MOTIVO="PIDs al ${PERCENTUAL_PIDS}% (${CURRENT_APACHE_PIDS}/${MAX_APACHE_PIDS})"
AZIONE_NECESSARIA=true
TIPO_AZIONE="reload"
elif [ "$close-wait_COUNT" -gt "$SOGLIA_close-wait" ]; then
MOTIVO="Rilevato leak di socket (${close-wait_COUNT} connessioni in close-wait)"
AZIONE_NECESSARIA=true
TIPO_AZIONE="reload" # Il reload è sufficiente a liberare i socket orfani
fi
# Check sopravvivenza: se Apache non risponde, forza RESTART a prescindere dalle soglie
if ! /usr/bin/curl -s --max-time 5 http://127.0.0.1/ > /dev/null; then
MOTIVO="Apache non risponde (Health Check fallito)"
AZIONE_NECESSARIA=true
TIPO_AZIONE="restart"
fi
# --- AZIONE ---
if $AZIONE_NECESSARIA; then
echo "$(date): Allarme: ${MOTIVO}. Eseguo ${TIPO_AZIONE}."
/usr/bin/logger -t apache_health_watchdog "Allarme: ${MOTIVO}. Eseguo ${TIPO_AZIONE}."
if [ "$TIPO_AZIONE" == "reload" ]; then
/usr/bin/systemctl reload apache2
# Se il reload fallisce (es. kernel già in fork rejected), prova il restart
if [ $? -ne 0 ]; then
/usr/bin/logger -t apache_health_watchdog "Reload fallito, forzo restart."
/usr/bin/systemctl restart apache2
fi
else
/usr/bin/systemctl restart apache2
fi
fi
Installazione
Salvare lo script in:
/usr/local/sbin/check_system_health.sh
Rendere il file eseguibile:
chmod +x /usr/local/sbin/check_system_health.sh
Configurazione del cron
Aggiungere in /etc/crontab:
*/2 * * * * root flock -n /tmp/apache_watchdog.lock /usr/local/sbin/check_system_health.sh >> /var/log/apache_health_watchdog.log 2>&1
Questo esegue il controllo ogni 2 minuti.
Perché usare flock
flock evita esecuzioni concorrenti dello script.
In condizioni di degrado del sistema:
- un controllo potrebbe impiegare più tempo del previsto;
- il cron successivo potrebbe partire mentre il precedente è ancora attivo;
- si rischiano reload o restart multipli contemporanei.
Con:
flock -n /tmp/apache_watchdog.lock
solo una istanza dello script può essere eseguita alla volta.
Analisi delle metriche monitorate
1. RAM disponibile
free -m
Lo script utilizza:
awk '{print $7}'
che corrisponde alla colonna available.
Se la memoria disponibile scende sotto:
SOGLIA_RAM_FREE_MB=100
viene eseguito un restart completo di Apache.
Questo è utile perché:
- il
reloadpuò richiedere fork aggiuntivi; - in condizioni di memoria critica il reload potrebbe peggiorare la situazione;
- un restart libera immediatamente worker e memoria frammentata.
2. Saturazione PID Apache
Lo script legge direttamente i contatori cgroup di systemd:
/sys/fs/cgroup/system.slice/apache2.service/pids.current
e:
/sys/fs/cgroup/system.slice/apache2.service/pids.max
Questo approccio è molto più affidabile rispetto al parsing di ps.
Se il servizio supera:
SOGLIA_PIDS_PERCENT=60
viene eseguito un reload.
Questo permette di:
- rigenerare worker;
- liberare processi stuck;
- evitare il raggiungimento del limite massimo PID.
3. Socket close-wait
Lo stato close-wait indica:
- il peer remoto ha chiuso la connessione;
- il processo locale non ha ancora rilasciato il socket.
Molte connessioni in close-wait possono indicare:
- leak applicativi;
- backend instabili;
- worker Apache bloccati;
- timeout mal configurati.
Lo script utilizza:
ss -tanp state close-wait
Questo approccio è preferibile rispetto a netstat perché:
-
ssè più moderno; - usa meno CPU;
- legge direttamente dal kernel tramite netlink;
- è più affidabile sotto alto carico;
- evita dipendenze da
net-tools.
Se il numero supera:
SOGLIA_close-wait=300
viene eseguito un reload.
Logging e monitoraggio
Lo script utilizza:
logger -t apache_health_watchdog
Quindi gli eventi sono consultabili tramite:
journalctl -t apache_health_watchdog
Esempio:
May 18 10:42:01 server apache_health_watchdog: Allarme: Rilevato leak di socket (182 connessioni in close-wait). Eseguo reload.
Per seguire i log in tempo reale:
journalctl -f -t apache_health_watchdog
Quando usare questo approccio
Questo watchdog è particolarmente utile quando:
- Apache funge da reverse proxy;
- i backend possono bloccarsi o degradare;
- non è disponibile un orchestratore avanzato;
- si vuole una soluzione semplice e immediata;
- si desidera un meccanismo di self-healing leggero.
Limiti della soluzione
Questo approccio non sostituisce:
- un monitoraggio completo;
- metriche Prometheus/Grafana;
- tracing applicativo;
- analisi root cause;
- tuning corretto di Apache e backend.
Il watchdog serve principalmente come:
- mitigazione automatica;
- protezione operativa;
- recovery rapido.
Top comments (0)