对等 - 对等复制中的冲突检测

适用范围:SQL Server

通过对等事务复制,可以在拓扑中的任何节点插入、更新或删除数据并将数据更改传播到其他节点。 由于可在任何节点上更改数据,因此在不同节点上进行的数据更改可能会相互冲突。 如果在多个节点上修改了某一行,则将该行传播给其他节点时会导致冲突甚至丢失更新。

对等复制提供用于在对等拓扑中启用冲突检测的选项。 此选项有助于防止因未检测到的冲突而引起的各种问题,包括不一致的应用程序行为和丢失更新。 启用该选项后,默认情况下,发生冲突的更改将被视为导致分发代理失败的关键错误。 发生冲突时,拓扑将始终处于不一致的状态,直至冲突得以解决而且拓扑中的数据保持一致。

注意

为了避免潜在的数据不一致性,即便已经启用了冲突检测功能,也应尽力避免对等拓扑中发生冲突。 为了确保仅在某一个节点上执行特定行的写入操作,访问并更改数据的应用程序必须对其插入、更新和删除操作进行分区。 分区可确保在一个节点上对给定行进行的修改可以在其他节点修改该行之前,与拓扑中的所有其他节点同步。 如果应用程序需要完善的冲突检测与解决功能,请使用合并复制。 有关详细信息,请参阅合并复制检测并解决合并复制冲突

了解冲突和冲突检测

在单个数据库中,不同应用程序对同一行进行的更改不会导致冲突。 原因在于,事务已经过序列化,而锁将处理并发更改。 在异步分布式系统(如对等复制)中,事务独立作用于每个节点,而且没有用来跨多个节点对事务进行序列化的机制。 可以使用两阶段提交之类的协议,但是这会显著影响性能。

在对等复制之类的系统中,在单个对等节点上提交更改之后将检测不到冲突。 相反,在复制这些更改并将其应用于其他对等节点之后,才能够检测到这些更改。 在对等复制中,用于将更改应用于每个节点的存储过程会基于每个已发布表中的一个或多个隐藏列来检测冲突。

在 SQL Server 2019 (15.x) CU 13 之前的版本中,SQL Server 会将一个隐藏列添加到每个已发布的表中:$sys_p2p_cd_id。 该隐藏列所存储的 ID 将您为每个节点指定的“ 发起方 ID”与行版本结合起来。

在 SQL Server 2019 (15.x) CU 13 和更高版本中,如果使用 @p2p_conflictdetection_policy = 'lastwriter' 创建对等发布,则 SQL Server 会将一个额外的隐藏列添加到每个已发布的表中:$sys_md_cd_id。 此隐藏列将日期时间存储为 datetime2 数据类型。

在同步期间,分发代理会针对每个表执行同步过程。 这些过程会应用来自其他对等节点的插入、更新和删除操作。 如果某个过程在读取该隐藏列的一个或多个值时检测到冲突,将会引发严重级别为 16 的错误 22815:

A conflict of type '%s' was detected at peer %d between peer %d (incoming), transaction id %s and peer %d (on disk), transaction id %s

默认情况下,此错误会导致分发代理停止向该节点应用所做的更改。 有关如何处理所检测到冲突的信息,请参阅处理冲突

注意

隐藏列只能由通过专用管理员连接 (DAC) 登录的用户来访问。 有关 DAC 的信息,请参阅用于数据库管理员的诊断连接

对等复制检测到下列类型的冲突:

  • 插入-插入

    每个表中所有参与对等复制的行都使用主键值进行唯一标识。 在将具有相同键值的行插入到多个节点时,会发生插入-插入冲突。

  • 更新-更新

    在多个节点上更新了同一行时发生。

  • 插入-更新

    在以下情况下发生:在一个节点上更新了某行,但是在另一个节点上删除了该行,然后又重新插入该行。

  • 插入-删除

    在以下情况下发生:在一个节点上删除了某行,但是在另一个节点上删除了该行,然后又重新插入该行。

  • 更新-删除

    在以下情况下发生:在一个节点上更新了某行,但是在另一个节点上删除了该行。

  • 删除-删除

    在多个节点上删除了同一行时发生。

启用冲突检测

若要使用冲突检测,请为所有节点启用检测。 默认情况下,在 SQL Server Management Studio 中配置对等复制时会启用冲突检测。 我们建议您启用冲突检测,即使在应当不会有任何冲突时也是如此。 可以使用 Management Studio 或 Transact-SQL 存储过程来启用和禁用冲突检测:

  • 在 Management Studio 中,可以使用“发布属性”对话框的“订阅选项”页或配置对等拓扑向导的“配置拓扑”页来启用和禁用冲突检测。

    如果你使用 Management Studio 来配置冲突检测,则分发代理将配置为在检测到冲突时停止应用所做的更改。

  • 还可以使用以下存储过程启用和禁用检测:

    • sp_addpublication

    • sp_configure_peerconflictdetection

      如果您使用存储过程来配置冲突检测,则可以指定在检测到冲突时分发代理是否应当停止应用所做的更改。 默认值是让分发代理停止。 我们建议您使用默认设置。

处理冲突

对等复制中发生冲突时,会引发对等冲突检测警报。 请配置此警报,以便在发生冲突时收到通知。 有关警报的详细信息,请参阅对复制代理事件使用警报

在分发代理停止并且引发警报之后,请使用下列方法之一来处理所发生的冲突:

  • 从包含必需数据的节点的备份中重新初始化检测到冲突的节点(建议的方法)。 此方法可确保数据保持一致状态。

  • 尝试通过允许分发代理继续应用所做的更改,再次同步节点:

    1. 执行 sp_changepublication:为 @property 参数指定“p2p_continue_onconflict”,为 @value 参数指定 true

    2. 重新启动分发代理。

    3. 使用冲突查看器验证检测到的冲突,并确定所涉及的行、冲突类型以及入选方。 冲突可基于您在配置过程中指定的发起方 ID 值来解决:源自具有最高 ID 的节点的行将在冲突中入选。 有关详细信息,请参阅查看事务发布的数据冲突 (SQL Server Management Studio)

    4. 运行验证步骤以确保发生冲突的行能够正确收敛。 有关详细信息,请参阅验证已复制的数据

      注意

      如果在执行该步骤之后数据不一致,则必须在具有最高优先级的节点上手动更新行,然后允许从该节点传播所做的更改。 如果拓扑中不再有发生冲突的更改,则所有节点将保持一致状态。

    5. 执行 sp_changepublication:为 @property 参数指定“p2p_continue_onconflict”,为 @value 参数指定 false

使用“最后写入者胜出”自动处理冲突

从 SQL Server 2019 (15.x) CU 13 开始,可将对等复制配置为允许最近的插入或更新操作在冲突时胜出,以此自动解决冲突。 如果任一写入操作删除了行,则 SQL Server 允许该删除操作在冲突时胜出。 此方法称作“最后写入者胜出”。

使用存储过程来配置最后写入胜出。 请参阅配置最后写入者冲突检测和解决方案。 无法使用 SQL Server Management Studio 配置最后写入胜出。

注意

使用“最后写入者胜出”的对等复制依赖于使用同步的参与方节点时钟来提供可靠结果。 如果参与方服务器的时钟严重不同步,则冲突解决可能会提供意外和/或不需要的结果。 例如,如果服务器 A 的时钟准确,但服务器 B 的时钟滞后一周,则会选择服务器 A 在每次冲突时胜出,即使在客观上它不是最后一个更新行的服务器。 如果无法将时钟保持在解决结果准确度问题所需的容限范围内,建议选择另一种冲突解决策略。