Tools: Watchdog Apache con Bash, Cron e Systemd: monitoraggio automatico di memoria, PID e socket close-wait - 2025 Update

Tools: Watchdog Apache con Bash, Cron e Systemd: monitoraggio automatico di memoria, PID e socket close-wait - 2025 Update

Obiettivo dello script

Script completo

Installazione

Configurazione del cron

Perché usare flock

Analisi delle metriche monitorate

1. RAM disponibile

2. Saturazione PID Apache

3. Socket close-wait

Logging e monitoraggio

Quando usare questo approccio

Limiti della soluzione 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: Questo approccio è particolarmente utile in ambienti: In base alle soglie configurate: Salvare lo script in: Rendere il file eseguibile: Aggiungere in /etc/crontab: Questo esegue il controllo ogni 2 minuti. flock evita esecuzioni concorrenti dello script. In condizioni di degrado del sistema: solo una istanza dello script può essere eseguita alla volta. che corrisponde alla colonna available. Se la memoria disponibile scende sotto: viene eseguito un restart completo di Apache. Questo è utile perché: Lo script legge direttamente i contatori cgroup di systemd: Questo approccio è molto più affidabile rispetto al parsing di ps. Se il servizio supera: viene eseguito un reload. Lo stato close-wait indica: Molte connessioni in close-wait possono indicare: Questo approccio è preferibile rispetto a netstat perché: viene eseguito un reload. Quindi gli eventi sono consultabili tramite: Per seguire i log in tempo reale: Questo watchdog è particolarmente utile quando: Questo approccio non sostituisce: Il watchdog serve principalmente come: Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to ? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

#!/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.-weight: 500;">service/pids.current" MAX_FILE="/sys/fs/cgroup/system.slice/apache2.-weight: 500;">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="-weight: 500;">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/-weight: 500;">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="-weight: 500;">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/-weight: 500;">systemctl reload apache2 # Se il reload fallisce (es. kernel già in fork rejected), prova il -weight: 500;">restart if [ $? -ne 0 ]; then /usr/bin/logger -t apache_health_watchdog "Reload fallito, forzo -weight: 500;">restart." /usr/bin/-weight: 500;">systemctl -weight: 500;">restart apache2 fi else /usr/bin/-weight: 500;">systemctl -weight: 500;">restart apache2 fi fi #!/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.-weight: 500;">service/pids.current" MAX_FILE="/sys/fs/cgroup/system.slice/apache2.-weight: 500;">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="-weight: 500;">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/-weight: 500;">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="-weight: 500;">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/-weight: 500;">systemctl reload apache2 # Se il reload fallisce (es. kernel già in fork rejected), prova il -weight: 500;">restart if [ $? -ne 0 ]; then /usr/bin/logger -t apache_health_watchdog "Reload fallito, forzo -weight: 500;">restart." /usr/bin/-weight: 500;">systemctl -weight: 500;">restart apache2 fi else /usr/bin/-weight: 500;">systemctl -weight: 500;">restart apache2 fi fi #!/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.-weight: 500;">service/pids.current" MAX_FILE="/sys/fs/cgroup/system.slice/apache2.-weight: 500;">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="-weight: 500;">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/-weight: 500;">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="-weight: 500;">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/-weight: 500;">systemctl reload apache2 # Se il reload fallisce (es. kernel già in fork rejected), prova il -weight: 500;">restart if [ $? -ne 0 ]; then /usr/bin/logger -t apache_health_watchdog "Reload fallito, forzo -weight: 500;">restart." /usr/bin/-weight: 500;">systemctl -weight: 500;">restart apache2 fi else /usr/bin/-weight: 500;">systemctl -weight: 500;">restart apache2 fi fi /usr/local/sbin/check_system_health.sh /usr/local/sbin/check_system_health.sh /usr/local/sbin/check_system_health.sh chmod +x /usr/local/sbin/check_system_health.sh chmod +x /usr/local/sbin/check_system_health.sh chmod +x /usr/local/sbin/check_system_health.sh /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 */2 * * * * root flock -n /tmp/apache_watchdog.lock /usr/local/sbin/check_system_health.sh >> /var/log/apache_health_watchdog.log 2>&1 */2 * * * * root flock -n /tmp/apache_watchdog.lock /usr/local/sbin/check_system_health.sh >> /var/log/apache_health_watchdog.log 2>&1 flock -n /tmp/apache_watchdog.lock flock -n /tmp/apache_watchdog.lock flock -n /tmp/apache_watchdog.lock free -m awk '{print $7}' awk '{print $7}' awk '{print $7}' SOGLIA_RAM_FREE_MB=100 SOGLIA_RAM_FREE_MB=100 SOGLIA_RAM_FREE_MB=100 /sys/fs/cgroup/system.slice/apache2.-weight: 500;">service/pids.current /sys/fs/cgroup/system.slice/apache2.-weight: 500;">service/pids.current /sys/fs/cgroup/system.slice/apache2.-weight: 500;">service/pids.current /sys/fs/cgroup/system.slice/apache2.-weight: 500;">service/pids.max /sys/fs/cgroup/system.slice/apache2.-weight: 500;">service/pids.max /sys/fs/cgroup/system.slice/apache2.-weight: 500;">service/pids.max SOGLIA_PIDS_PERCENT=60 SOGLIA_PIDS_PERCENT=60 SOGLIA_PIDS_PERCENT=60 ss -tanp state close-wait ss -tanp state close-wait ss -tanp state close-wait SOGLIA_close-wait=300 SOGLIA_close-wait=300 SOGLIA_close-wait=300 logger -t apache_health_watchdog logger -t apache_health_watchdog logger -t apache_health_watchdog journalctl -t apache_health_watchdog journalctl -t apache_health_watchdog journalctl -t apache_health_watchdog May 18 10:42:01 server apache_health_watchdog: Allarme: Rilevato leak di socket (182 connessioni in close-wait). Eseguo reload. May 18 10:42:01 server apache_health_watchdog: Allarme: Rilevato leak di socket (182 connessioni in close-wait). Eseguo reload. May 18 10:42:01 server apache_health_watchdog: Allarme: Rilevato leak di socket (182 connessioni in close-wait). Eseguo reload. journalctl -f -t apache_health_watchdog journalctl -f -t apache_health_watchdog journalctl -f -t apache_health_watchdog - monitora periodicamente lo stato del sistema; - verifica alcune metriche critiche; - esegue automaticamente un reload o un -weight: 500;">restart di Apache; - registra gli eventi tramite syslog e journalctl. - con reverse proxy Apache; - con backend applicativi instabili; - con leak di connessioni; - dove è necessario un meccanismo di self-healing semplice e trasparente. - RAM disponibile; - numero di PID usati dal servizio Apache; - connessioni TCP in stato close-wait verso un backend specifico; - health check HTTP locale; - esegue un reload di Apache; - oppure un -weight: 500;">restart completo; - scrive i dettagli nel journal di systemd. - un controllo potrebbe impiegare più tempo del previsto; - il cron successivo potrebbe partire mentre il precedente è ancora attivo; - si rischiano reload o -weight: 500;">restart multipli contemporanei. - il reload può richiedere fork aggiuntivi; - in condizioni di memoria critica il reload potrebbe peggiorare la situazione; - un -weight: 500;">restart libera immediatamente worker e memoria frammentata. - rigenerare worker; - liberare processi stuck; - evitare il raggiungimento del limite massimo PID. - il peer remoto ha chiuso la connessione; - il processo locale non ha ancora rilasciato il socket. - leak applicativi; - backend instabili; - worker Apache bloccati; - timeout mal configurati. - ss è più moderno; - usa meno CPU; - legge direttamente dal kernel tramite netlink; - è più affidabile sotto alto carico; - evita dipendenze da net-tools. - 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. - un monitoraggio completo; - metriche Prometheus/Grafana; - tracing applicativo; - analisi root cause; - tuning corretto di Apache e backend. - mitigazione automatica; - protezione operativa; - recovery rapido.