
Je suis Mathieu Ponton, Co-Founder & ingénieur logiciel chez Apogée Consult à Lyon. Ingénieur diplômé de Polytech Lyon (Informatique), j'ai fait trois ans en apprentissage, partagés entre la Métropole de Lyon (inclusion numérique avec Res'in et sobriété énergétique avec Écolyo) et Superwyze, une startup medtech (POCs, dont certains aujourd'hui industrialisés, et travail sur des codebases existantes). J'ai livré plus de 10 projets en production (web, mobile et IA / RAG) pour des PME, startups et organisations publiques.
Postgres en production: les backups dont on dépend vraiment quand ça casse
- devops
pgdump quotidien, c'est insuffisant. On explique pourquoi et comment on configure pgBackRest avec WAL archiving pour tenir un RPO de 5 minutes sur nos bases de production.
Postgres en production: les backups dont on dépend vraiment quand ça casse
Un client nous appelle un lundi matin : sa base Postgres est corrompue, le serveur ne redémarre pas. Son backup ? Un pg_dump qui tourne chaque nuit à 2h. Il est 10h30. Huit heures et demie de données perdues, soit environ 4 000 commandes.
Ce scénario n'est pas exceptionnel. C'est le point de départ qui nous a forcés à repenser notre stratégie de backup de manière sérieuse.
Ce que pg_dump ne fait pas
pg_dump produit un snapshot cohérent de la base à un instant T. C'est utile pour les migrations, les dumps de dev, les exports ponctuels. En production, il présente deux limites structurelles.
La première : le RPO (Recovery Point Objective) est au mieux égal à l'intervalle entre deux dumps. Si on dump à 2h et que la panne arrive à 10h, on perd 8h. Impossible de récupérer les données intermédiaires.
La seconde : la restauration est lente. Sur une base de 50 Go, pg_restore prend facilement 30 à 90 minutes selon le hardware. Pendant ce temps, le service est indisponible.
Pour un projet sérieux, ces deux caractéristiques sont incompatibles avec un SLA raisonnable.
WAL archiving : le fondement d'un backup continu
Postgres écrit chaque modification dans ses Write-Ahead Logs (WAL) avant de l'appliquer aux fichiers de données. Ces fichiers WAL sont la source de vérité de toutes les transactions.
Le WAL archiving consiste à copier ces fichiers en continu vers un stockage externe. Combiné à un backup de base (base backup), cela permet de rejouer l'historique des transactions jusqu'à n'importe quel point dans le temps : c'est le Point-in-Time Recovery (PITR).
Configuration minimale dans postgresql.conf :
wal_level = replica
archive_mode = on
archive_command = 'pgbackrest --stanza=main archive-push %p'
archive_timeout = 60archive_timeout = 60 force l'archivage d'un segment WAL toutes les 60 secondes même s'il n'est pas plein. Cela garantit un RPO maximal de ~1 minute sur une base peu active.
pgBackRest : pourquoi on l'a choisi
Il existe plusieurs outils : pgBarman, WAL-E (déprécié), pgBackRest. On a retenu pgBackRest pour plusieurs raisons concrètes.
Il gère nativement la compression (lz4, zstd, gzip), le chiffrement (AES-256-CBC), et la rétention par politique. Il supporte les backups différentiels et incrémentaux, ce qui réduit le volume transféré à chaque cycle. Il peut pousser vers S3, GCS, Azure Blob, ou un simple serveur SSH.
Son principal avantage opérationnel : la restauration est parallélisée. Sur une base de 100 Go, on descend à 8-12 minutes de restauration complète avec 4 processus parallèles, là où pg_restore prenait 70 minutes.
Configuration pgBackRest : exemple de setup
Fichier /etc/pgbackrest/pgbackrest.conf sur le serveur Postgres :
[global]
repo1-type=s3
repo1-path=/pgbackrest/main
repo1-s3-bucket=my-pg-backups
repo1-s3-endpoint=s3.eu-west-3.amazonaws.com
repo1-s3-region=eu-west-3
repo1-s3-key=AKIAIOSFODNN7EXAMPLE
repo1-s3-key-secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=strongpassphrase
repo1-retention-full=4
repo1-retention-diff=14
compress-type=lz4
compress-level=6
process-max=4
log-level-console=info
log-level-file=detail
[main]
pg1-path=/var/lib/postgresql/16/mainOn conserve 4 full backups (un par semaine) et 14 différentiels. Le WAL est archivé en continu. Cela nous donne un RPO inférieur à 5 minutes avec une rétention de 28 jours.
Initialisation du stanza :
pgbackrest --stanza=main --log-level-console=info stanza-createCycle de backup
On utilise trois types de backups avec des fréquences différentes :
# Full backup, chaque dimanche à 1h
0 1 * * 0 postgres pgbackrest --stanza=main backup --type=full
# Différentiel, du lundi au samedi à 1h
0 1 * * 1-6 postgres pgbackrest --stanza=main backup --type=diff
# Vérification de l'archivage WAL, toutes les heures
0 * * * * postgres pgbackrest --stanza=main checkLa commande check valide que l'archivage fonctionne bien. Elle échoue si le dernier WAL archivé est trop ancien, ce qui déclenche une alerte.
Point-in-Time Recovery : procédure réelle
Scénario : une migration erronée a supprimé des lignes à 14h37. On veut restaurer l'état de la base à 14h36.
# Arrêter Postgres
systemctl stop postgresql
# Restaurer jusqu'au timestamp souhaité
pgbackrest --stanza=main --delta \
--type=time "--target=2026-03-22 14:36:00" \
--target-action=promote \
restore
# Redémarrer
systemctl start postgresqlL'option --delta ne restaure que les fichiers modifiés depuis le backup de base, ce qui accélère significativement le processus.
Le flag --target-action=promote fait passer la base en mode primaire une fois la cible atteinte, au lieu d'attendre une commande manuelle.
Ce qu'on vérifie régulièrement
Un backup non testé n'est pas un backup. On automatise deux vérifications.
La première : pgbackrest --stanza=main info chaque nuit. Elle retourne l'état du stanza, la date du dernier backup, et la taille. Une alerte part si le dernier backup date de plus de 25 heures.
La seconde : une restauration de test mensuelle sur un serveur éphémère. On restaure le dernier full backup, on lance quelques requêtes de validation, on détruit l'instance. Cette procédure prend 20 minutes et évite les mauvaises surprises le jour J.
Les pièges qu'on a rencontrés
L'espace WAL qui s'accumule. Si archive_command échoue (bucket S3 inaccessible, quota dépassé), Postgres conserve les WAL localement. Sur une base active, cela peut remplir le disque en quelques heures. On surveille l'espace de pg_wal/ séparément.
Le chiffrement oublié. Les WAL contiennent des données brutes, y compris des champs sensibles. Sans chiffrement, le bucket S3 est un vecteur d'exposition. pgBackRest chiffre côté client avant transfert.
La rétention WAL incohérente. pgBackRest nettoie les WAL archivés selon la politique de rétention des backups. Mais si on supprime manuellement des backups dans S3 sans passer par l'outil, la rétention WAL devient incohérente et le PITR peut échouer sur la plage concernée.
Limites de cette approche
pgBackRest est excellent, mais il ne remplace pas une réflexion sur le RTO (Recovery Time Objective). Même avec 8 minutes de restauration, il faut réintégrer les connexions applicatives, vérifier l'état des séquences, éventuellement rejouer des traitements métier.
La question qui reste ouverte : à quel moment bascule-t-on vers une architecture avec réplication synchrone et failover automatique (Patroni, pg_auto_failover) plutôt que de s'appuyer uniquement sur la restauration ? Le PITR répond à la corruption et aux erreurs humaines, pas à la panne hardware. Les deux stratégies sont complémentaires, pas interchangeables.