PostgreSQL Sauvegardes et Réplication

Formation DBA3

Dalibo SCOP

26.09

10 septembre 2026

Sur ce document

Formation Formation DBA3
Titre PostgreSQL Sauvegardes et Réplication
Révision 26.09
ISBN N/A
PDF https://dali.bo/dba3_pdf
EPUB https://dali.bo/dba3_epub
HTML https://dali.bo/dba3_html
Slides https://dali.bo/dba3_slides

Licence Creative Commons CC-BY-NC-SA

Cette formation est sous licence CC-BY-NC-SA. Vous êtes libre de la redistribuer et/ou modifier aux conditions suivantes :

  • Paternité
  • Pas d’utilisation commerciale (y compris IA)
  • Partage des conditions initiales à l’identique

Marques déposées

PostgreSQL® Postgres® et le logo Slonik sont des marques déposées par PostgreSQL Community Association of Canada.

Versions de PostgreSQL couvertes

Ce document ne couvre que les versions supportées de PostgreSQL au moment de sa rédaction, soit les versions 14 à 18.

PostgreSQL : Politique de sauvegarde

Introduction

  • Le pire peut arriver
  • Politique de sauvegarde

Au menu

  • Objectifs
  • Approche
  • Points d’attention

Définir une politique de sauvegarde

  • Pourquoi établir une politique ?
  • Que sauvegarder ?
  • À quelle fréquence sauvegarder les données ?
  • Quels supports ?
  • Quels outils ?
  • Vérifier la restauration des sauvegardes

Objectifs

  • Sécuriser les données
  • Mettre à jour le moteur de données
  • Dupliquer une base de données de production
  • Archiver les données

Différentes approches

  • Sauvegarde à chaud en SQL (ou logique)
  • Sauvegarde physique des fichiers à froid
  • Sauvegarde à chaud des fichiers + journaux
    • niveau baie
    • pg_basebackup
  • Sauvegarde physique & PITR

RTO/RPO

La politique de sauvegarde découle du :

  • RPO (Recovery Point Objective) : Perte de Données Maximale Admissible
    • faible ou importante ?
  • RTO (Recovery Time Objective) : Durée Maximale d’Interruption Admissible
    • courte ou longue ?

Industrialisation

  • Évaluer les coûts humains et matériels
  • Intégrer les méthodes de sauvegardes avec le reste du SI
    • sauvegarde sur bande centrale
    • supervision
    • plan de continuité et de reprise d’activité

Documentation

  • Documenter les éléments clés de la politique :
    • perte de données
    • rétention
    • durée de restauration
  • Documenter les processus de sauvegarde et restauration
  • Imposer des révisions régulières des procédures

Règles 3-2-1 et 3-2-1-1-0

  • 3 exemplaires des données
  • 2 sur différents médias
  • 1 hors site
  • 1 stockage immuable (hors ligne ?)
  • 0 sauvegarde non testée
  • RAID & réplication ne sont pas des sauvegardes !
  • Le cloud n’est pas une solution magique !
    • perte de datacenters
    • ransomwares

Fichiers de configuration

  • Sauvegarder les fichiers de configuration
  • Et vos scripts
    • paramétrage
    • sauvegarde
    • maintenance

Tester la restauration

  • De nombreuses catastrophes auraient pu être évitées avec un test
  • Validation de la procédure
  • Estimation de la durée

Conclusion

  • Les techniques de sauvegarde de PostgreSQL sont :
    • complémentaires
    • automatisables
  • La maîtrise de ces techniques est indispensable pour assurer un service fiable.
  • Testez vos sauvegardes !

Quiz

Sauvegarde physique à chaud et PITR

Introduction

  • Sauvegarde traditionnelle
    • sauvegarde pg_dump à chaud
    • sauvegarde des fichiers à froid
  • Insuffisant pour les grosses bases
    • long à sauvegarder
    • encore plus long à restaurer
  • Perte de données potentiellement importante
    • car impossible de réaliser fréquemment une sauvegarde
  • Une solution : la sauvegarde PITR

Au menu

  • Rappel sur la journalisation
  • Principe de la sauvegarde PITR
  • Mise en place
    • sauvegarde : manuelle, ou avec pg_basebackup
    • archivage : manuel, ou avec pg_receivewal
  • Restaurer une sauvegarde PITR
  • Archivage & compression
  • Des outils

Rappel sur la journalisation

Journaux de transaction

  • Write Ahead Logs (WAL)
  • Chaque donnée est écrite 2 fois sur le disque !
  • Avantages :
    • sécurité infaillible (après COMMIT), intégrité, durabilité
    • écriture séquentielle rapide, et un seul sync sur le WAL
    • fichiers de données écrits en asynchrone
    • sauvegarde PITR et réplication fiables

PITR

  • Point In Time Recovery
  • À chaud
  • En continu
  • Cohérente

Sauvegarde physique

Image de la base au niveau des fichiers

Principe du PITR

Archiver tous les journaux et le base backup

Restauration PITR

  • Les journaux de transactions contiennent toutes les modifications
  • Il faut les archiver
    • …et avoir une image des fichiers à un instant t (base backup)
  • La restauration se fait en restaurant cette image
    • puis en rejouant les journaux
    • dans l’ordre
    • sans trou
    • entièrement
    • au moins jusqu’au point de cohérence
    • toute l’activité de la base
    • tous… ou jusqu’au moment voulu

Avantages du PITR

  • Sauvegarde à chaud
  • Choix du moment d’arrêt du rejeu
  • Moins de perte de données
  • Grandes bases : plus réaliste que pg_dump

Inconvénients du PITR

  • Sauvegarde/restauration de l’instance complète
  • Impossible de changer d’architecture (même OS conseillé)
  • Nécessite un grand espace de stockage (données + journaux)
  • Interdiction de perdre un journal
  • Risque d’accumulation des journaux
    • dans pg_wal/ si échec d’archivage… et arrêt si plein !
    • dans le dépôt d’archivage si échec des sauvegardes
  • Plus complexe

Copie physique à chaud ponctuelle avec pg_basebackup

(Non PITR)

Introduction à pg_basebackup

  • Simple & efficace
  • Fourni avec PostgreSQL
  • Réalise les 2 étapes d’une sauvegarde
    • « base backup »
    • journaux nécessaires (mais pas plus)
    • fichiers ou archives
  • Pas de reprise si échec
  • Pas de PITR
    • peut servir de base
  • Configuration : streaming (rôle, droits, slots)
$ pg_basebackup --format=tar --wal-method=stream \
 --checkpoint=fast --progress -h 127.0.0.1 -U sauve \
 -D /var/lib/postgresql/backups/
  • Restauration : décompresser/copier la sauvegarde

Archivage des journaux & archiver

Rappel des étapes d’une sauvegarde PITR

  • D’abord :
    • archivage des journaux de transactions
  • Puis : sauvegarde des fichiers
    • pg_basebackup
    • ou manuellement (outils de copie classiques)

Méthodes d’archivage

Deux méthodes :

  • Généralement :
    • processus interne archiver
  • Alternative :
    • pg_receivewal (flux de réplication)

Choix du répertoire d’archivage

  • À faire quelle que soit la méthode d’archivage
  • Attention aux droits d’écriture dans le répertoire
    • la commande configurée pour la copie doit pouvoir écrire dedans
    • et potentiellement y lire

Processus archiver : configuration (1/4)

Préalables :

  • Dans postgresql.conf :
    • wal_level = replica
    • archive_mode = on (ou always)

Processus archiver : configuration (2/4)

La commande d’archivage :

  • Dans postgresql.conf :
    • archive_command = '… une commande …'
    • ou : archive_library = '… une bibliothèque …' (v15+)

Processus archiver : configuration (3/4)

  • Exemples d’archive_command :
archive_command='cp %p /mnt/nfs1/archivage/%f && sync /mnt/nfs1/'
archive_command='test ! -f /arch/%f && cp %p /arch/%f'
archive_command='/usr/bin/rsync -az %p postgres@10.9.8.7:/archives/%f'
archive_command='/opt/mon_script.sh %p %f'
archive_command='/usr/bin/pgbackrest --stanza=prod archive-push %p'
archive_command='/usr/bin/barman-wal-archive backup prod %p'
archive_command='/bin/true'  # désactivation
  • Ne pas oublier de forcer l’écriture de l’archive sur disque
  • Code retour de l’archivage entre 0 (ok) et 125

Processus archiver : configuration (4/4)

  • Dans postgresql.conf (suite) :
    • période maximale entre deux archivages
    • archive_timeout = '… min'

Processus archiver : lancement

  • Redémarrage de PostgreSQL
    • si modification de wal_level et/ou archive_mode
  • ou rechargement de la configuration

Processus archiver : supervision

  • Vue pg_stat_archiver
  • pg_wal/archive_status/
    • fichiers .ready et .done
  • Archivage dans l’ordre des fichiers
  • Taille de pg_wal
    • si saturation : Arrêt !
  • Traces

Archivage avec pg_receivewal

pg_receivewal : principe

  • Alternative à archive_command
  • Copie les journaux via le protocole de réplication
    • au fil de l’eau
  • Slot de réplication obligatoire
  • Synchrone possible
  • Pour RPO à 0 sans secondaire

Sauvegarde PITR manuelle

Étapes d’une sauvegarde PITR manuelle

  • 3 étapes :
    • fonction de démarrage
    • copie des fichiers par outil externe
    • fonction d’arrêt
  • Exclusive : simple… & obsolète ! (< v15)
  • Concurrente : plus complexe à scripter
  • Aucun impact pour les utilisateurs ; pas de verrou
  • Préférer des outils dédiés qu’un script maison

Sauvegarde manuelle - 1/3 : pg_backup_start

SELECT pg_backup_start (

  • un_label : texte
  • fast : forcer un checkpoint ?

)

Sauvegarde manuelle - 2/3 : copie des fichiers

  • Cas courant : snapshot
    • cohérence ? redondance ?
  • Sauvegarde des fichiers à chaud
    • répertoire principal des données
    • tablespaces
  • Copie forcément incohérente (la restauration des journaux corrigera)
  • rsync et autres outils
  • Ignorer :
    • postmaster.pid, log, pg_wal, pg_replslot et quelques autres
  • Ne pas oublier : configuration !

Sauvegarde manuelle - 3/3 : pg_backup_stop

Ne pas oublier !!

SELECT * FROM pg_backup_stop (

  • true : attente de l’archivage

)

Sauvegarde de base à chaud : pg_basebackup

Outil de sauvegarde pouvant aussi servir au sauvegarde basique

  • Backup de base ici sans les journaux :
$ pg_basebackup --format=tar --wal-method=none \
 --checkpoint=fast --progress -h 127.0.0.1 -U sauve \
 -D /var/lib/postgresql/backups/

Fréquence de la sauvegarde de base

  • Dépend des besoins
  • De tous les jours à tous les mois
  • Plus elles sont espacées, plus la restauration est longue
    • et plus le risque d’un journal corrompu ou absent est important

Suivi de la sauvegarde de base

  • Vue pg_stat_progress_basebackup
SELECT *, pg_size_pretty (backup_total) AS total,
round(100.0*backup_streamed/backup_total::numeric,2) AS "%"
FROM  pg_stat_progress_basebackup  \gx
-[ RECORD 1 ]--------+-------------------------
pid                  | 3608155
phase                | streaming database files
backup_total         | 925114368
backup_streamed      | 197094400
tablespaces_total    | 1
tablespaces_streamed | 0
total                | 882 MB
%                    | 21.30

Restaurer une sauvegarde PITR

Simple, mais à appliquer rigoureusement

Exemple de scénario : sauvegarde

Exemple de scénario : restauration

Restaurer une sauvegarde PITR (1/5)

  • S’il s’agit du même serveur
    • arrêter PostgreSQL
  • Nettoyer les répertoires des données
    • y compris les tablespaces
    • sauf outil travaillant en mode delta

Restaurer une sauvegarde PITR (2/5)

  • Restaurer les fichiers de la sauvegarde
    • où ? (pas à la racine)
  • Peut-être besoin de nettoyer les fichiers restaurés
    • ex : pg_wal, postmaster.pid, log/
    • un bon outil ne les a pas copiés
  • Si restauration après crash :
    • récupérer le dernier journal de transactions connu (si disponible)

Restaurer une sauvegarde PITR (3/5)

  • Indiquer qu’on est en restauration
    • fichier vide recovery.signal
  • Commande de restauration
    • restore_command = '… une commande …'
    • directement dans pg_wal/
    • dans postgresql.[auto.]conf

Restaurer une sauvegarde PITR (4/5)

  • Jusqu’où restaurer :
    • recovery_target_name, recovery_target_time
    • recovery_target_xid, recovery_target_lsn
    • recovery_target_inclusive
  • Le backup de base doit être antérieur !
  • Suivi de timeline :
    • recovery_target_timeline : latest (en général)
  • Et on fait quoi ?
    • recovery_target_action : pause
    • pg_wal_replay_resume pour ouvrir immédiatement
    • ou modifier & redémarrer

Restaurer une sauvegarde PITR (5/5)

  • Démarrer PostgreSQL
  • Rejeu des journaux
  • Vérifier que le point de cohérence est atteint !
  • Ne jamais effacer recovery.signal volontairement

Restauration PITR : durée

  • Durée dépendante du nombre de journaux
    • rejeu séquentiel des WAL
  • Accéléré en version 15 (prefetch)

Restauration PITR : différentes timelines

  • Fin de recovery => changement de timeline :
    • l’historique des données prend une autre voie
    • le nom des WAL change (ex : 00000002000000000000000C)
    • fichiers .history
  • Permet plusieurs restaurations PITR à partir du même basebackup
  • Choix :recovery_target_timeline
    • défaut : latest

Restauration PITR : illustration des timelines

Après la restauration

  • Bien vérifier que l’archivage a repris
    • et que les archives des journaux sont complètes
  • Ne pas hésiter à reprendre une sauvegarde complète
  • Bien vérifier que les secondaires ont suivi

Archivage & compression

  • Limiter la volumétrie des journaux sauvegardés
  • Quels sont les outils PITR ?

Réduire le nombre de journaux sauvegardés

  • Monter
    • checkpoint_timeout
    • max_wal_size

Compresser les journaux de transactions

  • wal_compression = on
    • moins de journaux
    • un peu plus de CPU
    • à activer : pglz (on), lz4, zstd (v15+)
  • Outils de compression standards : gzip, bzip2, lzma
    • attention à ne pas ralentir l’archivage

Outils de sauvegarde PITR

  • Ne réinventez pas la roue !
  • Avantage des outils éprouvés :
    • gestion des backups & de leur rétention
    • commande sûre pour l’archivage
    • commandes pour la restauration
    • nombreuses optimisations
    • tranquillité d’esprit

pgBackRest

  • Gère la sauvegarde et la restauration PITR
    • pull ou push, multidépôts
    • mono- ou multiserveur
  • Indépendant des commandes système
    • protocole dédié
  • Sauvegardes complètes, différentielles ou incrémentales
  • Compression, multi-dépôts
  • Multithread, sauvegarde depuis un secondaire, archivage asynchrone…
  • Projet mature

barman

  • Gère la sauvegarde et la restauration
    • mode pull
    • multiserveurs
  • Une seule commande (barman)
  • Et de nombreuses actions
    • list-server, backup, list-backup, recover
  • Utilise pg_basebackup, pg_receivewal
  • Utilisé par CloudNativePG

WAL-G

  • Successeur de WAL-E, par Citus Data & Yandex
  • Orientation cloud
  • Aussi pour MySQL et SQL Server

Autres outils de l’écosystème

  • De nombreux autres outils existent
  • …ou ont existé
    • pitrery, WAL-E, OmniPITR, pg_rman, walmgr…

Définir ses besoins

  • Sauvegardes physiques ? Logiques ?
  • Sauvegarde locale (NFS ?) / distante (SSH ? S3 ?)
  • Push/pull ?
  • Ressources à disposition ?
  • Accès ? OS/environnement ?
  • Rétention ?
  • Compression ? Performances ?
  • Pérennité, historique ?
  • Supervision ?

Conclusion

  • Une sauvegarde
    • fiable
    • éprouvée
    • rapide
    • continue
  • Mais
    • plus complexe à mettre en place que pg_dump
    • qui restaure toute l’instance

Questions

N’hésitez pas, c’est le moment !

Quiz

Installation de PostgreSQL depuis les paquets communautaires

Introduction à pgbench

Travaux pratiques

pg_basebackup : sauvegarde ponctuelle & restauration

pg_basebackup : sauvegarde ponctuelle & restauration des journaux suivants

Travaux pratiques (solutions)

pg_basebackup

Introduction

pg_basebackup, l’outil simple et efficace pour la copie physique à chaud

Au menu

  • Copie physique à chaud
  • Formats de sauvegarde
  • Compression
  • Avantages/inconvénients
  • Utilisation possible pour
    • le PITR
    • créer un secondaire

Utilisation de pg_basebackup

Cas prévu : la sauvegarde ponctuelle physique à chaud

Présentation

  • Intégré à PostgreSQL
  • Buts :
    • copie physique à chaud cohérente
    • créer facilement un secondaire
  • Ni restauration ni PITR incluses

But

  • Réalise les différentes étapes d’une sauvegarde
    • via 1 ou 2 connexions de réplication + slots de réplication
    • « base backup » & journaux nécessaires
  • Copie intégrale
    • image de la base à la fin du backup
    • peut servir de base pour du PITR plus tard

Mise en place

  • postgresql.conf :
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
  • pg_hba.conf :
host  replication  usersvg  192.168.0.42/32  scram-sha-256

Exemple de sauvegarde

$ pg_basebackup --format=tar --wal-method=stream \
 --checkpoint=fast --progress -h 127.0.0.1 -U sauve \
 -D /var/lib/postgresql/backups/
  • Attention aux fichiers de configuration
  • Possible aussi depuis un serveur secondaire

Restauration

  • Aucun automatisme
    • éventuellement créer l’instance
  • Juste copier vers le bon PGDATA
    • éventuellement décompresser journaux/tablespaces
    • fichier tablespace_map
  • Fichiers de configuration ?
  • Configuration adaptée à la restauration

Options de pg_basebackup

Formats de sauvegarde

  • --format plain
    • arborescence identique à l’instance sauvegardée
  • --format tar
    • 3 archives : PGDATA, journaux, tablespaces
    • compression :
      • -z
      • -Z client-lz4
      • -Z server-zstd:6

Récupération des journaux

  • Défaut : --wal-method stream
    • par streaming, slot de réplication par défaut
  • --wal-method fetch
    • en une phase, un fichier, pas de slot
  • --wal-method none
    • pas de journaux (si copiés par ailleurs)
    • archive alors non cohérente

Slot de réplication

  • Par défaut : slot temporaire
  • Pour un secondaire :
    • créer le slot
    • --slot nom_du_slot --create
    • à utiliser rapidement

Intégrité

  • Fichier manifeste
    • pg_verifybackup
    • --manifest-checksums=CRC32C|SHA523|NONE
  • Vérification des checksums de l’instance

Cible de la sauvegarde

  • Généralement :
    • répertoire vide ou fichier
    • là où pg_basebackup est lancé
    • ex : -D /backups/erp_prod
  • --target=server:/backups/erp_prod
  • --target=blackhole
    • tests

Copie en vue d’un réplica

  • --write-recovery-conf
  • pré-configure le streaming d’un réplica

Autres options

  • Limite de débit :
    • --max-rate=10M
  • Checkpoint immédiat :
    • --checkpoint-fast
  • Adapter le chemin des tablespaces : --tablespace-mapping=<vieuxrep>=<nouveaurep>
  • Et des journaux : --waldir=chemin

Supervision de la sauvegarde

  • --progress
  • Vue pg_stat_progress_basebackup

Sauvegardes incrémentales

  • v17+
  • À recombiner avec pg_combinebackup
  • Plutôt destiné à être utilisé par un outil

Résumé des avantages/inconvénients

Avantages

  • Simple ; inclus dans le projet
  • Transfert des WAL nécessaires pendant la sauvegarde
  • Slot de réplication automatique (temporaire voire permanent)
  • Limitation du débit
  • Relocalisation des tablespaces
  • Fichier manifeste
  • Vérification des checksums
  • Sauvegarde possible à partir d’un secondaire
  • Compression côté serveur ou client, plusieurs algorithmes
  • Emplacement de la sauvegarde (client/server/blackhole)
  • Suivi : pg_stat_progress_basebackup

Limitations

  • Streaming nécessaire
  • Pas de configuration de l’archivage
  • Pas de politique de rétention des sauvegardes
  • Pas de politique de rétention des journaux
  • Sauvegarde incrémentale peu conviviale
  • Pas de gestion de la restauration

Conclusion

  • pg_basebackup : simple et efficace
  • Parfois, pas besoin de plus
  • Si ça se complique, voir pgBackRest & concurrents

Questions

N’hésitez pas, c’est le moment !

Quiz

Sauvegarde PITR avec pgBackRest

pgBackRest

PgbackRest

pgBackRest - Présentation générale

  • David Steele (Crunchy Data)
  • Langage : C
  • Licence : MIT (libre)
  • Type d’interface : CLI (ligne de commande)

pgBackRest - Fonctionnalités

  • Gère la sauvegarde et la restauration PITR
    • pull ou push, multidépôts
    • mono- ou multiserveur
  • Indépendant des commandes système
    • protocole dédié
  • Sauvegardes complètes, différentielles ou incrémentales
  • Compression, multi-dépôts
  • Multithread, sauvegarde depuis un secondaire, archivage asynchrone…
  • Projet mature

pgBackRest - Sauvegardes

  • Type de sauvegarde : physique/PITR (à chaud)
  • Type de stockage : local, push ou pull
  • Planification : crontab (ou autre)
  • Compression des WAL

pgBackRest - Sauvegardes « push »

  • Le serveur « pousse » sauvegardes & archives

  • Et les « tire » lors d’une restauration

pgBackRest - Sauvegardes « pull »

  • Le serveur de sauvegarde « tire » les sauvegardes
  • L’archivage reste en « push »

  • Restauration depuis le serveur PostgreSQL

pgBackRest - Restauration

  • Exécutée sur le serveur de BDD (pull)
    • où que soit le serveur
  • Point dans le temps :
    • date
    • identifiant de transaction
    • timeline
    • point de restauration (pg_create_restore_point())
  • pgBackrest copie et prépare
  • PostgreSQL fait la restauration

pgBackRest - Installation

  • Accéder au dépôt communautaire PGDG
    • paquet pgbackrest
  • Même version sur :
    • tous les serveurs PostgreSQL
    • celui de backup
  • Mises à jour assez fréquentes
    • les appliquer rapidement

pgBackRest - Utilisation

Usage:
    pgbackrest [options] [command]

Commands:
    archive-get     Get a WAL segment from the archive
    archive-push    Push a WAL segment to the archive
    backup          Backup a database cluster
    check           Check the configuration
    expire          Expire backups that exceed retention
    info            Retrieve information about backups
    repo-get        Get a file from a repository
    restore         Restore a database cluster
    server          pgBackRest server
    stanza-create   Create the required stanza data
    stanza-delete   Delete a stanza
    stanza-upgrade  Upgrade a stanza
    start           Allow pgBackRest processes to run
    stop            Stop pgBackRest processes from running
    verify          Verify contents of the repository.
    version         Get version.
    

pgBackRest - Stanza

  • Stanza = instance répartie dans un cluster (groupe de serveurs)
    • la même pour primaire & secondaire
  • Ex : erp_prod, dwh
    • sans n° de version

pgBackRest - Emplacement des fichiers de configuration

  • /etc/pgbackrest/pgbackrest.conf
    • /etc/pgbackrest.conf
    • pgbackrest --config=…
    • /etc/pgbackrest/conf.d/*.conf
    • pgbackrest --config-include-path=…

pgBackRest - Sections

  • [global]
  • [global:archive-push], [global:archive-get]
  • Stanzas :
    • [nomstanza1]
    • [nomstanza2]
  • Surcharges :
    • entre sections
    • en CLI par --nom-option

pgBackRest - Configuration PostgreSQL : archivage

  • postgresql.conf
archive_mode = on
wal_level = replica
archive_command = 'pgbackrest --stanza=erp_prod archive-push %p'
archive_timeout = '? min'   # selon RPO

pgBackRest - Configuration globale

  • Dans pgbackrest.conf :
[global]
repo1-path=/var/lib/pgbackrest
process-max=4
log-level-console=info
log-level-file=detail

pgBackRest - Exemples de déclaration de dépôts

[global]
repo1-path=/mnt/NFS/backups
repo1-retention-full=5
repo1-retention-diff=3

repo2-host-type=ssh
repo2-host=backup_serveur
repo2-host-user=postgres
repo2-path=/srv/depot2
repo2-retention-full=2
repo2-retention-diff=1

repo3-type=s3
repo3-path=/repo
repo3-s3-endpoint=s3.backup.local
repo3-s3-bucket=pgbackrest
repo3-s3-verify-tls=n
repo3-s3-key=XXXX
repo3-s3-key-secret=XXXXXXX
repo3-retention-full=10
repo3-retention-diff=1

pgBackRest - Rétention

  • Type de rétention des sauvegardes complètes
repo1-retention-full-type=count|time
  • Nombre de sauvegardes complètes
repo1-retention-full=2
  • Nombre de sauvegardes différentielles
repo1-retention-diff=3
  • Expiration sur demande :
pgbackrest --stanza=--set=…   expire
pgbackrest --stanza=--oldest  expire

pgBackRest - Accès au dépôt par SSH

  • Échange des clés SSH entre instances (postgres) & le dépôt

  • Accès depuis serveurs PostgreSQL au serveur de sauvegarde :

    [global]
    repo1-host=serveur_depot
    repo1-host-user=postgres
    repo1-host-port=22
  • Accès depuis le serveur de sauvegardes aux instances :

    
    [nomstanza]
    pg1-host=principal
    pg1-host-port=22                          
    pg1-host-user=postgres

pgBackRest - Configuration TLS

Alternative au SSH :

  • {repo1|pg1}-host-type = tls
  • Certificats à fournir
  • Service dédié sur serveurs PG et serveur de sauvegardes

pgBackRest - Configuration par stanza

[erp_prod]
pg1-path=/var/lib/pgsql/17/data
pg1-port=5432
pg1-database=postgres

pgBackRest - Initialiser le répertoire de stockage

  • Initialisation par stanza :
$ sudo -u postgres pgbackrest --stanza=erp_prod stanza-create
  • Vérification :
$ sudo -u postgres pgbackrest --stanza=erp_prod check

pgBackRest - Effectuer une sauvegarde

  • Déclencher une nouvelle sauvegarde :
$ sudo -u postgres pgbackrest --stanza=erp_prod --type=full backup
  • --type=full, --type=diff, --type=incr
  • La plupart des paramètres peuvent être surchargés

pgBackRest - Autres options de sauvegardes

# Journaux dans l'archive
archive-copy=y
# Sauvegarder depuis un secondaire
backup-standby=y
# Checkpoint immédiat
start-fast=y
# Délai de réception des journaux (secondes)
archive-timeout=120

pgBackRest - Lister les sauvegardes

  • Lister les sauvegardes présentes et leur taille
$ sudo -u postgres pgbackrest --stanza=erp_prod info
  • ou une sauvegarde spécifique (backup set)
$ sudo -u postgres pgbackrest --stanza=erp_prod --set 20221026-071751F info

pgBackRest - Dépôts multiples

  • Plusieurs dépôts simultanés possibles, tous types
    • sauvegarde & rétention indépendants
    • archivage sur tous les dépôts (asynchrone conseillé !)
    • --repo1-option=… , appel avec --repo=1

pgBackRest - Compression

Variantes possibles selon les différentes étapes :

# Backup : compression extrême et lente
compress-type=zst
compress-level=9
process-max=16

# Archives uniquement : compression la plus rapide possible
[global:archive-push]
compress-type=lz4
compress-level=1
process-max=2

pgBackRest - Mode asynchrone

Parallélisation de l’archivage/restauration :

archive-async=y
spool-path=/var/spool/pgbackrest
# spool pour la restauration
archive-get-queue-max=4GB

[global:archive-push]
# restauration : pas trop de processus
process-max=4

[global:archive-get]
# restauration : pas trop de processus
process-max=2
  • Gros gain en temps

pgBackRest - Sécurité contre la saturation de pg_wal

  • Abandon de l’archivage si trop de retard :
archive-push-queue-max = 20GB
  • Sauvegarde à relancer !

pgBackRest - Bundling et sauvegarde incrémentale en mode block

  • Regrouper les petits fichiers dans des bundles
repo1-bundle=y
  • Sauvegarde incrémentale en mode block (requiert le bundling)
repo1-bundle=y
repo1-block=y

pgBackRest - Restauration : commande

pgbackrest --stanza=erp_prod \
--pg1-path=/var/lib/postgresql/copie
restore
  • dans postgresql.auto.conf :
# Recovery settings generated by pgBackRest restore on 2026-09-02 18:44:49
restore_command = 'pgbackrest --pg1-path=/var/lib/postgresql/copie
--stanza=defo15 archive-get %f "%p"'

pgBackRest - Restauration : option

  • Nombreuses options à la restauration, notamment :
    • --delta (gros gain de temps parfois)
    • --db-exclude/--db-include (ne restaure pas tout !)
    • --archive_mode=off (sécurité)
    • --target / --type

pgBackRest - Exemple de restauration à une date précise

pgbackrest --stanza=erp_prod \
  --type=time \
  --target='2020-07-16 11:07:00' \
  --target-timeline=4 \
  --set=20200716-102845F \
  --delta \
  restore

pgBackRest - Exemple de restauration d’un secondaire

pgbackrest --stanza=erp_prod \
  --type=standby \
  --pg1-path=/var/lib/postgresql/secondaire \
  restore
  • Ajoute recovery.signal, restore_command
  • Pour streaming, dans pgbackrest.conf :
recovery-option=primary_conninfo='host=primaire port=5432 user=repli'

pgBackRest - Mises à jour

  • Mise à jour de pgBackRest
    • faire en même temps sur toutes les machines
  • Mise à jour mineure de PostgreSQL
    • transparent
  • Mise à jour majeure de PostgreSQL (pg_upgrade)
    • mise à jour des chemins
    • pgbackrest --stanza=… stanza-upgrade

pgBackRest - Traces

  • /var/log/pgbackrest : par stanza+commandes
    • NOMSTANZA-archive-push-async.log
    • NOMSTANZA-backup.log
    • NOMSTANZA-expire.log
  • Sur serveur TLS :
    • /var/log/pgbackrest/all-server.log
  • log-level-console, log-level-file

pgBackRest - Conclusion

  • Un outil de sauvegarde très puissant
  • Nombreuses options

Quiz

Travaux pratiques

Utilisation de pgBackRest (Optionnel)

Travaux pratiques (solutions)

Utilisation de pgBackRest

NB : Ce TP a été mis à jour pour PostgreSQL 17. Adapter le numéro de version dans les chemins au besoin.

Installer pgBackRest à partir des paquets du PGDG.

L’installation du paquet est triviale avec les paquets du PGDG :

 # dnf install pgbackrest    # Rocky Linux
 # apt install pgbackrest    # Debian/Ubuntu

En vous aidant de https://pgbackrest.org/user-guide.html#quickstart :

  • configurer pgBackRest pour sauvegarder le serveur PostgreSQL en local dans /var/lib/pgsql/backups ;
  • le nom de la stanza sera instance_dev ;
  • prévoir de ne conserver qu’une seule sauvegarde complète.

Le ficher de configuration de pgBackRest est /etc/pgbackrest.conf. Le modifier ainsi :

[global]
repo1-path=/var/lib/pgsql/backups
repo1-retention-full=1

[instance_dev]
# chemin de l'instance PostgreSQL
pg1-path=/var/lib/pgsql/17/data

(Les chemins ci-dessus sont ceux par défaut des paquets RPM du PGDG. Sous Debian/Ubuntu, les données sont dans /var/lib/postgresql/17/main. Adapter les autres chemins en fonction.)

Configurer l’archivage des journaux de transactions de PostgreSQL avec pgBackRest.

Le fichier de configuration de PostgreSQL doit être modifié au besoin ainsi.

wal_level = replica
archive_mode = on
archive_command = 'pgbackrest --stanza=instance_dev archive-push %p'

Redémarrer PostgreSQL :

 # systemctl restart postgresql-17

Initialiser le répertoire de stockage des sauvegardes et vérifier la configuration de l’archivage.

Sous l’utilisateur postgres :

pgbackrest --stanza=instance_dev --log-level-console=info stanza-create
… P00   INFO: stanza-create command begin 2.54.1: --exec-id=116151-5ba090e6 --log-level-console=info --pg1-path=/var/lib/pgsql/17/data --repo1-path=/var/lib/pgsql/backups --stanza=instance_dev
… P00   INFO: stanza-create for stanza 'instance_dev' on repo1
… P00   INFO: stanza-create command end: completed successfully (56ms)

Vérifier la configuration de pgBackRest et de l’archivage :

pgbackrest --stanza=instance_dev --log-level-console=info check

pgBackRest force ainsi un archivage :

… P00   INFO: check command begin 2.54.1: --exec-id=116153-45ee6160 --log-level-console=info --pg1-path=/var/lib/pgsql/17/data --repo1-path=/var/lib/pgsql/backups --stanza=instance_dev
… P00   INFO: check repo1 configuration (primary)
… P00   INFO: check repo1 archive for WAL (primary)
… P00   INFO: WAL segment 0000000200000000000000D8 successfully archived to '/var/lib/pgsql/backups/archive/instance_dev/17-1/0000000200000000/0000000200000000000000D8-81ecb9751dd627ba196fca377e9e6d0a2aa6fd05.gz' on repo1
… P00   INFO: check command end: completed successfully (409ms)

Vérifier que l’archivage fonctionne en vérifiant que ce répertoire n’est pas vide :

ls -alR /var/lib/pgsql/backups/archive/instance_dev/17-1/

On peut le vérifier aussi du côté PostgreSQL :

SELECT * FROM pg_stat_archiver \gx
-[ RECORD 1 ]------+------------------------------
archived_count     | 4
last_archived_wal  | 0000000200000000000000D8
last_archived_time | 2025-01-13 19:03:13.400874+01
failed_count       | 0
last_failed_wal    | 
last_failed_time   | 
stats_reset        | 2025-01-13 18:47:37.39799+01

Autre méthode, regarder le nom du processus archiver, qui contient le nom du dernier journal archivé :

$ ps faux|grep archiver
…
postgres  211745  0.0  0.1 502568  7124 ?        Ss   14:14   0:00  \_ postgres: archiver last was 0000000200000000000000D8

Lancer une sauvegarde complète. Afficher les détails de cette sauvegarde.

pgbackrest --stanza=instance_dev --type=full \
           --log-level-console=info backup

Noter le soin avec lequel pgBackRest vérifie que l’archivage est fonctionnel avant la sauvegarde, et l’attente du dernier journal avant d’assurer que la sauvegarde est terminée :

… P00   INFO: backup command begin 2.54.1: --exec-id=116270-de7f5e35 --log-level-console=info --pg1-path=/var/lib/pgsql/17/data --repo1-path=/var/lib/pgsql/backups --repo1-retention-full=1 --stanza=instance_dev --type=full
… P00   INFO: execute non-exclusive backup start: backup begins after the next regular checkpoint completes
… P00   INFO: backup start archive = 0000000200000000000000DC, lsn = 0/DC000028
… P00   INFO: check archive for prior segment 0000000200000000000000DB


… P00   INFO: execute non-exclusive backup stop and wait for all WAL segments to archive
… P00   INFO: backup stop archive = 0000000200000000000000DC, lsn = 0/DC000158
… P00   INFO: check archive for segment(s) 0000000200000000000000DC:0000000200000000000000DC
… P00   INFO: new backup label = 20250113-190921F
… P00   INFO: full backup size = 3.5GB, file total = 1594
… P00   INFO: backup command end: completed successfully (74648ms)
… P00   INFO: expire command begin 2.54.1: --exec-id=116270-de7f5e35 --log-level-console=info --repo1-path=/var/lib/pgsql/backups --repo1-retention-full=1 --stanza=instance_dev
… P00   INFO: repo1: expire full backup 20250113-190649F
… P00   INFO: repo1: remove expired backup 20250113-190649F
… P00   INFO: repo1: 17-1 remove archive, start = 0000000200000000000000D8, stop = 0000000200000000000000DB
… P00   INFO: expire command end: completed successfully (109ms)

Lister les sauvegardes :

pgbackrest --stanza=instance_dev info
stanza: instance_dev
    status: ok
    cipher: none

    db (current)
        wal archive min/max (17): 0000000200000000000000DC/0000000200000000000000DC

        full backup: 20250113-190921F
            timestamp start/stop: 2025-01-13 19:09:21+01 / 2025-01-13 19:10:35+01
            wal start/stop: 0000000200000000000000DC / 0000000200000000000000DC
            database size: 3.5GB, database backup size: 3.5GB
            repo1: backup set size: 197.7MB, backup size: 197.7MB

Ajouter des données : \ Ajouter une table avec 1 million de lignes. \ Forcer la rotation du journal de transaction courant afin de s’assurer que les dernières modifications sont archivées. \ Vérifier que le journal concerné est bien dans les archives.

La table suivante fait 35 Mo, qui seront intégralement écrits dans les journaux :

CREATE TABLE matable AS SELECT i FROM generate_series(1,1000000) i ;

Pour ce test, il est possible de forcer la rotation du journal avec pg_switch_wal. Dans la vie réelle, il y a de l’activité dans la base et le journal sera assez vite archivé. Sans cela il pourrait ne pas être sauvegardé.

pg_switch_wal renvoie un LSN peu lisible, comme 0/E8000180, où E8 correspond à la fin du nom du journal. On peut ajouter pg_walfile_name() pour voir plus clairement le nom du journal à archiver :

SELECT pg_walfile_name ( pg_switch_wal() );
      pg_walfile_name 
--------------------------
 0000000200000000000000E8

Vérifier que le journal concerné est bien dans le répertoire de sauvegarde des archives de pgBackRest, soit dans notre exemple /var/lib/pgsql/backups/archive/instance_dev/17-1/. La copie devrait être ici instantanée, mais en production ça ne ne l’est pas forcément.

Simulation d’un incident : noter l’heure puis supprimer tout le contenu de la table.

Noter l’heure exacte avant de détruire des données :

SELECT now() ;
 2025-01-13 19:21:22.043403+01
TRUNCATE TABLE matable;

Restaurer les données telles que juste avant l’incident à l’aide de pgBackRest. \ Avant de redémarrer PostgreSQL, consulter les fichiers que pgBackRest a créé ou modifié dans le PGDATA. \ Redémarrer.

D’abord, stopper PostgreSQL (sinon pgBackRest refusera de toucher aux données) :

sudo systemctl stop postgresql-17

En tant que postgres, lancer la commande de restauration avec une heure juste avant la destruction des données :

pgbackrest --stanza=instance_dev --log-level-console=info \
--delta                         \
--type=time                     \
--target="2025-01-13 19:21:22"  \
--target-exclusive              \
--target-action=promote         \
restore

Noter déjà le mode « delta » pour accélérer la restauration, et le type de restauration time avec une heure.

… P00   INFO: restore command begin 2.54.1: --delta --exec-id=116554-29ea7f39 --log-level-console=info --pg1-path=/var/lib/pgsql/17/data --repo1-path=/var/lib/pgsql/backups --stanza=instance_dev --target="2025-01-13 19:21:22" --target-action=promote --target-exclusive --type=time
… P00   INFO: repo1: restore backup set 20250113-190921F, recovery will start at 2025-01-13 19:09:21
… P00   INFO: remove invalid files/links/paths from '/var/lib/pgsql/17/data'
… P00   INFO: write updated /var/lib/pgsql/17/data/postgresql.auto.conf
… P00   INFO: restore global/pg_control (performed last to ensure aborted restores cannot be started)
… P00   INFO: restore size = 3.5GB, file total = 1594
… P00   INFO: restore command end: completed successfully (4909ms)

La restauration du base backup est un succès, mais il va falloir rejouer les journaux archivés.

pgBackRest a créé ou modifié ces fichiers :

$ ls -alrt  /var/lib/pgsql/17/data


-rw-------.  1 postgres postgres   353 13 janv. 19:15 postgresql.auto.conf
-rw-------.  1 postgres postgres     0 13 janv. 19:15 recovery.signal
  • recovery.signal signalera à PostgreSQL qu’il est en mode restauration, et pas en redémarrage après un crash ;
  • postgresql.auto.conf contient des paramètres qui vont surcharger postgresql.conf :
# Recovery settings generated by pgBackRest restore on 2025-01-13 19:15:22
restore_command = 'pgbackrest --stanza=instance_dev archive-get %f "%p"'
recovery_target_time = '2025-01-13 19:21:22'
recovery_target_inclusive = 'false'
recovery_target_action = 'promote'

On y trouve :

  • la restore_command pour récupérer les journaux dans le dépôt, commande que pgBackRest a préparé en fonction de sa configuration et des paramètres de la ligne de commande de restauration ;
  • recovery_target_time indique l’heure cible ;
  • recovery_target_inclusive = 'false' arrête la restauration juste avant cette heure pour ne pas rejouer la destruction des données (le défaut est de rejouter jusqu’à l’heure cible incluse) ;
  • recovery_target_action = 'promote' demande à PostgreSQL de s’ouvrir en écriture après le rejeu.

Démarrer PostgreSQL :

sudo systemctl start postgresql-17

Attendre la fin de la restauration dans les traces :

# Attention, le nom du fichier dépend du jour
tail -n100  /var/lib/pgsql/17/data/log/postgresql-Mon.log
2025-01-13 19:26:38.946 CET [116631] LOG:  database system was interrupted; last known up at 2025-01-13 19:09:21 CET
2025-01-13 19:26:39.032 CET [116631] LOG:  starting backup recovery with redo LSN 0/DC000028, checkpoint LSN 0/DC000080, on timeline ID 2
2025-01-13 19:26:39.108 CET [116631] LOG:  restored log file "0000000200000000000000DC" from archive
2025-01-13 19:26:39.168 CET [116631] LOG:  starting point-in-time recovery to 2025-01-13 19:21:22+01
2025-01-13 19:26:39.176 CET [116631] LOG:  redo starts at 0/DC000028
2025-01-13 19:26:39.236 CET [116631] LOG:  restored log file "0000000200000000000000DD" from archive
2025-01-13 19:26:39.298 CET [116631] LOG:  completed backup recovery with redo LSN 0/DC000028 and end LSN 0/DC000158
2025-01-13 19:26:39.298 CET [116631] LOG:  consistent recovery state reached at 0/DC000158
2025-01-13 19:26:39.298 CET [116626] LOG:  database system is ready to accept read-only connections
2025-01-13 19:26:39.584 CET [116631] LOG:  restored log file "0000000200000000000000DE" from archive
2025-01-13 19:26:39.893 CET [116631] LOG:  restored log file "0000000200000000000000DF" from archive
2025-01-13 19:26:40.169 CET [116631] LOG:  restored log file "0000000200000000000000E0" from archive
2025-01-13 19:26:40.458 CET [116631] LOG:  restored log file "0000000200000000000000E1" from archive
2025-01-13 19:26:40.609 CET [116631] LOG:  restored log file "0000000200000000000000E2" from archive
2025-01-13 19:26:40.758 CET [116631] LOG:  restored log file "0000000200000000000000E3" from archive
2025-01-13 19:26:40.907 CET [116631] LOG:  restored log file "0000000200000000000000E4" from archive
2025-01-13 19:26:41.029 CET [116631] LOG:  restored log file "0000000200000000000000E5" from archive
2025-01-13 19:26:41.291 CET [116631] LOG:  restored log file "0000000200000000000000E6" from archive
2025-01-13 19:26:41.592 CET [116631] LOG:  restored log file "0000000200000000000000E7" from archive
2025-01-13 19:26:41.876 CET [116631] LOG:  restored log file "0000000200000000000000E8" from archive
2025-01-13 19:26:42.238 CET [116631] LOG:  restored log file "0000000200000000000000E9" from archive
2025-01-13 19:26:42.333 CET [116631] LOG:  recovery stopping before commit of transaction 32096, time 2025-01-13 19:21:40.349582+01
2025-01-13 19:26:42.333 CET [116631] LOG:  redo done at 0/E904E420 system usage: CPU: user: 1.18 s, system: 0.18 s, elapsed: 3.15 s
2025-01-13 19:26:42.333 CET [116631] LOG:  last completed transaction was at log time 2025-01-13 19:20:51.370895+01
2025-01-13 19:26:42.403 CET [116631] LOG:  restored log file "0000000200000000000000E9" from archive
2025-01-13 19:26:42.498 CET [116631] LOG:  selected new timeline ID: 3
2025-01-13 19:26:42.612 CET [116631] LOG:  archive recovery complete
2025-01-13 19:26:42.615 CET [116629] LOG:  checkpoint starting: end-of-recovery immediate wait
2025-01-13 19:26:42.806 CET [116629] LOG:  checkpoint complete: wrote 4490 buffers (27.4%); 0 WAL file(s) added, 0 removed, 13 recycled; write=0.040 s, sync=0.114 s, total=0.194 s; sync files=36, longest=0.102 s, average=0.004 s; distance=213304 kB, estimate=213304 kB; lsn=0/E904E420, redo lsn=0/E904E420
2025-01-13 19:26:42.814 CET [116626] LOG:  database system is ready to accept connections

Vérifier les logs et la présence des données disparues.

La trace ci-dessus indique bien :

  • la restauration de divers journaux ;
  • l’arrivée au point de cohérence qui permet au moins d’avoir une instance utilisable telle qu’à la fin du base backup (consistent recovery state) ;
  • le changement vers une nouvelle timeline (selected new timeline ID: 3), comme après toute restauration ;
  • et l’heure de fin de la dernière transaction rejouée (last completed transaction was at …).

Les lignes perdues sont bien revenues :

SELECT count(*) FROM matable ;
  count
---------
 1000000

Remarque :

Sans spécifier de --target-action=promote, on obtiendrait dans les traces de PostgreSQL, après restore :

LOG:  recovery has paused
HINT:  Execute pg_wal_replay_resume() to continue.

Solutions de réplication

Préambule

  • Attention au vocabulaire !
  • Identifier le besoin
  • Keep It Simple…

Au menu

  • Rappels théoriques & vocabulaire
  • Réplication interne, physique ou logique
  • Alternatives

Objectifs

  • Identifier les différences entre les solutions de réplication proposées
  • Choisir le système le mieux adapté à votre besoin

Rappels théoriques

  • Termes
  • Réplication
    • synchrone / asynchrone
    • symétrique / asymétrique
    • diffusion des modifications

Cluster, primaire, secondaire, standby

  • Cluster : ambiguïté !
    • groupe de bases de données = 1 instance (PostgreSQL)
    • groupe de serveurs (haute disponibilité et/ou réplication)
  • Pour désigner les membres :
    • Primaire/primary
    • Secondaire/standby

Réplication asynchrone asymétrique

  • Asymétrique
    • écritures sur un serveur primaire unique
    • lectures sur le primaire et/ou les secondaires
  • Asynchrone
    • les écritures sur les serveurs secondaires sont différées
    • perte de données possible en cas de crash du primaire
  • Exemples :
    • réplication PostgreSQL par streaming (par défaut) ou log shipping
    • réplication par trigger

Réplication asynchrone symétrique

  • Symétrique
    • « multiprimaire »
    • écritures sur les différents primaires
    • besoin d’un gestionnaire de conflits
    • lectures sur les différents primaires
  • Asynchrone
    • la réplication des écritures est différées
    • perte de données possible en cas de crash du serveur primaire
    • risque d’incohérences !
  • Exemples :
    • BDR (EDB) : réplication logique

Réplication synchrone asymétrique

  • Asymétrique
    • écritures sur un serveur primaire unique
    • lectures sur le serveur primaire et/ou les secondaires
  • Synchrone
    • les écritures sur les secondaires sont immédiates
    • le client sait si sa commande a réussi sur plusieurs serveurs
  • Exemple : mode synchrone de la réplication physique de PostgreSQL
    • paramètres synchronous_commit et synchronous_standby_names

Réplication synchrone symétrique

  • Symétrique
    • écritures sur les différents serveurs primaires
    • besoin d’un gestionnaire de conflits
    • lectures sur les différents serveurs
  • Synchrone
    • les écritures sur les autres serveurs sont immédiates
    • le client sait si sa commande est validée sur plusieurs serveurs
    • risque important de lenteur !
  • En avez-vous vraiment besoin ?

Diffusion des modifications

  • Par requêtes
    • diffusion de la requête
  • Par triggers
    • diffusion des données résultant de l’opération
  • Par journaux, physique
    • diffusion des blocs disques modifiés
  • Par journaux, logique
    • extraction et diffusion des données résultant de l’opération depuis les journaux

Réplication interne physique

  • Réplication
    • asymétrique
    • asynchrone (défaut) ou synchrone (et selon les transactions)
  • Secondaires (Hot Standby)
    • disponibles en lecture seule
    • cascade
    • retard programmé, voire pause complète

Log Shipping

  • But :
    • envoyer les journaux de transactions à un secondaire
  • Première solution disponible
    • de nos jours, sécurité à côté du streaming
  • Gros inconvénients :
    • perte possible de plusieurs journaux
    • latence à la réplication
    • penser à archive_timeout ou pg_receivewal

Streaming replication

  • But
    • avoir un retard moins important sur le serveur secondaire
  • Rejouer les enregistrements de transactions du serveur primaire par paquets
    • paquets plus petits qu’un journal de transactions
    • le secondaire reconstitue les journaux

Secondaire Hot Standby

  • Serveur secondaire
    • accepte les connexions entrantes
    • requêtes en lecture seule et sauvegardes
    • prêt à prendre le relai du primaire
  • Différentes configurations selon les versions
    • asynchrone ou synchrone
    • application immédiate ou retardée

Exemple

Réplication interne

Réplication en cascade

Réplication interne logique

  • Réplique les changements
    • d’une seule base de données
    • d’un ensemble de tables défini
  • Principe Éditeur/Abonnés

Réplication logique - Fonctionnement

  • Création d’une publication sur un serveur
  • Souscription d’un autre serveur à cette publication
  • Limitations :
    • DDL, Large objects, séquences, tables étrangères et vues matérialisées non répliqués
    • peu adaptée pour un failover

Réplication externe

  • Outils les plus connus :
    • Pgpool (réplication par SQL)
    • Slony, Bucardo (par trigger, abandonnés)
    • pglogical (logique)
  • Niches

Sharding

  • Répartition des données sur plusieurs instances
  • Évolution horizontale en ajoutant des serveurs
  • Parallélisation
  • Clé de répartition cruciale
  • Administration complexifiée
  • Sous PostgreSQL :
    • Foreign Data Wrapper
    • PL/Proxy
    • Citus (extension), et nombreux forks

Réplication bas niveau

  • RAID
  • DRBD
  • SAN Mirroring

RAID

  • Obligatoire
  • Fiabilité d’un serveur
  • RAID 1 ou RAID 10
  • RAID 5 déconseillé (performances)
  • Lectures plus rapides
    • dépend du nombre de disques impliqués

DRBD

  • Simple / synchrone / Bien documenté
  • Lent / Secondaire inaccessible / Linux uniquement

SAN Mirroring

  • Comparable à DRBD
  • Solution intégrée
  • Manque de transparence

Vers la haute disponibilité ?

Haute disponibilité avec bascule automatique

Une bonne idée ?

  • Un collègue peu loquace et rigide
    • et tout doit passer par lui
  • Risque de cluster trop sensible (& déconnexions)
  • En fait : complexification de l’administration
    • watchdog, quorums, fencing, éviter les split brains
    • formation, tests, documentation, communication
  • Au final : est-ce plus fiable ?

Conclusion

Quelle que soit la solution envisagée :

  • Bien définir son besoin
  • Identifier tous les SPOF
  • Superviser son cluster
  • Tester régulièrement les procédures de failover (Loi de Murphy…)

Questions

N’hésitez pas, c’est le moment !

Quiz

Réplication physique : fondamentaux

Introduction

  • Principes
  • Mise en place
  • Administration

Objectifs

  • Connaître les avantages et limites de la réplication physique
  • Savoir la mettre en place
  • Savoir administrer et superviser une solution de réplication physique

Concepts / principes

Principe de la journalisation

  • Les journaux de transactions contiennent toutes les modifications
    • utilisation du contenu des journaux
  • Le serveur secondaire doit posséder une image des fichiers à un instant t
  • La réplication modifiera les fichiers
    • d’après le contenu des journaux suivants

Principales évolutions de la réplication physique

  • 8.2 : Réplication par journaux (log shipping), Warm Standby
  • 9.0 : Réplication en streaming, Hot Standby
  • 9.1 à 9.3 : Réplication synchrone, cascade, pg_basebackup
  • 9.4 : Slots de réplication, délai de réplication, décodage logique
  • 9.5 : pg_rewind, archivage depuis un serveur secondaire
  • 9.6 : Rejeu synchrone
  • 10 : Réplication synchrone sur base d’un quorum, slots temporaires
  • 12 : Déplacement de la configuration du recovery.conf vers le postgresql.conf
  • 13 : Sécurisation des slots (journaux)
  • 15 : Rejeu accéléré

Avantages

  • Système de rejeu éprouvé
  • Mise en place simple
  • Pas d’arrêt ou de blocage des utilisateurs
  • Réplique tout

Inconvénients

  • Réplication de l’instance complète
  • Serveur secondaire uniquement en lecture
  • Impossible de changer d’architecture
  • Même version majeure de PostgreSQL pour tous les serveurs

Réplication par streaming

Mise en place de la réplication par streaming

  • Réplication en flux
  • Un processus du serveur primaire discute avec un processus du serveur secondaire
    • d’où un lag moins important
  • Asynchrone ou synchrone
  • En cascade

Serveur primaire (1/2) - Configuration

Dans postgresql.conf :

  • wal_level = replica (ou logical)
  • max_wal_senders = X
    • 1 par client par streaming
    • défaut : 10
  • wal_sender_timeout = 60s

Serveur primaire (2/2) - Authentification

  • Le serveur secondaire doit pouvoir se connecter au serveur primaire
  • Pseudo-base replication
  • Utilisateur dédié conseillé avec attributs LOGIN et REPLICATION
  • Configurer pg_hba.conf :
host replication user_repli 10.2.3.4/32   scram-sha-256
  • Recharger la configuration

Serveur secondaire (1/4) - Copie des données

Copie des données du serveur primaire (à chaud !) :

  • Copie généralement à chaud donc incohérente !
  • Le plus simple : pg_basebackup
    • simple mais a des limites
  • Idéal : outil PITR
  • Possible : rsync, cp
    • ne pas oublier pg_backup_start()/pg_backup_stop() !
    • exclure certains répertoires et fichiers
    • garantir la disponibilité des journaux de transaction

Serveur secondaire (2/4) - Fichiers de configuration

  • postgresql.conf & postgresql.auto.conf
    • paramètres
  • standby.signal (dans PGDATA)
    • vide

Serveur secondaire (3/4) - Paramètres

  • primary_conninfo (streaming) :
primary_conninfo = 'user=user_repli host=prod port=5434
 application_name=standby '
  • Optionnel :
    • primary_slot_name
    • restore_command
    • wal_receiver_timeout

Serveur secondaire (4/4) - Démarrage

  • Démarrer PostgreSQL
  • Suivre dans les traces que tout va bien

Processus

Sur le primaire :

  • walsender ... streaming 0/3BD48728

Sur le secondaire :

  • walreceiver streaming 0/3BD48728

Promotion

Au menu

  • Attention au split-brain !
  • Vérification avant promotion
  • Promotion : méthode et déroulement
  • Retour à l’état stable

Attention au split-brain !

  • Si un serveur secondaire devient le nouveau primaire
    • s’assurer que l’ancien primaire ne reçoit plus d’écriture
  • Éviter que les deux instances soient ouvertes aux écritures
    • confusion et perte de données !

Vérification avant promotion

  • Primaire :
# systemctl stop postgresql-17
$ pg_controldata -D /var/lib/pgsql/17/data/ \
| grep -E '(Database cluster state)|(REDO location)'
Database cluster state:               shut down
Latest checkpoint's REDO location:    0/3BD487D0
  • Secondaire :
$ psql -c 'CHECKPOINT;'
$ pg_controldata -D /var/lib/pgsql/17/data/ \
| grep -E '(Database cluster state)|(REDO location)'
Database cluster state:               in archive recovery
Latest checkpoint's REDO location:    0/3BD487D0

Promotion du standby : méthode

  • Shell :
    • pg_ctl promote
  • SQL :
    • fonction pg_promote()

Promotion du standby : déroulement

Une promotion déclenche :

  • déconnexion de la streaming replication (bascule programmée)
  • rejeu des dernières transactions en attente d’application
  • récupération et rejeu de toutes les archives disponibles
  • choix d’une nouvelle timeline du journal de transaction
  • suppression du fichier standby.signal
  • nouvelle timeline et fichier .history
  • ouverture aux écritures

Opérations après promotion du standby

  • VACUUM ANALYZE conseillé
    • calcul d’informations nécessaires pour autovacuum

Retour à l’état stable

Si un standby a été momentanément indisponible :

  • Rattrapage possible si tous les journaux sont disponibles :
    • streaming depuis le primaire (slot, wal_keep_size)
    • log shipping depuis les archives (restore_command)
    • ou les deux (si configurés)
  • Sinon :
    • « décrochage… »
    • reconstruction nécessaire

Conclusion

  • Système de réplication fiable
  • Simple à maîtriser et à configurer

Quiz

Travaux pratiques

Sur Rocky Linux 8 ou 9

Réplication asynchrone en flux avec un seul secondaire

Promotion de l’instance secondaire

Retour à la normale

Sur Debian 12

Réplication asynchrone en flux avec un seul secondaire

Promotion de l’instance secondaire

Retour à la normale

Travaux pratiques (solutions)

Sur Rocky Linux 8 ou 9

Sur Debian 12

Réplication physique avancée

Introduction

  • Supervision
  • Fonctionnalités avancées

Au menu

  • Supervision
  • Gestion des conflits
  • Asynchrone ou synchrone
  • Réplication en cascade
  • Slot de réplication
  • Log shipping

Supervision (streaming)

  • Quelles vues et fonctions utilitaires ?
  • Comment voir et calculer le retard des secondaires ?

Utilitaires pour le streaming

  • pg_is_in_recovery() : instance en réplication ?
  • Calcul du retard en octets :
-- primaire
SELECT pg_wal_lsn_diff ( pg_current_wal_lsn(), '0/73D3C1F0' );
  • et en temps
-- secondaire
SELECT now() - pg_last_xact_replay_timestamp() ; -- si activité

pg_stat_replication

SELECT … FROM pg_stat_replication;
-[ RECORD 1 ]----+------------------------------
pid              | 286511
usesysid         | 10
usename          | postgres
application_name | secondaire2
client_addr      | 192.168.0.55
client_hostname  |
client_port      |
backend_start    | 2023-12-19 10:41:47.431471+01
backend_xmin     |
state            | streaming
sent_lsn         | 14/C402A000
write_lsn        | 14/C402A000
flush_lsn        | 14/C402A000
replay_lsn       | 14/C311D460
write_lag        | 00:00:00.032183
flush_lag        | 00:00:00.032601
replay_lag       | 00:00:02.984354
sync_priority    | 1
sync_state       | sync
reply_time       | 2023-12-19 11:05:37.903584+01

Autres vues pour le streaming

  • S’il y a un slot
    • pg_replication_slots
  • Sur le secondaire
    • pg_stat_wal_receiver

Supervision (log shipping)

Supervision du log shipping

  • Le primaire ne sait rien
  • Supervision de l’archivage comme pour du PITR
    • pg_stat_archiver
  • Secondaire :
    • pg_wal_lsn_diff()
    • traces
    • calcul du retard manuel (pg_last_wal_replay_lsn())

Conflits de réplication

Qu’est-ce qu’un conflit de réplication ?

Détection des conflits de réplication

  • Une requête en lecture pose des verrous
    • conflit possible avec changements répliqués !
  • Vue pg_stat_database_conflicts (secondaires)
  • Traces :
    • log_recovery_conflict_waits

Prévenir les conflits de réplication

  • wal_standby_streaming_delay
  • hot_standby_feedback à on + wal_receiver_status_interval (10s)
  • gênent le vacuum !

Contrôle de la réplication

  • pg_wal_replay_pause() : mettre en pause le rejeu
  • pg_wal_replay_resume() : reprendre
  • pg_is_wal_replay_paused() : statut
  • Utilité :
    • requêtes longues
    • pg_dump depuis un secondaire

Réplication synchrone

  • Comment configurer ?
  • Comment limiter l’impact sur les performances ?

Principe de la réplication synchrone

En synchrone, lors d’un COMMIT :

  • le primaire attend l’enregistrement sur le secondaire :
    • latence réseau
    • temps de rejeu des journaux
    • synchronisation sur le secondaire
  • le secondaire est à jour en cas de bascule
  • permet des secondaires qui renvoient le même résultat
  • mais ralentit les écritures !

Secondaires synchrones

  • Par défaut : réplication physique asynchrone
  • Secondaires synchrones :
# s1 synchrone, s2 en dépannage
synchronous_standby_names = 'FIRST 1 (s1, s2)'
# 2 synchrones au moins
synchronous_standby_names = 'ANY 2 (s1,s2,s3)'
# n'importe quel secondaire
synchronous_standby_names = '*'
  • Plusieurs synchrones simultanés possibles
    • ou un quorum

Niveau de synchronicité & performances

  • Niveau de synchronicité :
SET synchronous_commit = off / local / remote_write / on / remote_apply
  • Ajustable par base/utilisateur/session/transaction
  • Risque de blocage du primaire à cause des secondaires !

Réplication en cascade

Principe de la réplication en cascade

  • Un secondaire peut fournir les informations de réplication
  • Décharger le serveur primaire de ce travail
  • Diminuer la bande passante du serveur primaire

Délai à la réplication

Délai à la réplication

  • Le secondaire peut appliquer les modifications avec un retard
  • recovery_min_apply_delay = 1h
  • Nombreux inconvénients

Décrochage d’un secondaire

Causes d’un décrochage

  • Par défaut, le primaire n’attend pas les secondaires pour recycler ses WAL
  • « Décrochage » si :
    • liaison trop lente
    • secondaire déconnecté
    • secondaire trop lent à rejouer
  • Le primaire ne peut plus alimenter le secondaire
    • Reconstruction du secondaire nécessaire

Sécurisation par log shipping

  • archive_command / restore_command
    • script par l’outil PITR
    • ou cp, scp, lftp, rsync, script…
  • Nettoyage
    • rétention des journaux si outil PITR
    • ou outil dédié :
archive_cleanup_command = '/usr/pgsql-14/bin/pg_archivecleanup -d rep_archives/ %r'

Slot de réplication : mise en place

  • Slot de réplication sur le primaire :
    • max_replication_slots
    • NB : non répliqué !
    • création manuelle :
    SELECT pg_create_physical_replication_slot ('nomsecondaire') ;
  • Secondaire :
    • dans postgresql.conf
    primary_slot_name = 'nomsecondaire'
    • et rechargement de configuration

Slot de réplication : avantages & risques

  • Avantages :
    • plus de risque de décrochage des secondaires
    • supervision facile : pg_replication_slots
    • utilisable par pg_basebackup
  • Risque : accumulation des journaux
    • danger pour le primaire !
    • sécurité : max_slot_wal_keep_size, idle_replication_slot_timeout
  • Risque : vacuum bloqué
    • hot_standby_feedback ?

Divergence entre instances

Quand y a-t-il divergence ?

Il existe des enregistrements de journaux différents pour les mêmes LSN.

Cas :

  • Secondaire ouvert un temps en écriture (timeline propre)
  • Ancien primaire qui a écrit après la promotion d’un secondaire
  • En général sur timelines séparées

Corriger une divergence

  • Reconstruire les serveurs secondaires à partir du nouveau primaire :
    • rsync, restauration PITR, pg_basebackup
  • Pour les divergences faibles :
    • pg_rewind

Synthèse des paramètres

Serveur primaire

Log shipping Streaming
wal_level = replica * wal_level = replica *
archive_mode = on *
archive_command *
archive_library
archive_timeout wal_sender_timeout
max_wal_senders
max_replication_slots
wal_keep_size
max_slot_wal_keep_size *
idle_replication_slot_timeout

Serveur secondaire

Log shipping Streaming
wal_level = replica * wal_level = replica *
restore_command *
archive_cleanup_command
(selon outil) primary_conninfo *
wal_receiver_timeout
hot_standby
primary_slot_name*
max_standby_archive_delay max_standby_streaming_delay
hot_standby_feedback
wal_receiver_status_interval

Conclusion

  • Système de réplication fiable…
    • et très complet

Questions

N’hésitez pas, c’est le moment !

Quiz

Travaux pratiques

Réplication asynchrone en flux avec deux secondaires

Slots de réplication

Log shipping

Réplication synchrone en flux avec trois secondaires

Réplication synchrone : cohérence des lectures (optionnel)

Travaux pratiques (solutions)

Les outils de réplication physique

Introduction

  • Les outils à la rescousse !
    • (Re)construction d’un secondaire
    • Log shipping & PITR
    • Promotion automatique

Au menu

  • (Re)construction d’un secondaire
    • outils de copie
    • pg_rewind
  • Log shipping & PITR
    • pgBackRest
    • Barman
  • Promotion automatique
    • Patroni
    • repmgr
    • PAF

(Re)construire un secondaire

Outils :

  • pg_basebackup
  • rsync
  • outils PITR
  • pg_rewind

(Re)construction d’un secondaire : pg_basebackup

  • Simple et pratique
  • …mais recopie tout !

(Re)construction d’un secondaire : script rsync

  • Déconseillé si vous avez un autre outil
  • Intérêts :
    • reprendre des transferts interrompus
    • compression
  • Prévoir :
    • pg_backup_start()/pg_backup_stop()
    • rsync --whole-file
    • les tablespaces
    • ne pas tout copier !
    • postgresql.conf

(Re)construction d’un secondaire : outil PITR

  • Le plus confortable
  • Ne charge pas le primaire
  • Mode « delta »
pgbackrest --stanza=instance      --type=standby      --delta  \
  --repo1-host=depot --repo1-host-user=postgres --repo1-host-port=22 \
  --pg1-path=/var/lib/postgresql/17/secondaire \
  --process-max=8 \
  --recovery-option=primary_conninfo='host=principal port=5433 user=replicator' \
  --recovery-option=primary_slot_name='secondaire' \
  --target-timeline=latest \
  restore

pg_rewind

  • Pour récupérer un primaire après bascule & divergence
  • Évite la reconstruction complète
  • Pré-requis :
    • data_checksums = on
    • ou wal_log_hints = on
    • tous les WAL depuis la divergence
    • full_page_writes = on (défaut)
  • Revient au point de divergence

Outils dédiés au log shipping & à la sauvegarde PITR

Réplication par log shipping sécurisée par la sauvegarde PITR

  • Utilisation des archives pour :
    • se prémunir du décrochage d’un secondaire
    • une sauvegarde PITR
  • Utilisation des sauvegardes PITR pour :
    • resynchroniser un serveur secondaire

pgBackRest

  • pgbackrest restore
    • --type=standby
    • --recovery-option
    • --delta (optionnel)

barman

  • barman recover
    • --standby-mode
    • --target-*

Promotion automatique

Minimiser le temps d’interruption du service en cas d’avarie

Promotion automatique : vocabulaire

  • SPOF : Single Point Of Failure
  • Redondance : pour éviter les SPOF
  • Ressources : éléments gérés par un cluster
  • Split brain : deux primaires ! et perte de données
  • Fencing : isoler un serveur défaillant
  • STONITH : Shoot The Other Node In The Head (voir Fencing)
  • Watchdog : permet à un serveur de s’auto isoler
  • Quorum : participe à la résolution des partitions réseau

Patroni

  • Outil de HA
  • Basé sur un gestionnaire de configuration distribué : etcd, Consul, ZooKeeper…
  • Contexte physique, VM ou container
  • Spilo : image docker PostgreSQL+Patroni

repmgr

  • Outil spécialisé PostgreSQL
  • En pratique, fiable pour 2 nœuds
  • Gère automatiquement la bascule en cas de problème
    • health check
    • failover et switchover automatiques
  • Witness

Pacemaker

  • Solution de Haute Disponibilité généraliste
  • Disponible sur les distributions les plus répandues
  • Se base sur Corosync, un service de messagerie inter-nœuds
  • Permet de surveiller la disponibilité des machines
  • Gère le quorum, le fencing, le watchdog et le SBD
  • Gère les ressources d’un cluster et leur interdépendance
  • Extensible

PAF

  • Postgres Automatic Failover
  • Ressource Agent pour Pacemaker et Corosync permettant de :
    • détecter un incident
    • relancer l’instance primaire
    • basculer sur un autre nœud en cas d’échec de relance
    • élire le meilleur secondaire (avec le retard le plus faible)
    • basculer les rôles au sein du cluster en primaire et secondaire
  • Avec les fonctionnalités offertes par Pacemaker & Corosync :
    • surveillance de la disponibilité du service
    • quorum & Fencing
    • gestion des ressources du cluster

Conclusion

De nombreuses applications tierces peuvent nous aider à administrer efficacement un cluster en réplication.

Questions

N’hésitez pas, c’est le moment !

Travaux pratiques

(Pré-requis) Environnement

Promotion d’une instance secondaire

Suivi de timeline

pg_rewind

pgBackRest

Travaux pratiques (solutions)

Réplication logique

Objectifs

  • Réplication logique native
    • connaître les avantages et limites
    • savoir la mettre en place
    • savoir l’administrer et la superviser
  • Connaître d’autres outils de réplication logique

Au menu

  • Principes
  • Mise en place
  • Exemple
  • Administration
  • Supervision
  • Migration majeure avec la réplication logique
  • Limitations

Principes de la réplication logique native

  • Résout certaines des limitations de la réplication physique
  • Base sur le logical decoding
  • Réplication partielle des données
    • vers autre un PG différent/ouvert en écriture
  • Préférer PostgreSQL >= 14 et le plus récent possible

Réplication physique vs. logique

Physique Logique
Instance complète Tables aux choix
Par bloc Par ligne/colonnes
Asymétrique (1 principal) Asymétrique / croisée
Depuis primaire ou secondaire Depuis primaire ou secondaire (v16)
Toutes opérations Opération au choix
Réplica identique Destination modifiable
Même architecture -
Mêmes versions majeures -
Synchrone/Asynchrone Synchrone/Asynchrone

Schéma de principe de la réplication logique

Quelques termes essentiels

  • Serveur origine (publieur/éditeur)
    • publication
  • Serveur(s) abonné(s) (subscriber)
    • abonnement/souscription (subscription)

Réplication logique et streaming

La réplication logique utilise le streaming :

  • wal_level = logical
  • Processus wal sender
    • mais pas de wal receiver
    • un logical replication worker à la place
  • Décodage logique des journaux
  • Asynchrone / synchrone
  • Slots de réplication

Granularité de la réplication logique

  • Par table
    • toutes les tables d’une base
    • toutes les tables d’un schéma (v15+)
    • quelques tables spécifiques
  • Granularité d’une table
    • table complète
    • même partitionnée
    • uniquement certaines lignes/colonnes (v15+)
  • Par opération
    • INSERT, UPDATE, DELETE, TRUNCATE

Possibilités sur les tables répliquées

  • Possibilités
    • index supplémentaires
    • modification des valeurs
    • colonnes supplémentaires
    • triggers également activables sur la table répliquée
  • Attention à la cohérence des modèles
  • Attention à ne pas bloquer la réplication logique !
    • pg_stat_subscription_stats (v15+)
    • disable_on_error = on (v15+)
    • aller au plus simple

Limitations de la réplication logique

  • Pas de réplication des requêtes DDL
    • à refaire manuellement
    • être rigoureux et surveiller les traces !
  • Pas de réplication des valeurs des séquences
  • Pas de réplication des LO (table système)
  • PK/UK conseillée pour les UPDATE/DELETE
  • Coût CPU, disque, RAM
  • Réplication déclenchée uniquement lors du COMMIT (< v14)
  • Attention en cas de migration/bascule/restauration ! (<v17)

Mise en place

Étapes :

  • Configuration du serveur origine
  • Configuration du serveur destination
  • Création d’une publication
  • Ajout d’une souscription

Configurer le serveur origine : utilisateur de réplication

CREATE ROLE logrepli LOGIN REPLICATION ;
GRANT SELECT ON ALL TABLES IN SCHEMA monschema TO logrepli ;
# pg_hba.conf
host base_publication  logrepli XXX.XXX.XXX.XXX/XX scram-sha-256

Configurer le serveur origine : postgresql.conf

  • wal_level = logical
    • redémarrage
  • logical_decoding_work_mem = 64MB
    • en deçà : RAM jusque COMMIT
    • puis disque
    • ou transmission immédiate (v14+)

Configuration du serveur destination

  • Création, si nécessaire, des tables répliquées
pg_dump -h origine -s -t la_table la_base | psql la_base

Créer une publication

CREATE PUBLICATION pub_t1     FOR TABLE t1 ;
CREATE PUBLICATION pub_t1part FOR TABLE t1 (c1, c3);  -- v15
CREATE PUBLICATION pub_tout   FOR ALL TABLES ;
CREATE PUBLICATION pub_public FOR TABLES IN SCHEMA public ; -- v15
CREATE PUBLICATION pub_filtree
FOR TABLE employes  WHERE ( ville = 'Brest' ) ; --v15
WITH ( publish = 'update, delete, insert, truncate')  -- défaut
WITH (publish_via_partition_root = false)  -- défaut

Souscrire à une publication

CREATE SUBSCRIPTION nom
    CONNECTION 'infos_connexion'
    PUBLICATION nom_publication [, ...]
    [ WITH ( parametre_souscription [= value] [, ... ] ) ]
  • infos_connexion : chaîne de connexion habituelle
  • Par : superutilisateur ou pg_create_subscription

Options de la souscription (1/2)

Par défaut :

  • connect = true
    • connexion immédiate
  • copy_data = true
    • copie initiale des données
  • enabled = true
    • activation immédiate de la souscription
  • create_slot = true
    • création du slot de réplication
  • slot_name = <nom de la souscription>
    • nom du slot de réplication

Options de la souscription (2/2)

Par défaut :

  • streaming = off
    • true pour envoyer les modifications avant COMMIT
    • évite de gros fichiers sur le primaire
    • parallel: plusieurs workers (v16+)
  • binary = off
    • pour envoyer les données sous un format binaire
  • disable_on_error = false
    • désactivation de la souscription en cas d’erreurs détectées
  • synchronous_commit = off
    • surcharge synchronous_commit pour les wal sender

Mise en place : exemple

  • Réplication complète d’une base
  • Réplication partielle d’une base
  • Réplication croisée

Serveurs et schéma

  • 4 serveurs
    • s1, 192.168.10.1 : origine de toutes les réplications, et destination de la réplication croisée
    • s2, 192.168.10.2 : destination de la réplication complète
    • s3, 192.168.10.3 : destination de la réplication partielle
    • s4, 192.168.10.4 : origine et destination de la réplication croisée
  • Schéma
    • 2 tables ordinaires
    • 1 table partitionnée, avec trois partitions

Réplication complète

  • Configuration du serveur origine
  • Configuration du serveur destination
  • Création de la publication
  • Ajout de la souscription

Configuration du serveur origine (1/2)

  • Création et configuration de l’utilisateur de réplication
CREATE ROLE logrepli LOGIN REPLICATION;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO logrepli;
  • Fichier postgresql.conf
wal_level = logical

Configuration du serveur origine (2/2)

  • Fichier pg_hba.conf
host b1 logrepli 192.168.10.0/24 trust
  • En prod : mot de passe et .pgpass
  • Redémarrer le serveur origine

Configuration des 4 serveurs destinations

  • Création de l’utilisateur de réplication
CREATE ROLE logrepli LOGIN REPLICATION;
  • Création des tables répliquées (sans contenu)
createdb -h s2 b1
pg_dump -h s1 -s b1 | psql -h s2 b1

Créer une publication complète

  • Création d’une publication de toutes les tables de la base b1 sur le serveur origine s1
CREATE PUBLICATION publi_complete
  FOR ALL TABLES;

Souscrire à la publication

  • Souscrire sur s2 à la publication de s1
CREATE SUBSCRIPTION subscr_complete
  CONNECTION 'host=192.168.10.1 user=logrepli dbname=b1'
  PUBLICATION publi_complete;
  • Un slot de réplication est créé sur l’origine
  • Les données initiales sont immédiatement transférées

Tests de la réplication complète

  • Insertion, modification, suppression sur les différentes tables de s1
  • Vérifications sur s2
    • toutes doivent avoir les mêmes données entre s1 et s2

Réplication partielle

  • Identique à la réplication complète, sauf…
  • Créer la publication partielle
CREATE PUBLICATION publi_partielle
  FOR TABLE t1,t2 ;
  • Souscrire sur s3 à cette nouvelle publication de s1
CREATE SUBSCRIPTION subscr_partielle
  CONNECTION 'host=192.168.10.1 user=logrepli dbname=b1'
  PUBLICATION publi_partielle;

Réplication croisée

  • Écrire sur une table sur s1
    • et répliquer sur s4
  • Écrire sur une (autre) table sur s4
    • et répliquer sur s1
  • Pour compliquer :
    • on utilisera la table partitionnée

Réplication de t3_1 de s1 vers s4

  • Créer la publication partielle sur s1
CREATE PUBLICATION publi_t3_1
  FOR TABLE t3_1;
  • Y souscrire sur s4
CREATE SUBSCRIPTION subscr_t3_1
  CONNECTION 'host=192.168.10.1 user=logrepli dbname=b1'
  PUBLICATION publi_t3_1;
  • Configurer s4 comme serveur origine
    • wal_level , pg_hba.conf

Réplication de t3_2 de s4 vers s1

  • Créer la publication partielle sur s4
CREATE PUBLICATION publi_t3_2
  FOR TABLE t3_2;
  • Y souscrire sur s1
CREATE SUBSCRIPTION subscr_t3_2
  CONNECTION 'host=192.168.10.4 user=logrepli dbname=b1'
  PUBLICATION publi_t3_2;

Tests de la réplication croisée

  • Insertion, modification, suppression sur t3 (partition 1) sur s1
    • Vérifications sur s4 : les nouvelles données doivent être présentes
  • Insertion, modification, suppression sur t3 (partition 2) sur s4
    • Vérifications sur s1 : les nouvelles données doivent être présentes

pg_createsubscriber

  • Outil pour PostgreSQL 17 +
  • Transforme un réplica physique (arrêté) en serveur abonné
  • Une publication et un abonnement par base
  • Pour :
    • les grosses bases à répliquer intégralement
    • version majeure identique
    • migration majeure (pg_createsubscriber+pg_upgrade)

Administration

  • Processus
  • Fichiers
  • Procédures
    • Empêcher les écritures sur un serveur destination
    • Que faire pour les DDL ?
    • Gérer les opérations de maintenance
    • Gérer les sauvegardes

Processus

  • Serveur origine
    • wal sender
  • Serveur destination
    • logical replication launcher
    • logical replication worker

Synthèse des paramètres sur le serveur origine

Paramètre Valeur
wal_level logical
logical_decoding_work_mem 64MB ou plus
max_slot_wal_keep_size 0 (à ajuster)
idle_replication_slot_timeout 0 (à ajuster)
wal_sender_timeout 1 min
max_wal_senders 10 (parfois à ajuster)
max_replication_slots 10 (parfois à ajuster)

Synthèse des paramètres sur le serveur destination

Paramètre Valeur
max_worker_processes 8 (parfois à ajuster)
max_logical_replication_workers 4 (parfois à ajuster)
max_active_replication_origins 10 (parfois à ajuster)

Fichiers (serveur origine)

  • 2 répertoires importants
  • pg_replslot
    • slots de réplication
    • 1 répertoire par slot (+ slots temporaires)
    • 1 fichier state dans le répertoire
    • fichiers .spill (volumétrie !)
  • pg_logical
    • métadonnées

Empêcher les écritures sur un serveur destination

  • Par défaut, toutes les écritures sont autorisées sur le serveur destination
    • y compris écrire dans une table répliquée avec un autre serveur comme origine
  • Problèmes
    • serveurs non synchronisés
    • blocage de la réplication en cas de conflit sur la clé primaire
  • Solution
    • révoquer le droit d’écriture sur le serveur destination
    • mais ne pas révoquer ce droit pour le rôle de réplication !

Que faire pour les DDL ?

  • Les opérations DDL ne sont pas répliquées
  • De nouveaux objets ?
    • les déclarer sur tous les serveurs du cluster de réplication
    • tout du moins, ceux intéressés par ces objets
  • Changement de définition des objets ?
    • à réaliser sur chaque serveur

Que faire pour les nouvelles tables ?

  • Créer la table sur origine et destination
  • Éviter de modifier la publication à chaud
    • bug d’invalidation du cache corrigé (≥ source v13)
  • Publication FOR ALL TABLES/FOR TABLES IN SCHEMA
    • prise en compte automatique ajouter la table aux souscriptions concernées :
    -- origine
    ALTER PUBLICATIONADD TABLE …, TABLE … ;
    ALTER SUBSCRIPTIONREFRESH PUBLICATION ;

Comment ajouter une nouvelle colonne ?

    1. Ajouter la colonne sur l’abonné
    1. Puis ajouter la colonne sur le publieur
  • Si le contraire : pas grave, la réplication reprendra une fois les colonnes ajoutées

Comment supprimer une colonne ?

    1. Supprimer la colonne sur le publieur
    1. Supprimer la colonne sur l’abonné
  • Si le contraire : pas grave, la réplication reprendra une fois les colonnes supprimées

Comment ajouter une nouvelle contrainte ?

    1. Ajouter la contrainte sur le publieur
    1. Ajouter la contrainte sur l’abonné
  • Si incohérence : bloquage de la réplication

Comment corriger une erreur de réplication ?

  • Si les données diffèrent entre les serveurs, il faut corriger manuellement les données
  • Si blocage
    • publication arrêtée
    • pas de recyclage des journaux → accumulation → danger !
  • Puis, avancer le pointeur du slot de réplication
    • fonction pg_replication_slot_advance()
    • outil pg_waldump ou extension pg_walinspect

Gérer les opérations de maintenance

  • À faire séparément sur tous les serveurs
  • VACUUM, ANALYZE, REINDEX

Gérer les sauvegardes & restaurations logiques

  • pg_dumpall et pg_dump
    • sauvegardent publications et souscriptions
    • options --no-publications et --no-subscriptions
  • Restauration d’une publication :
    • nouveau slot de réplication !
    • réconciliation de données à prévoir
  • Restauration d’un abonnement :
    • ENABLE et REFRESH PUBLICATION
    • reprendre à zéro la copie… ou copier manuellement ?

Gérer les bascules & les restaurations physiques

Comme pour la réplication physique :

  • Sauvegarde PITR
    • publications et souscriptions
    • slots ?
  • Slots perdus et « trous » dans la réplication si :
    • bascule origine
    • restauration origine
    • restauration destination
  • Contrôle délicat !
    • interdire les écritures à ces moments ?
  • Bascule de la destination
    • si propre, devrait mieux se passer

Réplication logique depuis un secondaire comme origine

  • Depuis PostgreSQL 16
  • wal_level = logical sur le secondaire/origine
  • Création de la publication toujours sur le primaire
  • Le secondaire porte le slot et décode
  • Latence supplémentaire

Combien de réplications logiques ?

  • 1 publication logique = 1 walsender + 1 slot par abonné
  • Chaque worker doit décoder les WAL
    • attention au CPU et à la RAM !
  • Risques de slots bloqués
  • Contournements :
    • regrouper les réplications
    • réplication depuis un secondaire
    • streaming = on

Supervision

  • Méta-données
  • Statistiques
  • Outils

Catalogues systèmes - méta-données

  • pg_publication
    • définition des publications
    • \dRp sous psql
  • pg_publication_tables
    • tables ciblées par chaque publication
  • pg_subscription
    • définition des souscriptions
    • \dRs sous psql

État de la réplication

Dans la base destination :

  • pg_subscription_rel
    • statut de la copie/synchronisation
  • La réplication fonctionne-t-elle ?
    • il y aura toujours un retard
    • calcul par les LSN

Vues statistiques (origine)

Sur l’origine :

  • pg_stat_replication
    • lag, retards, statut…
  • pg_replication_slots
    • slots de réplication : statut
  • pg_stat_replication_slots
    • volumes écrits/envoyés en streaming via les slots de réplication logique

Vues statistiques (destination)

Dans la destination :

  • pg_stat_subscription
    • état des souscriptions
  • pg_replication_origin_status
    • statut des origines de réplication
  • pg_stat_database_conflicts (si origine est un secondaire)

Outils de supervision

  • check_pgactivity
    • replication_slots
  • check_postgres
    • same_schema

Migration majeure par réplication logique

  • Possible entre versions 10 et supérieures
  • Remplace la réplication par trigger (Slony, Bucardo…)
  • Bascule très rapide
  • Et retour possible
  • Des limitations
  • Futur : pg_createsubscriber + pg_upgrade (>v17)

Autres modules de décodage logique

Rappel des limitations de la réplication logique native

  • Pas de réplication : DDL, LO, valeurs de séquence
  • Contraintes d’unicité obligatoires pour les UPDATE/DELETE
  • Coût CPU, disque, RAM
  • Réplication déclenchée uniquement lors du COMMIT (< v14)
  • Que faire lors des restaurations/bascules ?

Conclusion

  • Réplication logique simple et pratique
    • …avec ses subtilités

Questions

N’hésitez pas, c’est le moment !

Quiz

Travaux pratiques

Pré-requis

Réplication complète d’une base

Réplication partielle d’une base

Réplication croisée

Réplication et partitionnement

Travaux pratiques (solutions)