Solutions 
Le prompt # indique une commande à exécuter avec l'utilisateur root. Le prompt $ est utilisé pour les commandes de l'utilisateur postgres.
Quelques informations sur la solution proposée ici 
Cette solution se base sur un système CentOS 6, installé à minima. Des adaptations seraient à faire pour un autre système (Linux ou Windows).
La solution apportée ici se base beaucoup sur la commande sudo qui permet à un utilisateur d'exécuter des commandes que seul un autre utilisateur est habituellement permis à exécuter. Si sudo n'est pas installé, son installation est donc conseillée :
La configuration de sudo se fait avec la commande visudo. Le but est d'ajouter la ligne suivante :
utilisateur ALL=(ALL) ALLEn remplaçant utilisateur par le nom de l'utilisateur à qui on veut autoriser l'exécution de toute commande via la commande sudo.
Le site postgresql.org propose son propre dépôt RPM, nous allons donc l'utiliser.
# yum install -y https://download.postgresql.org/pub/repos/yum 
           /testing/10/redhat/rhel-6-x86_64/pgdg-centos10-10-1.noarch.rpm 
Retrieving  https://download.postgresql.org/pub/repos/yum
           /testing/10/redhat/rhel-6-x86_64/pgdg-centos10-10-1.noarch.rpm 
warning : /var/tmp/rpm-tmp.RxZogq: Header V4 DSA/SHA1 Signature,
                                   key  ID 442df0f8: NOKEY
Preparing...                 ########################################**[100%]
   1 :pgdg-centos10          ########################################**[100%]# yum install -y postgresql10-server postgresql10-contrib Les paquets suivants seront installés :
(1/12): libicu-4.2.1-14.el6.x86_64.rpm
(2/12): libxslt-1.1.26-2.el6_3.1.x86_64.rpm
(3/12): perl-5.10.1-144.el6.x86_64.rpm
(4/12): perl-Module-Pluggable-3.90-144.el6.x86_64.rpm
(5/12): perl-Pod-Escapes-1.04-144.el6.x86_64.rpm
(6/12): perl-Pod-Simple-3.13-144.el6.x86_64.rpm
(7/12): perl-libs-5.10.1-144.el6.x86_64.rpm
(8/12): perl-version-0.77-144.el6.x86_64.rpm
(9/12): postgresql10-10.0-beta4_1PGDG.rhel6.x86_64.rpm
(10/12): postgresql10-contrib-10.0-beta4_1PGDG.rhel6.x86_64.rpm
(11/12): postgresql10-libs-10.0-beta4_1PGDG.rhel6.x86_64.rpm
(12/12): postgresql10-server-10.0-beta4_1PGDG.rhel6.x86_64.rpmRéplication asynchrone avec un seul secondaire  Commençons par créer une instance PostgreSQL 10 :
# service postgresql-10 initdb
Initialisation de la base de données :                     [  OK  ]Il reste maintenant à configurer ce serveur pour qu'il archive les journaux de transactions. Mais tout d'abord, il faut créer le répertoire d'archivage.
$ mkdir  /var/lib/pgsql/10/archivesLa commande ayant été exécutée par l'utilisateur postgres, les droits sont automatiquement bons.
Modifions maintenant le fichier /var/lib/pgsql/10/data/postgresql.conf pour que PostgreSQL archive les journaux de transactions et écrive ses logs en anglais. Voici les modifications à apporter :
archive_mode = on
archive_command = 'rsync %p /var/lib/pgsql/10/archives/%f'
lc_messages = 'C'
La commande rsync n'est pas installée par défaut. S'il est nécessaire de l'installer, voici la commande adéquate :
 
Le paramètre archive_mode étant modifié, il nous faut redémarrer PostgreSQL :
# service postgresql-10 start
Démarrage du service postgresql-10 :                      [  OK  ]Forçons PostgreSQL à changer de journal de transactions, pour voir si l'archivage fonctionne bien :
$ psql -c "SELECT pg_switch_wal()" 
 pg_switch_wal
---------------- 
 0 /168B71C
(1  row )
$ ls -l /var/lib/pgsql/10 /archives/
total 16384 
-rw------- 1 postgres postgres 16777216 Sep 29 10:04 000000010000000000000001 Parfait.
La valeur renvoyée par la fonction pg_switch_wal() peut varier suivant la quantité de données écrites précédemment par PostgreSQL.
 
Maintenant que l'archivage fonctionne, ajoutons un secondaire. Nous pourrions utiliser pg_basebackup, c'est d'ailleurs ce qu'on fera pour le troisième secondaire. Nous allons le faire manuellement pour cette fois.
Tout d'abord, nous devons utiliser la procédure stockée pg_start_backup() :
$ psql -c "SELECT pg_start_backup('un_label', true)" 
 pg_start_backup
----------------- 
 0 /2000028 
(1  row )Ensuite, il faut copier le répertoire des données :
$ cp  -rp /var/lib/pgsql/10/data /var/lib/pgsql/10/secondaire1Il est possible d'appeler pg_stop_backup() :
$ psql -c "SELECT pg_stop_backup()" 
NOTICE:  pg_stop_backup complete , all  required WAL segments have been archived
 pg_stop_backup
---------------- 
 0 /20000B8
(1  row )Sur CentOS, les fichiers de configuration se trouvent dans le répertoire de données, ils sont donc copiés automatiquement. Cependant, avant d'aller plus loin et de procéder à la configuration de la mise en réplication, il faut configurer cette instance pour démarrer sur le port 5433 et lui permettre de démarrer automatiquement.
Le fichier /etc/sysconfig/pgsql/secondaire1 va permettre de définir l'emplacement de l'instance et son port d'écoute par défaut :
PGDATA=/var/lib/pgsql/10/secondaire1
PGPORT=5433Il faut également positionner le paramètre port dans le fichier de configuration /var/lib/pgsql/10/secondaire1/postgresql.conf :
port=5433Enfin, il faut créer le script de démarrage /etc/init.d/secondaire1 qui nous permettra de démarrer l'instance :
# ln -s /etc/init.d/postgresql-10 /etc/init.d/secondaire1 Il ne reste plus qu'à configurer la restauration dans le fichier recovery.conf. Attention, ce dernier, contrairement aux autres, se trouvera dans le répertoire des données (donc ici /var/lib/postgresql/10/secondaire1). Pour se faciliter la vie, nous allons copier le fichier d'exemple :
$ cp  /usr/pgsql-10/share/recovery.conf.sample \
     /var/lib/pgsql/10/secondaire1/recovery.confEnfin, il reste à configurer le fichier /var/lib/pgsql/10/secondaire1/recovery.conf en modifiant ces paramètres :
restore_command = 'cp /var/lib/pgsql/10/archives/%f %p'
standby_mode = onUn peu de ménage au niveau des fichiers du secondaire :
$ rm  /var/lib/pgsql/10/secondaire1/postmaster.pid
     /var/lib/pgsql/10/secondaire1/pg_wal/* Le message d'erreur sur le répertoire archive_status peut être ignoré sans conséquence.
Il ne reste plus qu'à démarrer le secondaire :
# service secondaire1 start
Démarrage du service secondaire1 :                            [  OK  ]La commande ps suivante permet de voir que les deux serveurs sont lancés :
La première partie concerne le serveur secondaire :
PID CMD
881 /usr/pgsql-10/bin/postmaster -D /var/lib/pgsql/10/secondaire1
883  \_ postgres: logger process                                     
884  \_ postgres: startup process   waiting for 000000010000000000000006
886  \_ postgres: checkpointer process                               
887  \_ postgres: writer process                                     
888  \_ postgres: stats collector process                La deuxième partie concerne le serveur principal :
PID CMD
535 /usr/pgsql-10/bin/postmaster -D /var/lib/pgsql/10/data
537  \_ postgres: logger process                              
539  \_ postgres: checkpointer process                        
540  \_ postgres: writer process                              
541  \_ postgres: wal writer process                          
542  \_ postgres: autovacuum launcher process                 
543  \_ postgres: archiver process   last was 000000010000000000000005.00000028.backup
544  \_ postgres: stats collector process                     
545  \_ postgres: bgworker: logical replication launcher   Pour différencier les deux instances, il est possible d'identifier le répertoire de données (l'option -D), les autres processus sont des fils du processus postmaster. Il est aussi possible de configurer le paramètre cluster_name.
Le processus de démarrage (startup process ) indique qu'il attend le journal 000000010000000000000006. Pour le récupérer, il exécute la restore_command en indiquant le journal à récupérer.
Lançons un peu d'activité sur le principal pour générer (et surtout archiver) quelques journaux de transactions :
$ createdb b1
$ psql b1
psql (10)
Type "help" for help.
b1=# CREATE TABLE t1(id integer);
CREATE TABLE
b1=# INSERT INTO t1 SELECT generate_series(1, 1000000);
INSERT 0 1000000
b1=# \! ps -o pid,cmd fx | egrep "(archiver|startup)"
  884  \_ postgres: startup process   waiting for 000000010000000000000007
  543  \_ postgres: archiver process   last was 000000010000000000000006
[...]Le processus d'archivage (« archiver process ») a archivé le journal 000000010000000000000006. Le secondaire attend donc le suivant, à savoir le 000000010000000000000007. Les journaux applicatifs indiquent ceci :
$ grep "restored log file" /var/lib/pgsql/10/secondaire1/log/postgresql*.log
2017-09-06 10:13:32.862 EDT [790] LOG: restored log file 
                                       "000000010000000000000003" from archive
2017-09-06 10:14:30.358 EDT [884] LOG: restored log file 
                                       "000000010000000000000004" from archive
2017-09-06 10:44:07.671 EDT [884] LOG: restored log file 
                                       "000000010000000000000005" from archive
2017-09-06 10:44:10.069 EDT [884] LOG: restored log file 
                                       "000000010000000000000006" from archiveEssayons de nous connecter au secondaire et d'exécuter quelques requêtes :
$ psql -p 5433 
psql (10 )
Type  "help"  for  help.
postgres=# SELECT  * FROM  pg_tablespace;
  spcname   | spcowner | spcacl | spcoptions
------------+----------+--------+------------ 
 pg_default |       10  |        |
 pg_global  |       10  |        |
(2  rows )
postgres=# CREATE  TABLE  t1(id  integer );
ERROR:  cannot execute  CREATE  TABLE  in  a read-only transaction On peut se connecter, lire des données, mais pas écrire.
Le comportement est visible dans les logs de l'instance secondaire dans le répertoire /var/lib/pgsql/10/secondaire1/log :
2017-09-06 10:05:44.546 EDT [535] LOG: database system is ready to accept connectionsPostgreSQL indique bien qu'il accepte des connexions en lecture seule.
Réplication asynchrone avec un seul secondaire en Warm Standby  
Depuis la version 10, le comportement de PostgreSQL a changé et un secondaire sera par défaut en Hot Standby . Un secondaire sera donc accessible par défaut en lecture seule. Pour désactiver ce comportement, il faut passer le paramètre hot_standby à off sur le secondaire.
Il faut redémarre l'instance secondaire pour prendre en comtpe les changements :
# service secondaire1 restart
Stopping secondaire1 service:                              [  OK  ]
Starting secondaire1 service:                              [  OK  ]$ ps -o pid,cmd fx | egrep "(archiver|startup)"
  884  \_ postgres: startup process   waiting for 000000010000000000000007
  543  \_ postgres: archiver process   last was 000000010000000000000006
[...]Si nous essayons de nous connecter à l'instance nous obtenons le message :
$ psql -p 5433
psql: FATAL:  the database system is starting upIl est impossible de se connecter à l'instance en Warm Standby 
Réplication asynchrone en flux avec un seul secondaire 
Depuis la version 10, le comportement de PostgreSQL a changé et la réplication est activée par défaut en local.
Nous allons cependant modifier le fichier /var/lib/pgsql/10/data/pg_hba.conf pour que l'accès en réplication soit autorisé pour l'utilisateur repli :
host  replication  repli  127.0.0.1/32  md5Cette configuration indique que l'utilisateur repli peut se connecter en mode réplication à partir de l'adresse IP 127.0.0.1. L'utilisateur repli n'existant pas, il faut le créer (nous utiliserons le mot de passe repli ) :
$ createuser -SRD --replication -P repli
Enter password for new role:
Enter it again:Pour prendre en compte la configuration, la configuration de l'instance principale doit être rechargée :
$ psql  -c 'SELECT pg_reload_conf()' Maintenant, il faut configurer le secondaire pour qu'il se connecte au principal. Cela se fait au travers du fichier /var/lib/pgsql/10/secondaire1/recovery.conf et voici les paramètres à modifier :
restore_command = 'cp /var/lib/pgsql/10/archives/%f %p'
standby_mode = on
primary_conninfo = 'host=127.0.0.1 port=5432 user=repli password=repli'
trigger_file = '/tmp/secondaire1_autonome'Il faut que la restore_command renvoie un code retour différent de zéro pour indiquer au moteur qu'il n'y a plus de journaux de transaction et de passer en réplication en flux. Notez aussi que le fichier trigger_file ne doit pas exister. Une vérification est nécessaire avant de procéder à la suite.
Il ne reste plus qu'à redémarrer le secondaire :
# service secondaire1 restart Voici la liste des processus :
$ ps -o pid,cmd fx
  PID CMD
 4971 /usr/pgsql-10/bin/postmaster -D /var/lib/pgsql/10/secondaire1
 4973  \_ postgres: logger process                                     
 4974  \_ postgres: startup process   recovering 000000010000000000000006
 4976  \_ postgres: checkpointer process                               
 4977  \_ postgres: writer process                                     
 5006  \_ postgres: stats collector process                            
 5008  \_ postgres: wal receiver process   streaming 0/7000000         
 4634 /usr/pgsql-10/bin/postmaster -D /var/lib/pgsql/10/data
 4636  \_ postgres: logger process                              
 4638  \_ postgres: checkpointer process                        
 4639  \_ postgres: writer process                              
 4640  \_ postgres: wal writer process                          
 4641  \_ postgres: autovacuum launcher process                 
 4642  \_ postgres: archiver process   last was 000000010000000000000006
 4643  \_ postgres: stats collector process                     
 4644  \_ postgres: bgworker: logical replication launcher      
 5009  \_ postgres: wal sender process repli 127.0.0.1(45754) streaming 0/7D52830Nous avons bien les deux processus de réplication en flux wal sender et wal receiver.
Réplication asynchrone en flux avec deux secondaires 
Cette fois-ci, nous allons utiliser pg_basebackup pour créer le deuxième secondaire.
$ pg_basebackup -D /var/lib/pgsql/10/secondaire2 -P -h 127.0.0.1 -U repli
Password:
61401/61401 kB (100%), 1/1 tablespaceLes emplacements et le numéro de port du deuxième secondaire doit être différents des deux autres serveurs. Il faut donc créer le fichier /etc/sysconfig/pgsql/secondaire2 pour indiquer :
PGDATA=/var/lib/pgsql/10/secondaire2
PGPORT=5434Il faut également mettre en place le script de démarrage :
# ln -s /etc/init.d/postgresql-10 /etc/init.d/secondaire2 Il est aussi nécessaire de modifier le numéro de port d'écoute de l'instance dans /var/lib/pgsql/10/secondaire2/postgresql.conf :
port = 5434Le fichier de restauration doit être copié :
$ cp  /var/lib/pgsql/10/secondaire1/recovery.conf
     /var/lib/pgsql/10/secondaire2/recovery.conf Et légèrement modifié sur le nouvel secondaire :
trigger_file = '/tmp/secondaire2_autonome'Et on peut enfin démarrer le deuxième secondaire :
# service secondaire2 start Testons cette nouvelle architecture :
$ psql -p 5434 
psql (10 )
Type  "help"  for  help.
postgres=# SELECT  * FROM  pg_tablespace;
  spcname   | spcowner | spcacl | spcoptions
------------+----------+--------+------------ 
 pg_default |       10  |        |
 pg_global  |       10  |        |
(2  rows )
postgres=# CREATE  TABLE  t1(id  integer );
ERROR:  cannot execute  CREATE  TABLE  in  a read-only transaction 
postgres=# \c "port=5432 dbname=b1" 
Vous êtes maintenant connecté à la base de données « b1 » en tant qu'utilisateur 
« postgres » via le socket dans « /var/run/postgresql » via le port « 5432 ». 
b1=# INSERT INTO t1 SELECT generate_series(1, 1000); 
INSERT 0 1000 
postgres=# \c "port=5433 dbname=b1" 
Vous êtes maintenant connecté à la base de données « b1 » en tant qu' utilisateur
« postgres » via le socket dans « /var/run/postgresql » via le port « 5433  ».
b1=# SELECT  count (*) FROM  t1;
  count   
--------- 
 1001000 
(1  row )
b1=# \c "port=5434 dbname=b1" 
Vous êtes maintenant connecté à la base de données « b1 » en tant qu'utilisateur 
« postgres » via le socket dans « /var/run/postgresql » via le port « 5434 ». 
b1=# SELECT count(*) FROM t1; 
  count   
--------- 
 1001000 
(1 row) Nettoyage des journaux  Actuellement il n'y a aucun nettoyage des journaux archivés même s'ils ont été rejoués sur les secondaires. Quel paramètre modifier pour supprimer les anciens journaux ?
Le paramètre archive_cleanup_command du fichier recovery.conf permet de spécifier une commande exécutée à la fin d'un restartpoint (équivalent d'un checkpoint sur un secondaire). L'outil pg_archivecleanup est utilisé pour supprimer les journaux inutiles.
 
archive_cleanup_command =
     '/usr/pgsql-10/bin/pg_archivecleanup -d /var/lib/pgsql/10/archives/ %r'En générant de l'activité et en forçant des CHECKPOINT, le moteur va recycler ses journaux :
$ psql -c "INSERT INTO t1 SELECT * FROM generate_series(1,1000);"  b1
$ psql -c "CHECKPOINT;" 
$ psql -p 5433  -c "CHECKPOINT;" L'option -d permet d'avoir des informations supplémentaires dans les traces :
pg_archivecleanup: keeping WAL file "/var/lib/pgsql/10/archives//000000010000000000000062"
                   and later
pg_archivecleanup: removing file "/var/lib/pgsql/10/archives//000000010000000000000060"
pg_archivecleanup: removing file "/var/lib/pgsql/10/archives//00000001000000000000005F"
pg_archivecleanup: removing file "/var/lib/pgsql/10/archives//000000010000000000000061"
Sachant que les deux secondaires puisent leur journaux depuis le même répertoire d'archive. Quel pourrait être le risque ?
 
Le premier secondaire pourrait supprimer des journaux indispensables au deuxième secondaire. Sans ces journaux, la réplication du deuxième secondaire serait impossible et nécessiterait la reconstruction de celui-ci.
Slots de réplication  > Il est possible d'éviter d'avoir recours à l'archivage en utilisant les slots de réplication. Ces derniers permettent au serveur principal de connaître les journaux encore nécessaires au serveur secondaire.
Créer un slot de réplication et configurer le deuxième secondaire pour utiliser ce slot. Contrôler que le slot est bien actif.
 
Depuis la version 10, les slots de réplication sont activés par défaut. Le nombre maximum de slots est fixé à 10 :
# SHOW max_replication_slots;
 max_replication_slots 
-----------------------
 10
(1 row)La commande suivante permet de créer un slot de réplication sur le serveur principal :
$ psql -c "SELECT pg_create_physical_replication_slot('slot_secondaire2');" 
 pg_create_physical_replication_slot
------------------------------------- 
 (slot_secondaire2,)
(1  row )Il faut ensuite spécifier le slot dans le fichier recovery.conf :
primary_slot_name = 'slot_secondaire2'Puis redémarrer le serveur secondaire.
# service secondaire2 restart
Stopping secondaire2 service:                              [  OK  ]
Starting secondaire2 service:                              [  OK  ]Enfin, l'appel à la vue pg_replication_slots permet de s'assurer que le slot est bien actif :
postgres=# select  * from  pg_replication_slots ;
-[ RECORD  1  ]-------+----------------- 
slot_name           | slot_secondaire2
plugin              | 
slot_type           | physical
datoid              | 
database             | 
temporary            | f
active              | t
active_pid          | 1666 
xmin                | 
catalog_xmin        | 
restart_lsn         | 0 /62D5ACD8
confirmed_flush_lsn | 
Arrêter le deuxième secondaire et générer beaucoup d'activité. Où sont conservés les journaux de transaction ? Quel est le journal le plus ancien sur le serveur principal ? Et dans les journaux archivés ?
 
Pour générer de l'activité :
psql -c "INSERT INTO t1 SELECT * FROM generate_series(1,1000000);"  b1En regardant les journaux au niveau du serveur principal et au niveau des archives :
$ ls -alh /var/lib/pgsql/10/data/pg_wal/
(...)
-rw-------  1 postgres postgres  16M  7 sept. 05:58 00000001000000000000008C
-rw-------  1 postgres postgres  16M  7 sept. 05:58 00000001000000000000008D
$ ls -alh /var/lib/pgsql/10/archives/
(...)
-rw------- 1 postgres postgres  16M  7 sept. 06:06 000000010000000000000064
-rw------- 1 postgres postgres  16M  7 sept. 06:06 000000010000000000000065On constate que le principal a conservé les anciens journaux dans le répertoire pg_wal.
Que ce serait-il passé sans slot de réplication ?
 
Le deuxième secondaire n'aurait pas pu récupérer des journaux indispensables à la réplication.
Démarrer le deuxième secondaire et contrôler que les deux secondaires sont bien en Streaming Replication .
 
Au démarrage :
$  psql -x -c "SELECT * FROM pg_stat_replication" 
-[ RECORD  1  ]----+------------------------------ 
pid              | 1249 
usesysid         | 16388 
usename          | repli
application_name | walreceiver
client_addr      | 127.0 .0.1 
client_hostname  | 
client_port      | 45932 
backend_start    | 2017 -09 -07  05 :47:43 .316465 -04 
backend_xmin     | 
state            | streaming
sent_lsn         | 0 /66A951D0
write_lsn        | 0 /66A951D0
flush_lsn        | 0 /66A951D0
replay_lsn       | 0 /66A951D0
write_lag        | 
flush_lag        | 
replay_lag       | 
sync_priority    | 0 
sync_state       | async
-[ RECORD  2  ]----+------------------------------ 
pid              | 1801 
usesysid         | 16388 
usename          | repli
application_name | walreceiver
client_addr      | 127.0 .0.1 
client_hostname  | 
client_port      | 45946 
backend_start    | 2017 -09 -07  06 :08:02 .109247 -04 
backend_xmin     | 
state            | streaming
sent_lsn         | 0 /66A951D0
write_lsn        | 0 /66A951D0
flush_lsn        | 0 /66A951D0
replay_lsn       | 0 /66A951D0
write_lag        | 00 :00:01 .766658 
flush_lag        | 00 :00:01 .934458 
replay_lag       | 00 :00:02 .142817 
sync_priority    | 0 
sync_state       | asyncAu bout de quelques minutes il est enfin synchronisé :
$ psql -x -c "SELECT * FROM pg_stat_replication" 
-[ RECORD  1  ]----+------------------------------ 
pid              | 1249 
usesysid         | 16388 
usename          | repli
application_name | walreceiver
client_addr      | 127.0 .0.1 
client_hostname  | 
client_port      | 45932 
backend_start    | 2017 -09 -07  05 :47:43 .316465 -04 
backend_xmin     | 
state            | streaming
sent_lsn         | 0 /66A951D0
write_lsn        | 0 /66A951D0
flush_lsn        | 0 /66A951D0
replay_lsn       | 0 /66A951D0
write_lag        | 
flush_lag        | 
replay_lag       | 
sync_priority    | 0 
sync_state       | async
-[ RECORD  2  ]----+------------------------------ 
pid              | 1801 
usesysid         | 16388 
usename          | repli
application_name | walreceiver
client_addr      | 127.0 .0.1 
client_hostname  | 
client_port      | 45946 
backend_start    | 2017 -09 -07  06 :08:02 .109247 -04 
backend_xmin     | 
state            | streaming
sent_lsn         | 0 /66A951D0
write_lsn        | 0 /66A951D0
flush_lsn        | 0 /66A951D0
replay_lsn       | 0 /66A951D0
write_lag        | 
flush_lag        | 
replay_lag       | 
sync_priority    | 0 
sync_state       | asyncRéplication synchrone en flux avec deux secondaires  Nous allons passer le premier secondaire en tant que secondaire synchrone. Pour cela, il doit avoir un nom, indiqué par le paramètre de connexion application_name. Le fichier de configuration /var/lib/pgsql/10/secondaire1/recovery.conf doit être modifié ainsi :
primary_conninfo = 'host=127.0.0.1 port=5432 user=repli password=repli
                    application_name=secondaire1'Ensuite, nous devons indiquer le serveur secondaire dans la liste des serveurs synchrones initialisée par le paramètre synchronous_standby_names du fichier /var/lib/pgsql/10/data/postgresql.conf :
synchronous_standby_names = 'secondaire1'Il ne reste plus qu'à recharger la configuration pour les deux serveurs :
# service postgresql-10 reload 
# service secondaire1 restart 
Il n'est pas nécessaire de redémarrer les trois serveurs. Un reload du principal et un redémarrage du premier secondaire suffisent.
 
Vérifions l'état de la réplication pour les deux secondaires :
$ psql -p 5432 
psql (10 )
Type  "help"  for  help.
postgres=# \x
Expanded display is  on.
postgres=# SELECT  application_name, backend_start, state, sync_state
FROM  pg_stat_replication;
-[ RECORD  1  ]----+------------------------------ 
application_name | walreceiver
backend_start    | 2017 -09 -07  06 :08:02 .109247 -04 
state            | streaming
sync_state       | async
-[ RECORD  2  ]----+------------------------------ 
application_name | secondaire1
backend_start    | 2017 -09 -07  06 :11:06 .67367 -04 
state            | streaming
sync_state       | syncNous avons bien un serveur synchrone et un serveur asynchrone.
Exécutons une requête de modification sur le principal :
$ psql -p 5432  b1
psql (10 )
Type  "help"  for  help.
b1=# CREATE  TABLE  t2(id  integer );
CREATE  TABLE La table est bien créée, sans attendre. Maintenant, arrêtons le serveur secondaire synchrone et faisons une nouvelle modification sur le principal :
# service secondaire1 stop
$ psql -p 5432 b1
psql (10)
Type "help" for help.
b1=# CREATE TABLE t3(id integer);La requête reste bloquée. En effet, le secondaire ne peut pas répondre à la demande de la réplication car il est éteint. Du coup, le principal est bloqué en écriture. Il faut soit démarrer le secondaire, soit modifier la configuration du paramètre synchronous_standby_names.
Démarrons le secondaire synchrone à partir d'un autre terminal et la requête se termine.
Nous allons maintenant passer le deuxième secondaire en synchrone avec le application_name positionné à secondaire2 afin de les différencier (il est possible d'utiliser le même application_name). Ensuite ajoutons secondaire2 à la liste des synchronous_standby_names sur l'instance principale.
# service postgresql-10 reload 
# service secondaire2 restart $ psql -x -p 5432  -c "SELECT application_name, backend_start, state, sync_state 
FROM  pg_stat_replication;" 
-[ RECORD  1  ]----+------------------------------ 
application_name | secondaire2
backend_start    | 2017 -09 -07  06 :15:40 .969515 -04 
state            | streaming
sync_state       | potential
-[ RECORD  2  ]----+------------------------------ 
application_name | secondaire1
backend_start    | 2017 -09 -07  06 :12:46 .841986 -04 
state            | streaming
sync_state       | sync
$ psql -p 5432  -c "SHOW synchronous_standby_names" 
 synchronous_standby_names
--------------------------- 
 secondaire1,secondaire2Cette fois les deux serveurs correspondent au synchronous_standby_names, on peut constater qu'un serveur est sync et l'autre potential. Il ne peut y avoir qu'un seul serveur synchrone avec le principal. Si les deux serveurs avaient le même application_name, il n'y aurait eu qu'un seul serveur sync.
Arrêtons ensuite le premier secondaire synchrone :
# service secondaire1 stop $ psql -p 5432  -c "SELECT application_name, backend_start, state, sync_state 
FROM  pg_stat_replication;" 
-[ RECORD  1  ]----+------------------------------ 
application_name | secondaire2
backend_start    | 2017 -09 -07  06 :15:40 .969515 -04 
state            | streaming
sync_state       | syncEt faisons une modification sur le principal :
$ psql -p 5432  -c "CREATE TABLE t4(id integer);"  b1
CREATE  TABLE Cette fois, tout se passe bien. Le premier secondaire n'est pas disponible mais le second l'est. Il prend donc la suite du premier secondaire en tant que secondaire synchrone.
Si on souhaite avoir deux serveurs synchrones, il faut utiliser la syntaxe suivante pour le paramètre synchronous_standby_names :
synchronous_standby_names = 'N (liste serveurs)'N = nombre de serveurs synchrones 
Dans notre cas synchronous_standby_names = '2(secondaire1,secondaire2)'
Après un reload du principal on constate bien que les deux serveurs sont synchrones :
$ psql -c "SELECT application_name, backend_start, state, sync_state 
FROM  pg_stat_replication;" 
-[ RECORD  1  ]----+------------------------------ 
application_name | secondaire2
backend_start    | 2017 -09 -07  06 :15:40 .969515 -04 
state            | streaming
sync_state       | sync
-[ RECORD  2  ]----+------------------------------ 
application_name | secondaire1
backend_start    | 2017 -09 -07  06 :19:59 .248803 -04 
state            | streaming
sync_state       | syncPour repasser sur un seul serveur synchrone :
synchronous_standby_names = 'secondaire1,secondaire2'ou :
synchronous_standby_names = '1(secondaire1,secondaire2)'ou encore depuis la version 10 :
synchronous_standby_names = 'FIRST 1(secondaire1,secondaire2)'L'ordre de cette liste donne la priorité qui sera utilisée pour l'application de la réplication synchrone. La version 10 permet de se baser sur un quorum :
synchronous_standby_names = 'ANY 1(secondaire1,secondaire2)'On obtient alors un sync_state à la valeur quorum :
$ psql -c "SELECT application_name, backend_start, state, sync_state 
FROM  pg_stat_replication;" 
FROM  pg_stat_replication;" 
-[ RECORD  1  ]----+------------------------------ 
application_name | secondaire2
backend_start    | 2017 -09 -07  06 :15:40 .969515 -04 
state            | streaming
sync_state       | quorum
-[ RECORD  2  ]----+------------------------------ 
application_name | secondaire1
backend_start    | 2017 -09 -07  06 :19:59 .248803 -04 
state            | streaming
sync_state       | quorumRéplication synchrone : cohérence des lectures (optionnel)  > Exécuter la commande SELECT pg_wal_replay_pause(); sur le premier secondaire synchrone. Ajouter des données sur le principal et contrôler leur présence sur le secondaire. Que constatez-vous ?
$ psql -p 5433  -c "SELECT pg_wal_replay_pause()" $ psql -p 5432  b1
b1=# INSERT  INTO  t4 VALUES  ('1' );
INSERT  0  1 
b1=# SELECT  * FROM  t4;
 c1
---- 
  1 
(1  row )$ psql -p 5433  -c "SELECT * FROM t4;"  b1
 id 
---- 
(0  rows )$ psql -p 5434  -c "SELECT * FROM t4;"  b1
 id  
---- 
  1 
(1  row )La table est vide sur le premier secondaire synchrone mais elle est bien remplie sur le deuxième secondaire !
Est-ce que les instances sont bien synchrones (utilisez la vue pg_stat_replication) ? Relancer le rejeu et contrôler la présence des enregistrements sur les deux serveurs.
 
$ psql -p 5432 
postgres=# \x
Expanded display is  on.
postgres=# SELECT  application_name, backend_start, state, sent_lsn,
                  write_lsn, flush_lsn, replay_lsn, sync_state
           FROM  pg_stat_replication;
-[ RECORD  1  ]----+------------------------------ 
application_name | secondaire2
backend_start    | 2017 -09 -07  06 :15:40 .969515 -04 
state            | streaming
sent_lsn         | 0 /66AC5098
write_lsn        | 0 /66AC5098
flush_lsn        | 0 /66AC5098
replay_lsn       | 0 /66AC5098
sync_state       | quorum
-[ RECORD  2  ]----+------------------------------ 
application_name | secondaire1
backend_start    | 2017 -09 -07  06 :19:59 .248803 -04 
state            | streaming
sent_lsn         | 0 /66AC5098
write_lsn        | 0 /66AC5098
flush_lsn        | 0 /66AC5098
replay_lsn       | 0 /66AC4F18
sync_state       | quorumLe premier secondaire est bien synchrone, on constate que les deux ont bien reçu les enregistrements mais seul le secondaire2 a rejoué les journaux.
On réactive le rejeu sur le premier secondaire :
$ psql -p 5433  -c "SELECT pg_wal_replay_resume()" 
 pg_wal_replay_resume
----------------------- 
(1  row )$ psql -p 5432 
postgres=# \x
Expanded display is  on.
postgres=# SELECT  application_name, backend_start, state, sent_lsn,
                  write_lsn, flush_lsn, replay_lsn, sync_state
           FROM  pg_stat_replication;
-[ RECORD  1  ]----+------------------------------ 
application_name | secondaire2
backend_start    | 2017 -09 -07  06 :15:40 .969515 -04 
state            | streaming
sent_lsn         | 0 /66AC5098
write_lsn        | 0 /66AC5098
flush_lsn        | 0 /66AC5098
replay_lsn       | 0 /66AC5098
sync_state       | quorum
-[ RECORD  2  ]----+------------------------------ 
application_name | secondaire1
backend_start    | 2017 -09 -07  06 :19:59 .248803 -04 
state            | streaming
sent_lsn         | 0 /66AC5098
write_lsn        | 0 /66AC5098
flush_lsn        | 0 /66AC5098
replay_lsn       | 0 /66AC5098
sync_state       | quorumCette fois, le secondaire1 a bien rejoué les journaux. Les enregistrements sont bien présents dans la table t4 :
$ psql -p 5433  -c "SELECT * FROM t4;"  b1
 id  
---- 
  1 
(1  row )
Quel paramètre modifier pour obtenir les mêmes résultats sur les deux instances ?
 
Par défaut la réplication synchrone garantie qu'aucune transaction n'est perdue mais elle ne s'assure pas que le secondaire synchrone a bien rejoué la transaction. Pour cela, il faut placer le paramètre synchronous_commit à remote_apply sur le principal.
Appliquer ce paramètre et effectuer la même opération (pause du rejeu puis insertion d'enregistrement sur le principal). Que constatez-vous?
Dans /var/lib/pgsql/10/data/postgresql.conf :
synchronous_commit = remote_applyFaire un rechargement de la configuration du serveur principal :
# service postgresql-10 reload $ psql -p 5433  -c "SELECT pg_wal_replay_pause()" 
 pg_wal_replay_pause
---------------------- 
(1  row )
$ psql -p 5434  -c "SELECT pg_wal_replay_pause()" 
 pg_wal_replay_pause
---------------------- 
(1  row )
$ psql -p 5432  -c "INSERT INTO t4 VALUES ('2');"  b1Cette fois la requête est bloquée, il faut relancer le rejeu sur au moins un secondaire pour qu'elle puisse s'effectuer.
Réplication en cascade (optionnel)  Nous allons créer un troisième secondaire et le placer en cascade du premier secondaire.
Créons le troisième secondaire avec pg_basebackup :
$ pg_basebackup -D /var/lib/pgsql/10/secondaire3 -P -h 127.0.0.1 -U repli
Password:
178657/178657 Ko (100%), 1/1 tablespace
Remarquez que nous le créons à partir du principal. Nous aurions très bien pu le créer à partir du secondaire.
 
Les emplacements et le numéro de port du troisième secondaire doivent être différents des trois autres serveurs. Il faut donc créer le fichier /etc/sysconfig/pgsql/secondaire3 pour indiquer :
PGDATA=/var/lib/pgsql/10/secondaire3
PGPORT=5435Il faut également mettre en place le script de démarrage :
# ln -s /etc/init.d/postgresql-10 /etc/init.d/secondaire3 Il est aussi nécessaire de modifier le numéro de port d'écoute de l'instance dans /var/lib/pgsql/10/secondaire3/postgresql.conf :
port = 5435Le fichier de restauration doit être copié :
$ cp  /var/lib/pgsql/10/secondaire1/recovery.conf
     /var/lib/pgsql/10/secondaire3/recovery.conf Et légèrement modifié sur le nouveau secondaire :
primary_conninfo = 'host=127.0.0.1 port=5433 user=repli password=repli
                    application_name=secondaire3'
trigger_file = '/tmp/secondaire3_autonome'C'est dans cette dernière modification que tout se joue : notez que le numéro de port indique bien le premier secondaire et non pas le principal. Il faut également désactiver l'archive_cleanup_command.
Avant d'aller plus loin, il faut également s'assurer que les connections de préplication sont autorisées sur l'instance secondaire1. Le fichier /var/lib/pgsql/10/secondaire1/pg_hba.conf doit contenir la ligne suivante :
host  replication  repli  127.0.0.1/32  md5Suite à la modification des paramètres de sécurité, la configuration du secondaire1 doit être rechargée :
$ psql  -p 5433 -c "SELECT pg_reload_conf()" 
 pg_reload_conf  
---------------- 
 t 
( 1  ligne) On peut enfin démarrer le troisième secondaire :
# service secondaire3 start Le secondaire1 a bien un processus walreceiver et walsender :
-bash-4.1$ ps -o pid,cmd fx 
  PID CMD
 2603 /usr/pgsql-10/bin/postmaster -D /var/lib/pgsql/10/secondaire3
 2605  \_ postgres: logger process                                     
 2606  \_ postgres: startup process   recovering 000000010000000000000068
 2608  \_ postgres: checkpointer process                               
 2609  \_ postgres: writer process                                     
 2611  \_ postgres: stats collector process                            
 2612  \_ postgres: wal receiver process   streaming 0/68000060        
 2406 /usr/pgsql-10/bin/postmaster -D /var/lib/pgsql/10/secondaire1
 2408  \_ postgres: logger process                                     
 2409  \_ postgres: startup process   recovering 000000010000000000000068
 2411  \_ postgres: checkpointer process                               
 2412  \_ postgres: writer process                                     
 2413  \_ postgres: stats collector process                            
 2414  \_ postgres: wal receiver process   streaming 0/68000060        
 2613  \_ postgres: wal sender process repli 127.0.0.1(36364) streaming 0/68000060
 2262 /usr/pgsql-10/bin/postmaster -D /var/lib/pgsql/10/secondaire2
 2264  \_ postgres: logger process                                     
 2265  \_ postgres: startup process   recovering 000000010000000000000068
 2267  \_ postgres: checkpointer process                               
 2268  \_ postgres: writer process                                     
 2269  \_ postgres: stats collector process                            
 2270  \_ postgres: wal receiver process   streaming 0/68000060        
  443 /usr/pgsql-10/bin/postmaster -D /var/lib/pgsql/10/data
  445  \_ postgres: logger process                              
  447  \_ postgres: checkpointer process                        
  448  \_ postgres: writer process                              
  449  \_ postgres: wal writer process                          
  450  \_ postgres: autovacuum launcher process                 
  451  \_ postgres: archiver process   last was 000000010000000000000067.00000028.backup
  452  \_ postgres: stats collector process                     
  453  \_ postgres: bgworker: logical replication launcher      
 2271  \_ postgres: wal sender process repli 127.0.0.1(45956) streaming 0/68000060
 2415  \_ postgres: wal sender process repli 127.0.0.1(45958) streaming 0/68000060Une connexion sur l'instance secondaire1 permettra de vérifier :
$ psql -p 5433  -c "\x"  -c "SELECT * FROM pg_stat_replication;" 
Affichage étendu activé.
-[ RECORD  1  ]----+------------------------------ 
pid              | 2613 
usesysid         | 16388 
usename          | repli
application_name | secondaire3
client_addr      | 127.0 .0.1 
client_hostname  | 
client_port      | 36364 
backend_start    | 2017 -09 -07  06 :33:48 .669222 -04 
backend_xmin     | 
state            | streaming
sent_lsn         | 0 /68000140 
write_lsn        | 0 /68000140 
flush_lsn        | 0 /68000140 
replay_lsn       | 0 /68000140 
write_lag        | 00 :00:00 .000479 
flush_lag        | 00 :00:00 .015034 
replay_lag       | 00 :00:00 .015219 
sync_priority    | 0 
sync_state       | async