Configuration de la réplication synchrone pour la haute disponibilité dans PostgreSQL
La configuration de PostgreSQL pour la haute disponibilité (HA) est cruciale pour toute application critique. Bien que la réplication asynchrone offre des avantages en termes de performance, elle comporte intrinsèquement un risque de perte de données si le serveur primaire tombe en panne avant que les modifications ne soient entièrement transmises au serveur de secours. La réplication synchrone en flux continu résout ce problème en garantissant qu'une transaction n'est considérée comme validée qu'une fois que les données ont été écrites avec succès dans le WAL (Write-Ahead Log) du serveur primaire et d'au moins un serveur de secours désigné. Cela assure un objectif de point de récupération (RPO) de zéro.
Ce guide complet vous présente les étapes de configuration essentielles nécessaires pour établir une configuration de réplication PostgreSQL robuste et sans perte de données. Nous nous concentrerons sur les paramètres critiques tels que wal_level et synchronous_commit qui sous-tendent cette architecture de haute disponibilité.
Prérequis
Avant de commencer, assurez-vous d'avoir deux serveurs PostgreSQL configurés (un primaire et un de secours) exécutant des versions majeures identiques de PostgreSQL. Les deux serveurs doivent avoir une connectivité réseau. Pour ce guide, nous supposons :
- Nom d'hôte/IP primaire :
pg_primary - Nom d'hôte/IP de secours :
pg_standby - Utilisateur de réplication :
repl_user(créé avec les permissions appropriées) - Nom de la base de données :
mydb
Étape 1 : Configuration du serveur primaire
Le serveur primaire nécessite des paramètres spécifiques pour activer la réplication en flux continu et gérer le journal de transactions (Write-Ahead Log ou WAL) requis par les validations synchrones.
A. Ajustement de postgresql.conf sur le serveur primaire
Modifiez le fichier postgresql.conf du serveur primaire. Les paramètres suivants sont obligatoires pour la réplication en flux continu :
# --- Requis pour la réplication ---
listen_addresses = '*' # Autorise les connexions depuis les serveurs de secours
wal_level = replica # Doit être 'replica' ou supérieur (ex: 'logical')
max_wal_senders = 10 # Nombre max de connexions simultanées depuis les serveurs de secours
max_replication_slots = 10 # Slots nécessaires pour les flux de réplication persistants
# --- Essentiel pour la validation synchrone ---
synchronous_standby_names = '1 (standby_app_name)' # Spécifie les serveurs de secours requis
# --- Facultatif mais recommandé ---
wal_log_hints = on # Recommandé pour une réplication plus sûre, bien qu'il augmente le volume du WAL
shared_preload_libraries = 'pg_stat_statements' # Si vous utilisez la surveillance
Explication des paramètres clés :
wal_level = replica: Cela garantit que suffisamment d'informations sont écrites dans le WAL pour permettre à un serveur de secours de reconstruire l'état de la base de données. Pour les validations synchrones, ce niveau est l'exigence minimale.synchronous_standby_names: Il s'agit du paramètre central pour définir quels serveurs de secours doivent accuser réception des écritures. Nous le définissons en utilisant la syntaxe(N (nom_du_serveur_de_secours)). SiN=1, au moins un serveur de secours doit confirmer l'écriture avant que la transaction ne soit validée.
B. Configuration de l'authentification basée sur l'hôte (pg_hba.conf)
Le serveur primaire doit autoriser l'utilisateur de réplication des serveurs de secours à se connecter à des fins de réplication.
Ajoutez une entrée au fichier pg_hba.conf sur le serveur primaire :
# TYPE BASE_DE_DONNÉES UTILISATEUR ADRESSE MÉTHODE
host replication repl_user pg_standby/32 scram-sha-256
Remplacez pg_standby/32 par l'adresse IP réelle ou le sous-réseau de votre serveur de secours.
C. Création du slot de réplication et de l'utilisateur
Connectez-vous à PostgreSQL sur le serveur primaire pour créer l'utilisateur et le slot de réplication nécessaires.
1. Créer l'utilisateur de réplication :
CREATE ROLE repl_user WITH REPLICATION LOGIN PASSWORD 'a_strong_password';
2. Créer le slot de réplication :
Ce slot garantit que les segments WAL sont conservés jusqu'à ce que le serveur de secours confirme leur réception, ce qui empêche la perte de données si le serveur de secours se déconnecte temporairement.
SELECT pg_create_physical_replication_slot('standby_app_name');
- Remarque sur la dénomination : Le nom fourni ici (
standby_app_name) doit correspondre au nom spécifié danssynchronous_standby_namessur le serveur primaire.
D. Redémarrage du serveur primaire
Appliquez toutes les modifications de configuration en redémarrant le service PostgreSQL sur le serveur primaire.
sudo systemctl restart postgresql
Étape 2 : Configuration du serveur de secours
Le serveur de secours est configuré pour diffuser les enregistrements WAL depuis le serveur primaire en utilisant une configuration de récupération.
A. Sauvegarde de base
Avant de commencer la diffusion, le serveur de secours a besoin d'une copie complète du répertoire de données du serveur primaire. Arrêtez d'abord PostgreSQL sur le serveur de secours.
sudo systemctl stop postgresql
Effectuez la sauvegarde de base à l'aide de pg_basebackup. Remplacez les chemins et les détails de connexion si nécessaire :
# Exemple utilisant l'utilitaire pg_basebackup
pg_basebackup -h pg_primary -D /var/lib/postgresql/15/main/ -U repl_user -P -Xs -R -W
-D: Le répertoire de données cible sur le serveur de secours.-U: L'utilisateur de réplication.-P: Afficher la progression.-Xs: Inclure les fichiers WAL nécessaires pendant la sauvegarde de base.-R: Crée automatiquement le fichierstandby.signalet génère les paramètres de connexion nécessaires danspostgresql.auto.conf(ou la configuration de récupération).
B. Configuration de postgresql.conf sur le serveur de secours
Sur le serveur de secours, assurez-vous que postgresql.conf lui permet d'agir comme une réplique. Le paramètre clé ici est la définition du nom de l'application, qui doit correspondre au nom du slot utilisé sur le serveur primaire.
# --- Requis sur le serveur de secours ---
primary_conninfo = 'host=pg_primary port=5432 user=repl_user password=a_strong_password application_name=standby_app_name'
hot_standby = on # Autorise les requêtes de lecture en mode récupération/secours
C. Démarrage du serveur de secours
Démarrez le service PostgreSQL sur le serveur de secours.
sudo systemctl start postgresql
Étape 3 : Vérification et test de la validation synchrone
Une fois que les deux serveurs sont en cours d'exécution, vérifiez la connexion puis testez le comportement synchrone.
A. Vérification de l'état de la réplication
Connectez-vous à la base de données primaire et vérifiez la vue pg_stat_replication :
SELECT client_addr, application_name, state, sync_state FROM pg_stat_replication;
Vous devriez voir une entrée pour standby_app_name avec sync_state défini sur sync.
B. Test de la validation synchrone
Le paramètre global qui dicte à quel point PostgreSQL attend est synchronous_commit. Pour un RPO=0, vous devez utiliser une valeur qui force la synchronisation.
1. Définition du comportement global
Si vous avez configuré synchronous_standby_names sur le serveur primaire comme indiqué à l'étape 1, le comportement par défaut forcera l'attente des serveurs de secours requis si synchronous_commit est défini sur on (par défaut) ou remote_write.
Pour la garantie la plus forte, définissez-le explicitement dans postgresql.conf sur remote_write ou remote_apply (si vous avez besoin que le serveur de secours ait vidé les données sur le disque, et pas seulement les ait reçues).
# Dans postgresql.conf sur le serveur primaire
synchronous_commit = remote_write
Attention : Définir
synchronous_commit = remote_writeouonaugmente considérablement la latence des transactions par rapport aux modes asynchrones (offoulocal). Cette latence est directement corrélée à la vitesse du réseau entre le serveur primaire et le serveur de secours synchrone.
2. Test au sein d'une transaction
Pour tester de manière transactionnelle (sans nécessiter de modification de configuration globale), vous pouvez le définir par session ou par transaction :
-- Se connecter au serveur primaire
BEGIN;
SET LOCAL synchronous_commit = remote_write;
INSERT INTO sales (item, amount) VALUES ('Widget A', 100);
-- Cette insertion bloquera jusqu'à ce que 'standby_app_name' confirme la réception.
COMMIT;
-- La validation (COMMIT) ne réussit qu'après que le serveur de secours ait accusé réception de l'écriture WAL.
Si la connexion au serveur de secours synchrone est perdue pendant la transaction, le serveur primaire attendra indéfiniment (si le serveur de secours se déconnecte proprement) ou reviendra en arrière en fonction du paramètre synchronous_commit_fallback_on_error (qui est on par défaut, ce qui signifie que la transaction pourrait échouer ou se bloquer si le serveur primaire ne peut pas confirmer l'état de synchronisation).
Meilleures pratiques pour la HA synchrone
- Utiliser des serveurs de secours dédiés : N'affectez à votre liste de réplication synchrone que les serveurs de secours qui sont physiquement proches (faible latence) du serveur primaire. Une latence élevée aura un impact sévère sur les performances d'écriture.
- Surveiller le décalage de réplication : Même en mode synchrone, surveillez le décalage du serveur de secours. Un serveur de secours lent, qui est techniquement toujours 'synchrone' mais qui met trop de temps à traiter le WAL, peut toujours impacter l'expérience utilisateur.
- Repli de connexion : Comprenez le paramètre
synchronous_commit_fallback_on_error. S'il est défini suroff, un échec de communication avec le serveur de secours synchrone pendant une validation entraînera l'échec de la transaction sur le serveur primaire, empêchant une divergence potentielle des données, mais impactant immédiatement la disponibilité. - Utiliser plusieurs serveurs de secours : Pour une redondance maximale dans une configuration synchrone, configurez
synchronous_standby_names = '2 (standby1, standby2)'pour exiger des validations de deux serveurs de secours distincts.