Brive-la-Gaillarde, le 3 septembre 2025
Il est régulièrement recommandé de mettre le répertoire pg_wal
de PostgreSQL sur
une partition dédiée, mais quelles en sont les motivations ?
Pourquoi ?
Le répertoire pg_wal
contient les journaux de transactions de l’instance,
appelés WAL (Write-Ahead-Log).
Ces journaux sont écrits avant d’appliquer les changements sur les données,
afin de garantir la durabilité des transactions et de permettre la récupération
en cas de problème.
Plusieurs avantages motivent la séparation du répertoire pg_wal
sur une partition
ou un disque distinct :
-
Meilleure organisation et maintenance : avoir son
pg_wal
sur un volume distinct facilite la gestion et évite les erreurs de manipulation. Par exemple, on réduit le risque de supprimer accidentellement les WAL lors d’interventions sur la partition principale de données. Il est également plus simple de superviser séparément l’espace occupé par les données et par les journaux de transactions. -
Performances I/O améliorées : les écritures de WAL sont essentiellement séquentielles, et un disque réservé à ces journaux permet de lisser les I/O sans interférer avec les lectures/écritures aléatoires des fichiers de données. N’espérez cependant pas de gros gains de performances avec du matériel récent (SSD, NVMe…).
-
Isolation des risques de saturation : séparer
pg_wal
sur une partition dédiée limite l’impact d’une éventuelle saturation. Si la partition principale contenant les données se remplit complètement, les nouvelles écritures de données deviennent impossibles (erreurs « No space left on device »), mais le serveur PostgreSQL lui-même ne s’arrêtera pas tant que les WAL sont encore accessibles en écriture. Inversement, si c’est le répertoirepg_wal
qui arrive à saturation, PostgreSQL ne peut plus effectuer aucune écriture. Il stoppe alors immédiatement le serveur et refuse de redémarrer tant que le problème n’est pas résolu. Il reste toujours possible de remplir le répertoire des WAL en cas de problème (ex: archiveur défaillant, réplication en retard, etc… – voir plus loin). L’avantage est que ces situations n’impacteront que la partitionpg_wal
et seront plus facilement identifiables et traitables sans compromettre le reste des données.
À noter : avoir une partition dédiée pour les logs est également une bonne pratique.
Comment ?
Il faudra tout d’abord faire la demande auprès de votre administrateur système, voici les informations nécessaires à fournir afin d’éviter toute ambiguïté :
- Stockage SSD de préférence, si possible différent de celui contenant le répertoire data, afin de profiter au maximum de la parallélisation des I/O.
- Formatage ext4 ou XFS.
Et enfin faire le montage et donner les permissions à l’utilisateur postgres sur
le répertoire, par exemple ici /var/lib/postgresql/pg_wal/17/main/wal
.
La mise en place d’une partition séparée pour pg_wal
peut se faire de deux manières :
Dès l’initialisation de l’instance, vous pouvez spécifier un emplacement différent
pour les WAL. Par exemple, la commande d’initialisation suivante crée l’instance tout
en plaçant pg_wal
à l’emplacement désiré :
$ sudo -iu postgres /usr/lib/postgresql/17/bin/initdb \
--pgdata=/var/lib/postgresql/pgdata \
--waldir=/var/lib/postgresql/pg_wal/17/main/wal
PostgreSQL écrira alors ses journaux de transactions dans ce répertoire dédié.
Il est également possible de déplacer le pg_wal
d’une instance déjà en service, mais
cela nécessite une brève interruption. La procédure générale est :
Arrêt de l’instance
# Vérification du pg_wal
$ ls /var/lib/postgresql/17/main/pg_wal/
000000010000000000000003 000000010000000000000004 000000010000000000000005 archive_status summaries
# Arrêt de l'instance
$ sudo systemctl stop postgresql
# Vérification du bon arrêt de l'instance
$ ps -u postgres -f f
UID PID PPID C STIME TTY STAT TIME CMD
Préparation du nouveau répertoire
# Création du répertoire
$ sudo mkdir -p /var/lib/postgresql/pg_wal
# Montage du répertoire pg_wal sur la partition dédiée
$ sudo mount /dev/sdc /var/lib/postgresql/pg_wal
# Création du sous répertoire afin d'éviter de mettre les WAL à la racine du point de montage
$ sudo mkdir -p /var/lib/postgresql/pg_wal/17/main/wal
Déplacement de l’intégralité du répertoire pg_wal
vers la nouvelle partition
# Copie du contenu du pg_wal vers notre pg_wal
$ sudo rsync -av /var/lib/postgresql/17/main/pg_wal/ /var/lib/postgresql/pg_wal/17/main/wal/
sending incremental file list
./
000000010000000000000003
000000010000000000000004
000000010000000000000005
archive_status/
summaries/
sent 50,344,304 bytes received 88 bytes 100,688,784.00 bytes/sec
total size is 50,331,648 speedup is 1.00
# Vérification que les WAL sont tous présents
$ sudo ls -la /var/lib/postgresql/pg_wal/17/main/wal/
total 49156
drwx------ 4 postgres postgres 141 Aug 27 05:33 .
drwxr-xr-x 5 postgres postgres 4096 Aug 27 05:31 ..
-rw------- 1 postgres postgres 16777216 Aug 27 05:45 000000010000000000000003
-rw------- 1 postgres postgres 16777216 Aug 27 05:33 000000010000000000000004
-rw------- 1 postgres postgres 16777216 Aug 27 05:33 000000010000000000000005
drwx------ 2 postgres postgres 6 Aug 26 04:47 archive_status
drwx------ 2 postgres postgres 6 Aug 26 04:47 summaries
# Renommage du répertoire pg_wal
$ sudo mv /var/lib/postgresql/17/main/pg_wal /var/lib/postgresql/17/main/pg_wal_old
Création du lien symbolique et ajout des permissions
# Création du lien symbolique reliant pg_wal vers notre pg_wal
$ sudo ln -s /var/lib/postgresql/pg_wal/17/main/wal /var/lib/postgresql/17/main/pg_wal
# Vérification dans le pgdata que le lien symbolique a bien été créé
$ ls -l /var/lib/postgresql/17/main/ | grep pg_wal
lrwxrwxrwx 1 root root 25 Aug 27 05:54 pg_wal -> /var/lib/postgresql/pg_wal/17/main/wal
# Ajout des droits à l'utilisateur postgres sur le répertoire pg_wal
$ sudo chown -R postgres:postgres /var/lib/postgresql/pg_wal/17/main/wal
$ sudo chown -h postgres:postgres /var/lib/postgresql/17/main/pg_wal
Redémarrage de l’instance
# Redémarrage de l'instance
$ sudo systemctl start postgresql
# Vérification que les nouveaux WAL sont créés au bon endroit
$ ls -l /var/lib/postgresql/pg_wal/17/main/wal/
total 360448
-rw------- 1 postgres postgres 16777216 Aug 27 05:58 000000010000000000000003
-rw------- 1 postgres postgres 16777216 Aug 27 05:58 000000010000000000000004
-rw------- 1 postgres postgres 16777216 Aug 27 05:59 000000010000000000000005
-rw------- 1 postgres postgres 16777216 Aug 27 05:59 000000010000000000000006
-rw------- 1 postgres postgres 16777216 Aug 27 05:59 000000010000000000000007
drwx------ 2 postgres postgres 6 Aug 26 04:47 archive_status
drwx------ 2 postgres postgres 6 Aug 26 04:47 summaries
# Suppression de pg_wal_old une fois le bon fonctionnement validé
$ sudo rm -rf /var/lib/postgresql/17/main/pg_wal_old
À noter : certains outils de sauvegarde ou de réplication pourraient ne pas
conserver le lien symbolique. Par exemple, un pg_basebackup
sur le primaire ne
recréera pas automatiquement le lien symbolique sur un secondaire, à moins d’utiliser
l’option --waldir
lors de la sauvegarde.
Et si c’est trop tard ?
Que faire si votre instance se retrouve avec le pg_wal
saturé (ou sur le point de
l’être) ? Voici deux approches envisageables pour réagir en urgence :
-
Ajouter de l’espace disque : la solution la plus simple et sûre est d’augmenter la taille de la partition qui héberge actuellement
pg_wal
. Si votre système de fichiers ou votre environnement le permet, étendez la partition saturée pour redonner de la marge à PostgreSQL. Le serveur pourra ainsi redémarrer normalement une fois qu’il dispose à nouveau d’espace libre, donnant le temps de traiter la cause et minimisant ainsi la coupure de production. Cette option évite de toucher aux fichiers internes, mais n’est pas toujours possible selon le contexte (partition non extensible, pas de stockage additionnel disponible immédiatement, etc…). -
Déplacer le
pg_wal
: si vous ne pouvez pas agrandir l’espace disque existant, il faut alors déplacer les WAL vers un emplacement plus spacieux. La démarche est similaire à celle décrite plus haut :
# Arrêt de l'instance
$ sudo systemctl stop postgresql
# Création du répertoire
$ sudo mkdir -p /var/lib/postgresql/pg_wal
# Montage du répertoire pg_wal sur la partition dédiée
$ sudo mount /dev/sdc /var/lib/postgresql/pg_wal
# Création du sous répertoire
$ sudo mkdir -p /var/lib/postgresql/pg_wal/17/main/wal
# Copie du contenu du pg_wal vers notre pg_wal
$ sudo rsync -av /var/lib/postgresql/17/main/pg_wal/ /var/lib/postgresql/pg_wal/17/main/wal/
# Renommage du répertoire pg_wal
$ sudo mv /var/lib/postgresql/17/main/pg_wal /var/lib/postgresql/17/main/pg_wal_old
# Création du lien symbolique reliant pg_wal vers notre pg_wal
$ sudo ln -s /var/lib/postgresql/pg_wal/17/main/wal /var/lib/postgresql/17/main/pg_wal
# Ajout des droits à l'utilisateur postgres sur le répertoire pg_wal
$ sudo chown -R postgres:postgres /var/lib/postgresql/pg_wal/17/main/wal
$ sudo chown -h postgres:postgres /var/lib/postgresql/17/main/pg_wal
# Redémarrage de l'instance
$ sudo systemctl start postgresql
# Suppression de l'ancien répertoire
$ sudo rm -rf /var/lib/postgresql/17/main/pg_wal_old
Cette manipulation permet de relancer rapidement le service afin de traiter le problème ensuite. Veillez à ne pas perdre de WAL en route, sous peine de compromettre la capacité de récupération. N’oubliez pas dans tous les cas de corriger la cause de fond de la saturation (reprise d’un archivage interrompu, nettoyage des slots de réplication obsolètes, etc…). Il est préférable de se préparer en amont afin d’éviter le recours à ce genre de solutions exécutées en urgence et sous pression.
Exemples rencontrés au support
Enfin, voici quelques cas réels, observés au support, car ça n’arrive pas qu’aux autres :
- Un ordre “CREATE TABLE AS” qui a généré 330 Go de WAL. L’instance a subi quatre interruptions sur la journée.
- Espace insuffisant pour VACUUM FULL, il faut normalement prévoir le double d’espace pris par la table concernée. Le VACUUM FULL a saturé l’espace disque, arrêtant net l’instance sans possibilité de la remettre en marche avant l’ajout d’espace disque par l’administrateur système. La recherche et la suppression des “fichiers orphelins” générés par l’arrêt brutal du VACUUM FULL sont chronophages et risquées.
- Processus
archiver
en erreur suite à une différence de version pgbackrest. Une mise à jour avait été effectuée sur le primaire, mais pas sur le serveur d’archivage, aboutissant à une accumulation de 100 Go de WAL. - Suite à un VACUUM FREEZE non effectué après une grosse restauration, l’autovacuum a fini par geler de force un grand nombre de lignes, ralentissant le système, ce qui a généré un total de 600 Go de WAL.
- Un archivage qui a décroché suite à un retard impossible à rattraper, générant
200 Go de WAL par heure. En dernier recours, arrêt de l’archivage en passant le
paramètre
archive_command
à/bin/true
alors qu’il restait 5 Go d’espace disque. Cette manipulation entraîne obligatoirement la reconstruction du secondaire.
Les exemples sont nombreux, les causes diverses : de l’erreur de manipulation au VACUUM qui rattrape un retard, en passant par le serveur d’archivage injoignable.
A retenir
Placer le répertoire pg_wal
sur une partition dédiée est une bonne pratique pour la
plupart des installations : cela améliore la résilience et peut apporter un gain de
performance dans certains cas. Il convient toutefois de dimensionner
correctement toutes les partitions (données, WAL, et logs), de surveiller leur taux
d’occupation (supervision), et d’anticiper les opérations lourdes. La séparation
du pg_wal
évite bien des scénarios catastrophiques où PostgreSQL s’arrête
pour protéger l’intégrité des données. Avec une bonne architecture de stockage
et une supervision proactive, on se donne toutes les chances d’éviter ces interruptions
de service liées à l’espace disque.
- PostgreSQL (445) ,
- Dalibo (185) ,
- 2025 (9) ,
- stockage (4) ,
- emplacement (2) ,
- pg_wal (1) ,
- planetpgfr (38)