La réplication logique se comporte de la même manière pour les opérations DML
dans le sens où les données seront mises à jour même si la modification a été
faite en local sur la base abonnée. Si les données entrantes entrainent des
violations de contrainte d'intégrité, la réplication s'arrête. Cela sera
référencé comme un conflit. Lorsque l'on réplique des
opérations UPDATE
ou DELETE
, les
données manquantes sont aussi considérées comme un
conflit, mais cela ne se termine pas avec une erreur
et de telles opérations seront simplement ignorées.
Une trace supplémentaire est déclenchée et les statistiques sur les conflits
sont enregistrées (disponibles dans la vue
pg_stat_subscription_stats
)
dans les cas suivants conflict :
insert_exists
#
Insérer une ligne qui viole une contrainte d'unicité NOT
DEFERRABLE
. Notez que pour tracer des détails comme l'origine
et la date et heure de validation de la clé en conflit,
track_commit_timestamp
doit être activé sur l'abonné. Dans ce cas, une erreur sera levée
jusqu'à ce que le conflit soit résolu manuellement.
update_origin_differs
#
Mettre à jour une ligne qui a été précédemment modifiée par une autre
origine. Notez que ce conflit peut seulement être détecté quand
track_commit_timestamp
est activé sur l'abonné. Actuellement, une mise à jour est toujours
appliquée quelque soit l'origine de la ligne locale.
update_exists
#
La valeur mise à jour d'une ligne viole la contrainte d'unicité
NOT DEFERRABLE
. Notez que pour tracer des détails
comme l'origine et la date et heure de validation de la clé en conflit,
track_commit_timestamp
doit être activé sur l'abonné. Dans ce cas, une erreur sera levée
jusqu'à ce que le conflit soit résolu manuellement. Notez que lors de la
mise à jour d'une table partitionnée, si la valeur de la ligne mise à
jour satisfait une autre contrainte de partitionnement résultant en
l'insertion de la ligne dans une nouvelle partition, le conflit
insert_exists
peut survenir si la nouvelle ligne viole
la contrainte d'unicité NOT DEFERRABLE
.
update_missing
#La ligne à mettre à jour n'a pas été trouvée. La mise à jour sera simplement ignorée dans ce scénario.
delete_origin_differs
#
Supprimer une ligne qui a été modifiée précédemment par une autre
origine. Notez que ce conflit peut seulement être détecté quand
track_commit_timestamp
est activé sur l'abonné. Actuellement, la suppression est toujours
appliquée quelque soit l'origine de la ligne locale.
delete_missing
#La ligne à supprimer n'a pas été trouvée. La suppression sera simplement ignorée dans ce scénario.
multiple_unique_conflicts
#
Insérer ou mettre à jour une ligne viole plusieurs contraintes d'unicité
NOT DEFERRABLE
. Notez que pour tracer des détails
comme l'origine et la date et heure des clés en conflit, il faut
s'assurer que
track_commit_timestamp
est activé sur l'abonné. Dans ce cas, une erreur sera levée jusqu'à ce
que le conflit soit résolu manuellement.
Notez qu'il y a d'autres scénarios de conflit comme par exemple les violations de contraintes d'exclusion. Actuellement, nous ne fournissons pas de détails supplémentaires dans les traces pour ces scénarios.
Le format de la trace pour les conflits de réplication logique ressemble à ceci :
LOG: conflict detected on relation "nom_schéma
.nom_table
": conflict=type_conflit
DETAIL:explication_détaillée
. {informations_supplémentaires
[; ... ]}. oùinformations_supplémentaires
fait partie de :Key
(nom_colonne
[, ...])=(valeur_colonne
[, ...])existing local tuple
[(nom_colonne
[, ...])=](valeur_colonne
[, ...])remote tuple
[(nom_colonne
[, ...])=](valeur_colonne
[, ...])replica identity
{(nom_colonne
[, ...])=(valeur_colonne
[, ...]) | full [(nom_colonne
[, ...])=](valeur_colonne
[, ...])}
La trace fournit les informations suivantes :
LOG
nom_schéma
.nom_table
identifie la relation locale impliquée dans le conflit.
type_conflit
est le type de conflit
survenu (par exemple insert_exists
,
update_exists
).
DETAIL
explication_détaillée
inclut l'origine, l'identifiant de transaction et les date et heure
de la transaction qui a modifié la ligne locale existante, si
disponible.
La section Key
inclut les valeurs de la clé de la
ligne locale qui a violé une contrainte d'unicité pour les conflits
insert_exists
, update_exists
ou
multiple_unique_conflicts
.
La section existing local tuple
inclut la ligne
locale si son origine diffère de la ligne distante pour les conflits
update_origin_differs
ou
delete_origin_differs
, ou si la valeur de la clé
entre en conflit avec la ligne distante pour les conflits
insert_exists
, update_exists
ou
multiple_unique_conflicts
.
La section remote tuple
inclut la nouvelle ligne
de l'opération distante d'insertion ou de mise à jour qui a causé le
conflit. Notez que pour une opération de mise à jour, la valeur de la
colonne de la nouvelle ligne sera NULL si la valeur n'est pas modifiée
ou placée dans un TOAST.
La section replica identity
inclut les valeurs de
la clé d'identité de réplicat qui ont été utilisé pour la ligne locale
existante qui doit être mise à jour ou supprimée. Cela peut inclure
la valeur complète de la ligne si la relation locale est marquée avec
REPLICA
IDENTITY FULL
.
nom_colonne
est le nom
de la colonne. Pour les cas existing local tuple
,
remote tuple
et replica identity
full
, les noms de colonne sont tracés uniquement si
l'utilisateur n'a pas le droit d'accéder à toutes les colonnes de la
table. Si les noms de colonne sont présents, ils apparaissent dans le
même ordre que les valeurs correspondantes.
valeur_colonne
est la
valeur de la colonne. Les valeurs volumineuses sont tronquées à
64 octets.
Notez que dans le cas d'un conflit
multiple_unique_conflicts
, plusieurs lignes
explication_détaillée
et informations_supplémentaires
seront générées, chacune détaillant l'information de conflit associée
à des contraintes d'unicité distinctes.
Les opérations de réplication logique sont réalisées avec les droits du
propriétaire de la souscription. Les échecs de droit sur les tables cibles
causeront des conflits de réplication, tout autant que l'activation de politiques de sécurité au niveau ligne sur
des tables cibles et pour lesquels le propriétaire de la souscription est
sujet des politiques de sécurité, sans chercher si une politique rejetterait
habituellement les opérations INSERT
,
UPDATE
, DELETE
ou
TRUNCATE
en cours de réplication. Cette restriction sur
les politiques de sécurité niveau ligne pourrait être supprimée dans une
prochaine version de PostgreSQL.
Lorsqu'un conflit entraine une erreur, cela stoppe la réplication ; Le conflit devra être résolu manuellement par un utilisateur. Des informations détaillées concernant le conflit seront disponibles dans les journaux applicatifs de l'instance abonnée.
La résolution peut être réalisée, soit en changeant les données ou les droits sur la base abonnée pour qu'elles ne soient plus en conflit avec les données entrantes ou en évitant les transactions qui sont en conflit avec les données existantes. Quand un conflit produit une erreur, la réplication ne peut pas continuer et le processus worker de la réplication logique émet un message du type suivant dans les journaux applicatifs de l'abonné :
ERROR: conflict detected on relation "public.test": conflict=insert_exists DETAIL: Key already exists in unique index "t_pkey", which was modified locally in transaction 740 at 2024-06-26 10:47:04.727375+08. Key (c)=(1); existing local tuple (1, 'local'); remote tuple (1, 'remote'). CONTEXT: processing remote data for replication origin "pg_16395" during "INSERT" for replication target relation "public.test" in transaction 725 finished at 0/14C0378
Le LSN de la transaction qui contient le changement violant la contrainte et
le nom d'origine de réplication peuvent être trouvés à partir du journal
applicatif du serveur (LSN 0/14C0378 et origine de réplication
pg_16395
dans le cas ci-dessus). La transaction qui a
produit le conflit peut être ignorée en utilisant l'instruction
ALTER SUBSCRIPTION
... SKIP
avec le LSN final (LSN
0/14C0378). Le LSN final pourrait être un LSN sur lequel la transaction est
validée ou préparée sur le publieur. La transaction peut aussi être ignorée
en appelant la fonction pg_replication_origin_advance()
.
Avant d'utiliser cette fonction, la souscription doit être désactivée
temporairement soit par
ALTER SUBSCRIPTION ... DISABLE
soit en utilisant l'option disable_on_error
de la souscription. Ensuite, vous pouvez utiliser la fonction
pg_replication_origin_advance()
avec
node_name
(pg_16395
) et le LSN
suivant du LSN final (0/14C0379). La position actuelle des origines peut être
trouvée dans la vue système pg_replication_origin_status
.
Merci de noter qu'ignorer la transaction complète inclut d'ignorer des
changements qui pourraient ne pas violer des contraintes. Ceci peut rendre
l'abonné incohérent très facilement.
Les détails supplémentaires concernant les lignes en conflit, comme leur
origine et l'horodatage de la validation sont disponibles dans la ligne
DETAIL
de la trace. Mais notez que cette information est
uniquement disponible quand
track_commit_timestamp
est activé sur l'abonné. Les utilisateurs peuvent utiliser cette information
pour décider s'il faut conserver la modification locale ou adopter la
modification distante. Par exemple, la ligne DETAIL
dans
la trace ci-dessus indique que la ligne existante a été modifiée localement.
Les utilisateurs peuvent réaliser manuellement un
.
Quand le mode streaming
vaut parallel
, le LSN final des transactions en échec peut ne pas être
journalisé. Dans ce cas, il peut être nécessaire de changer le mode
de flux (streaming) à on
ou off
et provoquer
les même conflits encore pour que le LSN final des transactions échouées soit écrit dans
le journal du serveur. Pour l'utilisation du LSN final, veuillez vous reférer à
ALTER SUBSCRIPTION ... SKIP
.