Diagnostiquer un incident en production
AvancéQuand la base « ne répond plus », on procède dans l'ordre : est-elle saturée, bloquée, ou sans espace ?
1. Connexions saturées#
SELECT state, count(*) FROM pg_stat_activity GROUP BY state;
Beaucoup de active : requêtes lentes ou CPU saturé. Beaucoup d'idle in transaction : l'application garde des transactions ouvertes (fuite, appel externe dans une transaction).
2. Verrous : qui bloque qui ?#
SELECT blocked.pid AS bloque,
blocking.pid AS bloquant,
left(blocked.query, 50) AS requete_bloquee,
left(blocking.query, 50) AS requete_bloquante,
now() - blocking.xact_start AS depuis
FROM pg_stat_activity blocked
JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS b(pid) ON true
JOIN pg_stat_activity blocking ON blocking.pid = b.pid;
Une migration ou une transaction oubliée tient un verrou : pg_cancel_backend(pid) d'abord, pg_terminate_backend(pid) si nécessaire.
3. Disque plein#
- Causes fréquentes : WAL qui s'accumule (slot de réplication abandonné, archivage en échec), table ou index gonflé, journaux, fichiers temporaires d'un gros tri.
- Vérifiez les slots :
SELECT slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) FROM pg_replication_slots;
4. Retard de réplication et lectures obsolètes#
Comparez le retard (pg_stat_replication sur le primaire) et cherchez une transaction longue ou une requête de reporting sur la réplique qui retarde le rejeu.
5. Après l'incident#
- Post-mortem sans reproche : chronologie, cause racine, ce qui a bien marché, actions (avec responsable et échéance).
- Transformer chaque détection tardive en alerte ; chaque geste manuel en runbook ou en automatisation.
Astuce : en cas de doute pendant un incident, ne modifiez pas plusieurs choses à la fois : vous ne saurez plus ce qui a corrigé (ou aggravé) la situation. Notez chaque action et son heure.