Réplication logique

Module W5

Dalibo SCOP

24.12

18 décembre 2024

Sur ce document

Formation Module W5
Titre Réplication logique
Révision 24.12
PDF https://dali.bo/w5_pdf
EPUB https://dali.bo/w5_epub
HTML https://dali.bo/w5_html
Slides https://dali.bo/w5_slides
TP https://dali.bo/w5_tp
TP (solutions) https://dali.bo/w5_solutions

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
  • 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 13 à 17.

Réplication logique

PostgreSQL

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 (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
    • rédémarrage
  • logical_decoding_work_mem = 64MB
    • en-deça : 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, v13

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
  • create_slot = true
    • création du slot de réplication
  • enabled = true
    • activation immédiate de la souscription
  • 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 (v14+)
    • évite de gros fichiers sur le primaire
    • parallel: plusieurs workers (v16+)
  • binary = off (v14+)
    • 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 logique (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)
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)

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
  • Publication FOR ALL TABLES/FOR TABLES IN SCHEMA
    • prise en compte automatique ajouter la table aux souscriptions concernées :
    -- origine
    ALTER PUBLICATION … ADD TABLE …, TABLE … ;
    ALTER SUBSCRIPTION … REFRESH 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

Vues statistiques

  • pg_stat_replication
    • statut de réplication
  • pg_replication_slots
    • slots de réplication : statut
  • pg_stat_replication_slots (v14)
    • volumes écrits/envoyés en streaming via les slots de réplication logique
  • 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)