DM 安全模式

    安全模式的目的是在增量同步过程中,同一条 binlog event 能够在下游被重复同步且保证幂等性,从而确保增量同步能够“安全”进行。

    DM 从 checkpoint 恢复数据同步任务后,可能重复执行某些 binlog 事件而导致下述问题:

    1. 当 DM 重启同步任务,并从 checkpoint 重新开始增量数据同步时,checkpoint 之后的部分数据可能已经在异常退出前被处理过了,从而导致部分 SQL 语句重复执行
    2. 如果重复执行 INSERT 操作,会导致主键或唯一索引冲突,引发同步中断;如果重复执行 UPDATE 操作,会导致不能根据筛选条件找到之前对应的更新记录。

    在安全模式下,通过改写 SQL 语句,DM 可以解决上述问题。

    安全模式通过 SQL 语句改写来保证 binlog event 的幂等性。具体来说,在安全模式下:

    • INSERT 语句会被改写成 REPLACE 语句。
    • UPDATE 语句会被分析,得到该语句涉及的行的主键或唯一索引的值,然后改写成 DELETE + REPLACE 语句 :先根据主键或唯一索引的定位删除对应的行,然后使用 REPLACE 语句插入一条最新值的行记录。

    REPLACE 操作是 MySQL 特有的数据插入语法。使用 REPLACE 语法插入数据时,如果新插入的数据和现有数据存在主键或唯一约束冲突,MySQL 会删除所有冲突的记录,然后再执行插入记录操作,相当于“强制插入”的操作。具体请参考 。

    启用安全模式后,上述 SQL 语句再次在下游执行时,会被改写为下面的 SQL 语句:

    上述语句中,UPDATE 被改写为 DELETE + REPLACE,而不是 DELETE + INSERT。如果这里使用 INSERT,那么 id = 999 的记录在已经存在的情况下重复插入时,数据库会报错主键冲突。因此这里使用了 REPLACE,新的记录会替换之前已经插入的记录。

    通过这样的语句改写,在进行重复的插入或更新操作时,DM 都会使用执行该操作后的行数据来覆盖之前已经存在的行数据。这样保证了插入和更新操作的可重复执行。

    当 DM 从 checkpoint 恢复增量同步任务(例如 worker 重启,网络中断重连等)时,会自动开启一段时间的安全模式。开启安全模式的逻辑,与 checkpoint 中的 safemode_exit_point 信息相关。当一个增量同步任务异常暂停时,DM 会先尝试将内存中所有的 DML 全部同步到下游,然后记录当前内存中从上游拉取到的最新的 binlog 位置点,记作 safemode_exit_point,把 safemode_exit_point 保存在异常暂停之前最后一个 checkpoint 当中。

    当 DM 从 checkpoint 恢复增量同步任务时,会根据下面的判断逻辑来开启安全模式:

    手动开启

    你可以通过调整增量任务配置文件中 syncer 的配置项 safe-mode,控制是否需要全程开启安全模式。safe-mode 是布尔类型参数,默认为 false。如果设置为 true,则表示在增量同步的全过程中都会开启安全模式。例如,下面是一个开启了安全模式的任务配置示例:

    • 安全模式对于增量同步有额外开销。频繁的 DELETE + REPLACE 操作会带来主键或唯一索引的频繁变化,带来了比单纯 UPDATE 语句更大的性能开销。
    • 安全模式会强制替换主键相同的记录,可能导致下游的记录数据丢失。如果由于上游分片表合并导入下游的配置不当,可能导致在上游合并导入到下游数据库的时候,出现大量的主键或唯一索引冲突。如果此时全程开启安全模式,会导致下游大量的数据丢失,并且可能无法从任务中看到有任何的异常,导致大量数据不一致。
    • 安全模式依赖于通过主键或唯一索引来判断冲突。如果下游数据库对应的表没有主键或唯一索引,会导致 REPLACE 语句无法实现替换插入的目的。这种情况下,即使开启了安全模式,DM 将 语句改写成 REPLACE 并执行后,依旧会向下游插入重复记录。

    因此,如果上游存在主键重复的数据,业务可以接受丢失重复数据和性能损失,你可以开启安全模式来忽略数据重复错误。