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épertoire pg_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 partition pg_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.


DALIBO

DALIBO est le spécialiste français de PostgreSQL®. Nous proposons du support, de la formation et du conseil depuis 2005.