Réplication de Base de Données
← Retour au Guide des Opérations
Table des Matières
- Aperçu
- Comment Ça Fonctionne
- Architectures de Déploiement
- Référence de Configuration
- Gestion des Pairs
- Surveillance
- Dépannage
Aperçu
OmniHSS utilise PostgreSQL avec réplication logique bidirectionnelle pour des déploiements multi-sites à haute disponibilité. Chaque site fonctionne comme un primaire indépendant en lecture/écriture. Il n'y a pas de maître unique ou de répliques en lecture seule.
Caractéristiques Clés
- Les Deux Sites en Lecture/Écriture : Chaque site possède une base de données primaire complète. Les écritures locales sont instantanées, quelle que soit la qualité du lien inter-site.
- Réplication Asynchrone : Les modifications se répliquent via le Write-Ahead Log (WAL) de PostgreSQL. Aucune écriture n'est bloquée en attendant qu'un site distant accuse réception.
- Tolérant aux Partitions : Si le lien inter-site tombe en panne, les deux sites continuent de fonctionner indépendamment. Les segments WAL s'accumulent localement et se rejouent automatiquement lorsque le lien se rétablit.
- Pas de Quorum Requis : Contrairement aux approches de cluster synchrones, il n'y a pas de concept de quorum. Un déploiement sur un seul site fonctionne de la même manière qu'un déploiement multi-sites.
- Clés Primaires UUID : Tous les enregistrements utilisent des clés primaires UUIDv4, éliminant les collisions d'ID entre les sites sans coordination.
Comment Cela Diffère de la Réplication Synchrone
| Synchrone | Réplication Logique Asynchrone | |
|---|---|---|
| Latence d'écriture | Bloquée par le nœud le plus lent | Local uniquement : sous-millisecondes |
| Échec de lien | Le site minoritaire devient en lecture seule | Les deux sites continuent en lecture/écriture |
| Quorum nécessaire | Oui (majorité des nœuds) | Non |
| Cohérence des données | Forte (tous les nœuds identiques) | Éventuelle (brève latence de réplication) |
| Adapté aux liens satellites | Non (la latence nuit aux performances d'écriture) | Oui (les files d'attente WAL se rattrapent) |
Comment Ça Fonctionne
Flux de Réplication Logique
Modèle de Publication / Souscription
Chaque site a :
- Une publication qui diffuse tous les changements de table (sauf
schema_migrations) - Une souscription à la publication de chaque site pair
Mise en File d'Attente WAL Pendant une Panne de Lien
Lorsque le lien inter-site n'est pas disponible :
- Les écritures locales continuent sans interruption
- Les segments WAL s'accumulent du côté de la publication
- Le slot de réplication suit où chaque abonné s'est arrêté
- Lorsque le lien se rétablit, le WAL en file d'attente se rejoue depuis la dernière position reconnue
- Les deux sites convergent vers un état identique
La rétention WAL est limitée par max_slot_wal_keep_size pour éviter une croissance illimitée du disque pendant des pannes prolongées.
Prévention des Conflits
Les clés primaires UUID éliminent la principale source de conflits dans la réplication bidirectionnelle. Étant donné que chaque site génère des identifiants uniques globalement de manière indépendante, les opérations INSERT ne se chevauchent jamais.
L'option de souscription origin = none empêche les boucles de réplication. Les changements arrivés par réplication ne sont pas republés à d'autres abonnés.
La table schema_migrations est exclue des publications car les deux sites exécutent des migrations identiques de manière indépendante.
Last-Write-Wins pour l'État Dynamique
Les tables d'état dynamique (subscriber_state, pdn_session, lte_call) sont mises à jour fréquemment par le signalement Diameter. Chaque ULR met à jour le MME servant, chaque CCR met à jour la session PGW, et chaque AAR met à jour l'appel actif.
Dans un déploiement multi-sites, un abonné est servi par un site à la fois. Lorsque l'abonné se déplace entre les sites, les deux sites peuvent avoir des mises à jour de la même ligne subscriber_state à des moments différents. Sans résolution de conflit, l'ordre de réplication déterminerait quelle valeur survit. Cela pourrait écraser le MME servant actuel avec une valeur obsolète.
OmniHSS utilise des triggers Last-Write-Wins (LWW) sur les tables d'état dynamique :
CREATE TRIGGER lww_subscriber_state_trigger
BEFORE UPDATE ON subscriber_state
FOR EACH ROW
EXECUTE FUNCTION lww_subscriber_state();
Le trigger compare le timestamp updated_at de la mise à jour répliquée entrante avec la ligne existante. Si la ligne existante est plus récente, la mise à jour est silencieusement supprimée. Cela garantit :
- Lorsque un abonné passe du Site A au Site B, la mise à jour la plus récente du Site B gagne toujours
- Les mises à jour obsolètes du Site A (d'avant le déplacement de l'abonné) sont rejetées
- Les deux sites convergent vers la même valeur : la dernière écriture
Tables avec des triggers LWW :
| Table | Mis à Jour Par | Fréquence |
|---|---|---|
subscriber_state | ULR, SAR, AIR, PUR | Chaque mise à jour d'attachement/localisation |
pdn_session | CCR-I, CCR-T | Chaque création/suppression de session PDN |
lte_call | AAR, STR | Chaque mise en place/fin d'appel VoLTE |
ims_subscription | UAR, SAR (S-CSCF partagé) | Chaque enregistrement d'un membre groupé |
Les données de provisionnement statiques (abonnés, profils, clés, APNs) n'ont pas besoin de LWW. L'API de provisionnement ne met à jour ces enregistrements que, généralement, depuis un seul plan de gestion.
Convention de Nommage (Requise pour les Nouvelles Tables)
Les noms de fonction et de trigger LWW sont un contrat, pas un choix libre. Pour une table foo, la fonction doit être nommée lww_foo() et le trigger doit être nommé lww_foo_trigger.
Le rôle Ansible omnihss d'OmniCore ne garde pas sa propre liste de ces tables. Il découvre chaque trigger dont le nom correspond à lww_<table>_trigger et s'assure que chacun est en mode ENABLE REPLICA à travers le maillage. Un trigger nommé autrement est invisible à cette réconciliation, donc la résolution de conflit inter-site ne serait pas appliquée silencieusement sur cette table.
Lorsque vous ajoutez une nouvelle table d'état dynamique (une table écrite à partir du trafic Diameter en direct sur plus d'un site à la fois), suivez ces étapes :
- Donnez à la table une colonne
updated_at(le macrotimestamps()d'Ecto l'ajoute). - Dans la même migration, créez
lww_<table>()etlww_<table>_triggeravec exactement ces noms. - Dans la même migration, exécutez
ALTER TABLE <table> ENABLE REPLICA TRIGGER lww_<table>_trigger, afin que le trigger se déclenche lors de l'application de la réplication, et non sur les écritures locales.
La table ims_subscription est l'exemple de référence : sa migration crée lww_ims_subscription() et lww_ims_subscription_trigger, puis active le trigger en mode réplique. Suivez cette même structure, et ne renommez pas la fonction ou le trigger.
Architectures de Déploiement
Site Unique (Pas de Réplication)
Plusieurs instances d'application HSS partagent une seule base de données PostgreSQL. La réplication en streaming PostgreSQL standard peut être utilisée pour le basculement de base de données local si nécessaire.
Déploiement à Deux Sites
Les deux sites sont des primaires complets. La provision des abonnés sur l'un ou l'autre site se réplique à l'autre. Chaque MME se connecte à son HSS local. Il n'y a pas de dépendance Diameter inter-site.
Déploiement Multi-Sites
Chaque site s'abonne à la publication de chaque autre site. Les pairs sont auto-découverts à partir de l'inventaire Ansible. Pour ajouter un site, ajoutez-le au groupe d'inventaire hss et ex��cutez le playbook.
Exigences Réseau
| Port | Protocole | But |
|---|---|---|
| 5432 | TCP | Connexions client et de réplication PostgreSQL |
Référence de Configuration
Variables Ansible
La réplication est configurée par groupe HSS dans votre inventaire :
hss:
hosts:
site-a-hss01:
ansible_host: 10.80.12.140
site-a-hss02:
ansible_host: 10.80.12.141
vars:
omnihss:
database_type: postgres
database_host: localhost
database_port: 5432
database_name: omnihss
database_username: omnihss
database_password: "secure_password"
replication:
enabled: true
Paramètres Ansible
| Paramètre | Type | Requis | Par Défaut | Description |
|---|---|---|---|---|
database_type | Chaîne | Non | postgres | Backend de base de données. Doit être postgres pour la réplication. |
database_host | Chaîne | Non | localhost | Hôte PostgreSQL. Utilisez localhost lorsque Postgres fonctionne sur le même hôte qu'OmniHSS. |
database_port | Entier | Non | 5432 | Port PostgreSQL. |
database_name | Chaîne | Non | omnihss | Nom de la base de données. |
database_username | Chaîne | Oui | - | Utilisateur PostgreSQL. Doit avoir les privilèges CREATEDB et REPLICATION. |
database_password | Chaîne | Oui | - | Mot de passe PostgreSQL. |
replication.enabled | Booléen | Non | false | Activer la réplication logique bidirectionnelle. Lorsque true, le rôle Ansible configure automatiquement les publications, les souscriptions et les entrées pg_hba.conf. |
Découverte des Pairs
Les pairs sont découverts automatiquement à partir de deux sources :
- Groupe d'inventaire local : Tous les autres hôtes dans le groupe Ansible
hss - Sites distants : Entrées dans
connected_sites.hssà partir deprod_master_peers.yml
Aucune configuration de pair par hôte n'est requise. Ajouter un hôte au groupe hss ou à connected_sites.hss et exécuter le playbook est suffisant.
Pairs de Sites Distants (prod_master_peers.yml)
Pour la réplication inter-site à travers des emplacements géographiques :
# group_vars/prod_master_peers.yml
connected_sites:
hss:
- remote-site-hss01: 10.80.20.140
- remote-site-hss02: 10.80.20.141
Configuration PostgreSQL
Le rôle Ansible configure automatiquement les paramètres PostgreSQL suivants lorsque la réplication est activée :
| Paramètre | Valeur | But |
|---|---|---|
wal_level | logical | Requis pour la réplication logique. Inclut les données de ligne complètes dans le WAL. |
max_wal_senders | 10 | Maximum de processus d'envoi WAL concurrents (un par abonné). |
max_replication_slots | 10 | Maximum de slots de réplication. Chaque pair utilise un slot. |
listen_addresses | * | Accepter les connexions des sites pairs. |
Le rôle ajoute également des entrées pg_hba.conf pour permettre les connexions de réplication depuis chaque IP de pair découverte.
Gestion des Pairs
Ajouter un Nouveau Site
- Ajoutez le(s) nouvel(s) hôte(s) au groupe d'inventaire
hss, ou ajoutez-le àconnected_sites.hssdansprod_master_peers.yml - Exécutez le playbook OmniHSS
Le rôle va :
- Installer PostgreSQL et OmniHSS sur le nouvel hôte
- Exécuter les migrations de base de données
- Créer une publication pour le nouveau site
- Créer des souscriptions à tous les pairs existants
- Mettre à jour
pg_hba.confsur tous les pairs existants pour permettre le nouveau site - Créer des souscriptions des pairs existants vers le nouveau site
Supprimer un Site
ansible-playbook -i hosts site.yml --tags hss-remove-peer \
-e "peer_name=site_b confirm_remove=yes"
Le paramètre confirm_remove=yes est requis comme mesure de sécurité. Sans cela, le playbook refuse de continuer et affiche ce qui se passerait.
Supprimer un pair :
- Supprime la souscription (arrête la réplication entrante depuis ce pair)
- Supprime l'IP du pair de
pg_hba.conf - Les données déjà répliquées depuis le pair restent dans la base de données locale
- La souscription du site pair à ce site doit être supprimée séparément sur le pair
Ajouter un Pair Ad-Hoc
Pour les cas où vous devez ajouter un pair en dehors du flux standard du playbook :
ansible-playbook -i hosts site.yml --tags hss-add-peer \
-e "peer_name=site_b peer_host=10.80.20.140"
Surveillance
Métriques Prometheus
Le service postgres_exporter s'exécute sur chaque hôte HSS sur le port 9187, exposant les métriques PostgreSQL à Prometheus.
Métriques de Réplication
| Métrique | Type | Description |
|---|---|---|
pg_replication_slots_active | Gauge | 1 si le slot de réplication est actif (pair connecté), 0 si inactif |
pg_replication_slots_pg_wal_lsn_diff | Gauge | Latence de réplication en octets. Distance entre la position WAL actuelle et la dernière position confirmée du pair |
pg_stat_replication_pg_current_wal_lsn_bytes | Gauge | Position WAL actuelle sur ce nœud |
Exemples de Requêtes Prometheus
# Slot de réplication actif (1 = connecté, 0 = d��connecté)
pg_replication_slots_active{slot_name=~"sub_from_.*"}
# Latence de réplication en mégaoctets
pg_replication_slots_pg_wal_lsn_diff / 1048576
# Alerte : slot de réplication inactif pendant plus de 60 secondes
pg_replication_slots_active == 0
Alertes Recommandées
| Alerte | Condition | Sévérité | Description |
|---|---|---|---|
| Slot de Réplication Inactif | pg_replication_slots_active == 0 pendant 60s | Critique | Le pair est déconnecté. Le WAL s'accumule. |
| Latence WAL Excessive | pg_replication_slots_pg_wal_lsn_diff > 104857600 pendant 5m | Avertissement | La latence de réplication dépasse 100 Mo. Le pair peut être lent ou le lien dégradé. |
| Slot WAL Perdu | Le statut WAL est lost | Critique | Le slot a été invalidé. Le pair nécessite un re-seeding complet. |
Validation Ansible
Le playbook OmniHSS valide la santé de la réplication à la fin de chaque exécution. Il vérifie :
- Tous les travailleurs de souscription sont vivants
- Tous les slots de réplication sont actifs
- La latence WAL est dans le seuil (100 Mo par défaut)
- Le statut du slot WAL est
reservedouextended(paslost)
Si une assertion échoue, le playbook échoue avec un message d'erreur clair identifiant le problème.
Validation Manuelle
# Vérifiez que les travailleurs de souscription sont vivants
sudo -u postgres psql -d omnihss -c \
"SELECT subname, pid IS NOT NULL as worker_alive FROM pg_stat_subscription;"
# Vérifiez les slots de réplication et la latence
sudo -u postgres psql -d omnihss -c \
"SELECT slot_name, active,
pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn) as lag_bytes,
wal_status
FROM pg_replication_slots WHERE slot_type = 'logical';"
# Comparez les comptes d'abonnés entre les sites
sudo -u postgres psql -d omnihss -c "SELECT count(*) FROM subscriber;"
Dépannage
Travailleur de Souscription Mort
Symptômes : pg_stat_subscription montre pid IS NULL pour une souscription. La validation Ansible échoue avec "Travailleurs morts."
Causes Courantes :
- La table existe sur le publisher mais pas sur l'abonné (incompatibilité DDL)
- Conflit de clé dupliquée d'un enregistrement inséré manuellement
- Pair injoignable pendant une période prolongée entraînant l'invalidation du slot WAL
Résolution :
- Vérifiez les journaux PostgreSQL pour l'erreur spécifique :
journalctl -u postgresql | grep "logical replication" | tail -20 - Si incompatibilité DDL : appliquez la migration manquante sur ce site, puis le travailleur redémarrera automatiquement
- Si clé dupliquée : résolvez le conflit manuellement, puis réactivez la souscription :
ALTER SUBSCRIPTION sub_from_<pair> ENABLE;
Slot de Réplication Inactif
Symptômes : pg_replication_slots montre active = false. Alerte Prometheus se déclenche.
Causes Courantes :
- Problème de connectivité réseau entre les sites
- PostgreSQL sur le site pair est arrêté
- Pare-feu bloquant le port 5432 depuis l'IP du pair
Résolution :
- Vérifiez la connectivité réseau avec le pair :
pg_isready -h <peer_ip> -U <db_user> -d omnihss - Vérifiez que PostgreSQL sur le site pair fonctionne
- Vérifiez que les règles de pare-feu autorisent le port 5432 depuis l'IP de ce site
Le travailleur de souscription se reconnectera automatiquement lorsque le pair deviendra joignable.
Slot WAL Perdu
Symptômes : pg_replication_slots montre wal_status = 'lost'. La validation Ansible échoue avec "WAL SLOT CRITIQUE."
Cause : Le pair a été déconnecté si longtemps que le WAL conservé a dépassé max_slot_wal_keep_size et a été nettoyé.
Résolution : Le pair nécessite un re-seeding complet :
- Supprimez la souscription cassée sur ce site :
DROP SUBSCRIPTION sub_from_<pair>; - Supprimez le slot cassé sur le site pair :
SELECT pg_drop_replication_slot('sub_from_<this_site>'); - Réexécutez le playbook OmniHSS. Il recrée la souscription avec
copy_data = truepour effectuer une synchronisation initiale.
Latence WAL Excessive
Symptômes : pg_replication_slots_pg_wal_lsn_diff est grand et en croissance. Alerte Prometheus se déclenche.
Causes Courantes :
- Lien inter-site à haute latence ou congestionné
- Site pair sous forte charge (le travailleur d'application ne peut pas suivre)
- Grande opération en bloc (par exemple, provisionnement massif) générant un volume WAL significatif
Résolution :
- Vérifiez si la latence est en croissance ou stable :
SELECT slot_name,
pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn) as lag_bytes
FROM pg_replication_slots WHERE slot_type = 'logical'; - Si stable : le pair applique des changements mais est en retard. Il rattrapera.
- Si en croissance : enquêtez sur le lien réseau ou la charge du site pair.
- Pour les opérations en bloc : la latence pendant l'opération est attendue et se résoudra après la fin de l'opération.
Coordination des Migrations de Schéma
Important : Les changements de schéma de base de données (migrations) ne se répliquent pas via la réplication logique. Lors du déploiement d'une nouvelle version d'OmniHSS qui inclut des changements de schéma :
- Appliquez la migration sur tous les sites avant de déployer le code d'application qui dépend de nouvelles colonnes/tables
- Le playbook Ansible gère cela automatiquement. Il exécute des migrations sur chaque hôte
- Si vous déployez manuellement, exécutez les migrations sur tous les sites d'abord :
/opt/omnihss/bin/hss rpc "Hss.Command.Database.migrate()"