# _Réplication Logique_ avec PostgreSQL ## Mise en place Sur le serveur primaire et réplica, on s'assure d'avoir deux bases : ~~~ postgres $ createuser -p 5432 -P foo Enter password for new role: postgres $ createdb -p 5432 -O foo foo ~~~ Sur le serveur primaire, on modifie la directive `wal_level` : ~~~ wal_level = logical ~~~ Puis l'on crée un utilisateur `replication` et une publication liée à cette base : ~~~ postgres $ createuser -p 5432 -P --replication replication postgres $ psql -p 5432 foo foo=# GRANT SELECT on ALL TABLES IN SCHEMA public TO replication; GRANT foo=# CREATE PUBLICATION alltables FOR ALL TABLES; CREATE PUBLICATION ~~~ Sur le serveur réplica, on crée une subscription liée à cette base : ~~~ postgres $ psql -p 5432 foo foo=# CREATE SUBSCRIPTION mysub CONNECTION 'dbname=foo host=192.0.2.1 port=5436 user=replication password=PASSWORD' PUBLICATION alltables; NOTICE: created replication slot "mysub" on publisher CREATE SUBSCRIPTION ~~~ Attention, contrairement à la réplication physique, rien n'empêche d'écrire sur le serveur réplica. Ensuite, il faut créer les tables de façon identique sur les deux bases : ~~~ postgres $ psql -U foo -h 127.0.0.1 -p 5432 foo foo=> CREATE TABLE t (a INT); ~~~ Enfin, l'insertion de données sur le serveur primaire, devrait provoquer le transfert de ces données sur le serveur réplica : ~~~ LOG: logical replication table synchronization worker for subscription "mysub", table "t" has started ~~~ Si besoin, on peut « rafraichir » la subscription sur le serveur replica via la commande : ~~~ postgres $ psql -p 5432 foo foo=# ALTER SUBSCRIPTION mysub REFRESH PUBLICATION; ~~~ ## Administration ### Ajout / modification d'une table Si l'on veut ajouter ou modifier une table, il faut : - créer / modifier la table sur les 2 serveurs maître et réplica - relancer la commande suivante sur le serveur maître : ~~~ postgres $ psql -p 5432 foo foo=# GRANT SELECT on ALL TABLES IN SCHEMA public TO replication; GRANT ~~~ - relancer la commande suivante sur le serveur réplica : ~~~ postgres $ psql -p 5432 foo foo=# ALTER SUBSCRIPTION mysub REFRESH PUBLICATION; ~~~ On peut ensuite insérer des données sur la nouvelle table qui sera répliquée. ### Suspendre une réplication Mettre en pause une réplication : ~~~ foo=# ALTER SUBSCRIPTION mysub DISABLE; LOG: le processus apply de réplication logique pour la souscription « mysub » s'arrêtera car la souscription a été désactivée ~~~ Reprendre une réplication : ~~~ foo=# ALTER SUBSCRIPTION mysub ENABLE; ~~~ ### Suppression ~~~ DROP PUBLICATION alltables; DROP SUBSCRIPTION mysub; ~~~ ### Ajout d'un schema à une base / utilisateur répliqué Si l'on ajoute un schéma à une base répliqué, pour que la syncho des données de ce shcéma se fasse, il faut que l'utilisateur SQL dédié à la réplication est le droit **USAGE** sur ce schéma : ~~~ foo=# GRANT USAGE ON SCHEMA bar TO replication; ~~~ Sinon la copié initiale des données de ce schéma n'est pas copié dans la réplication, on auras des erreurs de ce type dans les logs sur le master : ~~~ 2020-05-30 00:06:26.163 CEST [40846] replication@foo ERROR: permission denied for schema bar 2020-05-30 00:06:26.163 CEST [40846] replication@foo STATEMENT: COPY bar."21GEHAVL" TO STDOUT ~~~ Sur le réplica on aura des erreurs de ce type : ~~~ 020-05-30 15:55:57.594 CEST [986] LOG: le processus de synchronisation des tables en réplication logique pour la souscription « mysub_sql3 », table « 21NOHAII » a démarré 2020-05-30 15:55:57.601 CEST [985] ERREUR: n'a pas pu lancer la copie initiale du contenu de la table « bar.21GEHVRH » : ERROR: permission denied for schema bar ~~~ ## Monitoring Sur le serveur replica, on peut surveiller le bon fonctionnement de la réplication ainsi : ~~~ postgres=# select * from pg_subscription ; subdbid | subname | subowner | subenabled | subconninfo | subslotname | subsynccommit | subpublications ---------+---------+----------+------------+----------------------------------------------------------------------------+-------------+---------------+----------------- 16385 | mysub | 10 | t | dbname=foo host=192.0.2.1 port=5432 user=replication password=PASSWORD | mysub | off | {alltables} (1 row) postgres=# select * from pg_stat_subscription ; subid | subname | pid | relid | received_lsn | last_msg_send_time | last_msg_receipt_time | latest_end_lsn | latest_end_time -------+---------+-------+-------+--------------+-------------------------------+-------------------------------+----------------+------------------------------- 16388 | mysub | 12767 | | 0/16A58D8 | 2019-09-17 21:09:16.512057+00 | 2019-09-17 21:09:16.512241+00 | 0/16A58D8 | 2019-09-17 21:09:16.512057+00 ~~~