pgstef's blog

SELECT * FROM pgstef

Home About me Talks PITR tools View on GitHub

Configurer la réplication

Installer PostgreSQL 9.6 sur les 2 serveurs (server1 et server2) :

# yum install https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm
# yum install postgresql96-server
# firewall-cmd --permanent --add-service=postgresql
# firewall-cmd --reload

Initialiser et démarrer PostgreSQL sur server1 :

# /usr/pgsql-9.6/bin/postgresql96-setup initdb
# systemctl enable postgresql-9.6
# systemctl start postgresql-9.6

Configurer postgresql.conf :

##Global
listen_addresses = '*'

##Réplication
wal_level = replica
max_wal_senders = 5
wal_log_hints = on
hot_standby = on
hot_standby_feedback = on

##Archivage
archive_mode = on
archive_command = 'true'

Créer un utilisateur pour la réplication :

# sudo -iu postgres psql
postgres=# CREATE ROLE replicator WITH LOGIN REPLICATION PASSWORD 'motdepasse';

Configurer pg_hba.conf (et interdire que l’instance réplique sur elle-même) :

host replication replicator server1 reject
host replication replicator server2 md5

Configurer ~postgres/.pgpass sur les 2 serveurs :

# echo "*:*:replication:replicator:motdepasse" >> ~postgres/.pgpass
# chown postgres:postgres ~postgres/.pgpass
# chmod 0600 ~postgres/.pgpass

Redémarrer PostgreSQL pour prendre en compte le nouveau paramétrage :

# systemctl restart postgresql-9.6

Initialiser instance secondaire sur server2 :

# sudo -iu postgres
$ pg_basebackup -h server1 -U replicator \
   --pgdata /var/lib/pgsql/9.6/data \
   --xlog-method=stream \
   --progress

Configurer recovery.conf :

standby_mode = 'on'
primary_conninfo = 'host=server1 user=replicator'
recovery_target_timeline = 'latest'

Modifier pg_hba.conf pour interdire que l’instance ne réplique sur elle-même :

host replication replicator server1 md5
host replication replicator server2 reject

Démarrer PostgreSQL :

# systemctl enable postgresql-9.6
# systemctl start postgresql-9.6

Pour vérifier que la réplication est fonctionnelle

# ps -ef |grep postgres |grep "wal receiver"
postgres 18086 18078  0 09:41 ?        00:00:00 postgres: wal receiver process   streaming 0/4000140
# ps -ef |grep postgres |grep "wal sender"
postgres 18265 18239  0 09:41 ?        00:00:00 postgres: wal sender process replicator 192.168.122.219(40366) streaming 0/4000140

# sudo -iu postgres psql
postgres=# SELECT
	client_addr AS client, usename AS user, application_name AS name,
	state, sync_state AS mode,
	(pg_xlog_location_diff(pg_current_xlog_location(),sent_location) / 1024)::bigint as pending,
	(pg_xlog_location_diff(sent_location,write_location) / 1024)::bigint as write,
	(pg_xlog_location_diff(write_location,flush_location) / 1024)::bigint as flush,
	(pg_xlog_location_diff(flush_location,replay_location) / 1024)::bigint as replay,
	(pg_xlog_location_diff(pg_current_xlog_location(),replay_location))::bigint / 1024 as total_lag
FROM pg_stat_replication;

Configurer la sauvegarde PITR

Supposons le répertoire /mnt/backups monté sur les 2 serveurs et disponible en RW pour l’utilisateur système postgres.

Installer et configurer pitrery sur les 2 serveurs :

# yum install pitrery
# cat /etc/pitrery/pitrery.conf
PGDATA="/var/lib/pgsql/9.6/data"
BACKUP_DIR="/mnt/backups/pitrery"
PURGE_KEEP_COUNT=1
STORAGE="rsync"

Configurer l’archivage dans postgresql.conf :

archive_command = '/usr/bin/archive_xlog %p'

Vérifier le bon fonctionnement de l’archivage sur server1 :

# systemctl reload postgresql-9.6.service
# sudo -iu postgres mkdir -p /mnt/backups/pitrery/archived_xlog
# sudo -iu postgres pitrery check
# sudo -iu postgres psql -c "SELECT pg_switch_xlog();"

Générer une sauvegarde :

# sudo -iu postgres pitrery backup

Modifier le recovery.conf de server2 :

restore_command = '/usr/bin/restore_xlog %f %p'

Après redémarrage, cela permettra à server2 de rattraper automatiquement son retard sur server1 en rejouant les wal archivés en cas de problème avec la réplication.

Promouvoir proprement l’instance primaire sur server2

Sur server1 :

# systemctl stop postgresql-9.6.service
# LC_MESSAGES=C /usr/pgsql-9.6/bin/pg_controldata /var/lib/pgsql/9.6/data | grep -E '(Database cluster state)|(REDO location)'
Database cluster state:               shut down
Latest checkpoint's REDO location:    0/47000028

Sur server2 :

# sudo -iu postgres psql -c "CHECKPOINT"
# LC_MESSAGES=C /usr/pgsql-9.6/bin/pg_controldata /var/lib/pgsql/9.6/data | grep -E '(Database cluster state)|(REDO location)'
Database cluster state:               in archive recovery
Latest checkpoint's REDO location:    0/47000028

Il faut absolument que le statut de Database cluster state soit à in archive recovery et que les valeurs retournées dans Latest checkpoint location soient strictement identiques pour qu’il n’y ait pas de perte de données.

Si tel est le cas, promouvoir le service via et en vérifier la bonne exécution depuis les logs :

# sudo -iu postgres /usr/pgsql-9.6/bin/pg_ctl -D /var/lib/pgsql/9.6/data promote

Pour réintégrer server1 comme instance secondaire, y créer le recovery.conf avant de redémarrer l’instance :

standby_mode = 'on'
primary_conninfo = 'user=replicator host=server2'
recovery_target_timeline = 'latest'
restore_command = '/usr/bin/restore_xlog %f %p'

Pour vérifier l’état de l’instance locale :

# sudo -iu postgres psql -c "SELECT pg_is_in_recovery();"

Reconstruire l’instance secondaire à partir d’une sauvegarde pitrery

Supposons l’instance primaire démarrée et fonctionnelle sur server1 et une sauvegarde pitrery correcte.

Sur server 2 :

# sudo -iu postgres pitrery list -v
List of local backups
----------------------------------------------------------------------
Directory:
  /mnt/backups/pitrery/2018.07.30_11.20.11
  space used: 403M
  storage: rsync
Minimum recovery target time:
  2018-07-30 11:20:11 CEST
PGDATA:
  pg_default 402 MB
  pg_global 497 kB

# sudo -iu postgres pitrery restore
INFO: searching backup directory
INFO: retrieving the PostgreSQL version of the backup
INFO: PostgreSQL version: 9.6
INFO: searching for tablespaces information
INFO: 
INFO: backup directory:
INFO:   /mnt/backups/pitrery/2018.07.30_11.20.11
INFO: 
INFO: destinations directories:
INFO:   PGDATA -> /var/lib/pgsql/9.6/data
INFO: 
INFO: recovery configuration:
INFO:   target owner of the restored files: postgres
INFO:   restore_command = 'restore_xlog -C /etc/pitrery/pitrery.conf %f %p'
INFO: 
INFO: creating /var/lib/pgsql/9.6/data with permission 0700
INFO: transferring PGDATA to /var/lib/pgsql/9.6/data with rsync
INFO: transfer of PGDATA successful
INFO: preparing pg_xlog directory
INFO: preparing recovery.conf file
INFO: done
INFO: 
INFO: please check directories and recovery.conf before starting the cluster
INFO: and do not forget to update the configuration of pitrery if needed
INFO: 

Configurer recovery.conf :

standby_mode = 'on'
primary_conninfo = 'host=server1 user=replicator'
recovery_target_timeline = 'latest'
restore_command = '/usr/bin/restore_xlog %f %p'

Modifier pg_hba.conf pour interdire que l’instance ne réplique sur elle-même :

host replication replicator server1 md5
host replication replicator server2 reject

Démarrer l’instance et en vérifier le bon démarrage depuis les logs :

# systemctl start postgresql-9.6.service

Pour finir, vérifier que la réplication est fonctionnelle comme vu précédemment.