Dans le précédent article nous avons vu comment mettre en place une réplication sur un serveur secondaire par copie puis rejeu des journaux de transaction. L’inconvénient de cette technique c’est qu’il peut y avoir un delta assez important entre le maitre et l’esclave : de la taille d’un fichier journal ou d’une durée correspondant au paramètre archive_timeout.

Postgres intègre un mécanisme de réplication par flux, plutôt que de copier des fichiers journaux, les informations sur les transactions seront véhiculées via un flux. Cette technique permet de réduire énormément le delta entre le maitre et l’esclave. Les processus qui vont gérer ces flux seront : wal_sender pour la maitre et wal_receiver pour le secondaire.

Il est également possible de définir le serveur secondaire en warm standby, c’est à dire qu’il peut à tout moment arrêter la réplication et basculer en serveur maître. Il est donc tout à fait possible de mettre en place une solution type hearthbeat entre les deux serveurs, si le maitre ne répond plus on bascule sur le secondaire.

La réplication peut être asynchrone mais il est également possible de la rendre synchrone. Le serveur maitre confirme que la transaction a été bien été « commitée » une fois qu’elle a bien été écrite sur l’esclave. C’est assez tentant mais cela a un impact sur les performances. Enfin, il est également possible de configurer le maitre afin que celui-ci retourne la confirmation de commit quand la transaction est bien arrivée sur l’esclave même si celle-ci n’a pas été écrite, permettant un gain significatif sur les performances. Il y aurait perte de données si on perdait le maitre et que le secondaire était coupé avant qu’il n’ai pu écrire la transaction sur les disques. Cette fonctionnalité est apparue dans la version 9.2 de Postgres :

The synchronous_commit parameter has a new value: remote_write. It can be used when there is a synchronous slave (synchronous_standby_names is set), meaning that the master doesn’t have to wait for the slave to have written the data to disk, only for the slave to have acknowledged the data. With this set, data is protected from a crash on the master, but could still be lost if the slave crashed at the same time (i.e. before having written the in flight data to disk). As this is a quite remote possibility, and the performance improvement will be large, some people will be interested in this compromise.
https://wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.2

Configuration du maître

C’est assez simple, il faut ouvrir un flux de réplication dans le fichier pg_hba.

host    replication     replicator        <ip du slave>/32            md5

Note : Il est possible de créer un rôle dédié à la réplication :

CREATE ROLE replicator WITH REPLICATION PASSWORD 'password' LOGIN

Il faut paramétrer le flux de réplication dans postgres.conf dans la section « REPLICATION » :

max_wal_senders = 1 # Nombre de processus qui pourront se connecter sur le maitre.

Un autre paramètre qui a son importance :

wal_keep_segments = 3

Celui-ci sert à indiquer à Postgres de conserver 3 journaux de transaction. En effet si le flux venait à être interrompu et que le maitre avait déjà effectué une rotation de ses journaux il manquerait des informations au secondaire pour rejouer les journaux. On peut donc demander au maitre de conserver quelques journaux. Enfin, si la coupure était très importante et que ce paramètre ne suffisait plus le secondaire devrait se baser sur les journaux archivés. C’est pourquoi il est indispensable de mettre en place l’archivage des journaux en plus de la streaming réplication. Ça peut sembler superflu mais en cas de grosse coupure ça permet au secondaire de repartir. S’il manque les journaux de transaction on serait obligé de repartir sur une copie du maitre. Suivant la taille des bases cette opération peut être très lourde.

Relancer le maitre.

Configuration du secondaire

La encore la communauté Postgres a fait dans la simplicité, il faut rajotuer la ligne suivante dans le fichier recovery.conf :

primary_conninfo = 'user=replcator password=password host=<ip du maitre> port=5432'

Relancer le secondaire.

Vous aurez peut être cette erreur dans les logs :

Vérifiez que votre maitre écoute bien sur la bonne interface (listen_addresses).

Si la streaming réplication fonctionne vous verrez apparaitre cette ligne dans les logs du secondaire:

2014-11-11 11:50:11 CET LOG:  started streaming WAL from primary at 0/FC000000 on timeline 1

Et sur le maitre :

Dans les processus du maitre vous verrez :

postgres  2552  0.0  0.5 216008  2984 ?        Ss   11:52   0:00 postgres: wal sender process replicator 192.168.1.127(38613) streaming 0/FD000090

Et sur le secondaire :

postgres  3739  0.1  0.5 219744  2844 ?        Ss   11:52   0:00 postgres: wal receiver process

On peut également constater que le secondaire procède à des checkpoint réguliers et qu’il continue de faire le nettoyage dans le dossier d’archive:

Et c’est tout!

Avec ce type de réplication est important de contrôler les logs pour détecter tout défaillance de la réplication. Il existe aussi la vue pg_stat_replication qui donne quelques informations sur le bon fonctionnement de la réplication :

sync_state nous indique que la réplication est asynchrone.

Dans le prochain article qui va traiter du secondaire en hot standby nous verront qu’il est plus facile de contrôler le bon fonctionnement de la réplication.

Passage de la réplication asynchrone à synchrone

Il faut paramétrer le maitre pour activer la réplication synchrone :

Le doit synchronous_commit être à « on » :

Vous remarquerez qui peut prendre plusieurs valeurs :

  • off : on désactive le synchronous commit. Ne dois jamais être à off, sauf si vous acceptez de perdre des données en cas de crash.
  • on : Commit synchrone sur le maitre et les esclaves définis dans « synchronous_standby_names »
  • local : les commit sont synchrone sur le maitre uniquement et asynchrone sur les esclaves.
  • remote_write : Ce paramètre peut prêter à confusion, s’il est activé la réplication est « semi-synchrone ». Le maitre renvoi la confirmation de bon déroulement de transaction une fois que le secondaire a reçu la transaction même s’il ne l’a pas encore écrite sur le disque! Cette option permet d’avoir un gain de performance, il y a un risque de perte de données si on perdait le maitre et sie le secondaire était coupé avant d’avoir pu écrite sa transaction.

Su le secondaire il faut indiquer le « application_name » (celui que nous avons renseigné dans « synchronous_standby_names »)  dans le fichier recovery.conf:

primary_conninfo = 'user=replicator password=password host=192.168.1.126 port=5432 application_name=slave'

Relancer l’esclave puis le maitre. Dans les logs du maitre :

Effectuons quelques tests avec pgbench :

Réplication asynchrone :

Réplication Synchrone :

Réplication semi-synchrone :

La vue pg_stat_replication en mode synchrone :

Le sync_state est bien à « sync ».

Warm standby

Actuellement notre réplicat n’accepte aucune connexion. Il est possible de le faire basculer du mode réplication au mode master grâce au « trigger_file ». Il est possible de spécifier dans le fichier recovery.conf un fichier qui va déclencher la bascule :

trigger_file = '/tmp/pg_slave'

Il suffit de faire un « touch /tmp/pg_slave » pour que le secondaire bascule :

Le secondaire démarre et accepte les connexion. On remarque la ligne « selected new timeline ID: 2 », Postgres démarre une nouvelle timeline. Pour l’explication voir les liens ci dessous :

Note : Il n’est pas possible de rebasculer l’esclave en secondaire, il faut le détruire et repartir d’une base du maitre.

Pour approfondir :

https://wiki.postgresql.org/images/e/e5/FOSDEM2013-Timelines.pdf

http://www.dalibo.org/glmf131_mise_en_place_replication_postgresl_9.0_1

http://www.dalibo.org/glmf131_mise_en_place_replication_postgresl_9.0_2

Ecrire un commentaire

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url=""> 

requis