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
operations, missing data is also considered as a
conflict, but does not result in an error and such
operations will simply be skipped.
Additional logging is triggered, and the conflict statistics are collected (displayed in the
pg_stat_subscription_stats
view)
in the following conflict cases:
insert_exists
#
Inserting a row that violates a NOT DEFERRABLE
unique constraint. Note that to log the origin and commit
timestamp details of the conflicting key,
track_commit_timestamp
should be enabled on the subscriber. In this case, an error will be
raised until the conflict is resolved manually.
update_origin_differs
#
Updating a row that was previously modified by another origin.
Note that this conflict can only be detected when
track_commit_timestamp
is enabled on the subscriber. Currently, the update is always applied
regardless of the origin of the local row.
update_exists
#
The updated value of a row violates a NOT DEFERRABLE
unique constraint. Note that to log the origin and commit
timestamp details of the conflicting key,
track_commit_timestamp
should be enabled on the subscriber. In this case, an error will be
raised until the conflict is resolved manually. Note that when updating a
partitioned table, if the updated row value satisfies another partition
constraint resulting in the row being inserted into a new partition, the
insert_exists
conflict may arise if the new row
violates a NOT DEFERRABLE
unique constraint.
update_missing
#The tuple to be updated was not found. The update will simply be skipped in this scenario.
delete_origin_differs
#
Deleting a row that was previously modified by another origin. Note that
this conflict can only be detected when
track_commit_timestamp
is enabled on the subscriber. Currently, the delete is always applied
regardless of the origin of the local row.
delete_missing
#The tuple to be deleted was not found. The delete will simply be skipped in this scenario.
multiple_unique_conflicts
#
Inserting or updating a row violates multiple
NOT DEFERRABLE
unique constraints. Note that to log
the origin and commit timestamp details of conflicting keys, ensure
that track_commit_timestamp
is enabled on the subscriber. In this case, an error will be raised until
the conflict is resolved manually.
Note that there are other conflict scenarios, such as exclusion constraint violations. Currently, we do not provide additional details for them in the log.
The log format for logical replication conflicts is as follows:
LOG: conflict detected on relation "schemaname
.tablename
": conflict=conflict_type
DETAIL:detailed_explanation
. {detail_values
[; ... ]}. wheredetail_values
is one of:Key
(column_name
[, ...])=(column_value
[, ...])existing local tuple
[(column_name
[, ...])=](column_value
[, ...])remote tuple
[(column_name
[, ...])=](column_value
[, ...])replica identity
{(column_name
[, ...])=(column_value
[, ...]) | full [(column_name
[, ...])=](column_value
[, ...])}
The log provides the following information:
LOG
schemaname
.tablename
identifies the local relation involved in the conflict.
conflict_type
is the type of conflict that occurred
(e.g., insert_exists
, update_exists
).
DETAIL
detailed_explanation
includes
the origin, transaction ID, and commit timestamp of the transaction that
modified the existing local tuple, if available.
The Key
section includes the key values of the local
tuple that violated a unique constraint for
insert_exists
, update_exists
or
multiple_unique_conflicts
conflicts.
The existing local tuple
section includes the local
tuple if its origin differs from the remote tuple for
update_origin_differs
or delete_origin_differs
conflicts, or if the key value conflicts with the remote tuple for
insert_exists
, update_exists
or
multiple_unique_conflicts
conflicts.
The remote tuple
section includes the new tuple from
the remote insert or update operation that caused the conflict. Note that
for an update operation, the column value of the new tuple will be null
if the value is unchanged and toasted.
The replica identity
section includes the replica
identity key values that were used to search for the existing local
tuple to be updated or deleted. This may include the full tuple value
if the local relation is marked with
REPLICA IDENTITY FULL
.
column_name
is the column name.
For existing local tuple
, remote tuple
,
and replica identity full
cases, column names are
logged only if the user lacks the privilege to access all columns of
the table. If column names are present, they appear in the same order
as the corresponding column values.
column_value
is the column value.
The large column values are truncated to 64 bytes.
Note that in case of multiple_unique_conflicts
conflict,
multiple detailed_explanation
and detail_values
lines
will be generated, each detailing the conflict information associated
with distinct unique
constraints.
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.
The additional details regarding conflicting rows, such as their origin and
commit timestamp can be seen in the DETAIL
line of the
log. But note that this information is only available when
track_commit_timestamp
is enabled on the subscriber. Users can use this information to decide
whether to retain the local change or adopt the remote alteration. For
instance, the DETAIL
line in the above log indicates that
the existing row was modified locally. Users can manually perform a
remote-change-win.
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
.