DM 安全模式
安全模式的目的是在增量同步过程中,同一条 binlog event 能够在下游被重复同步且保证幂等性,从而确保增量同步能够“安全”进行。
DM 从 checkpoint 恢复数据同步任务后,可能重复执行某些 binlog 事件而导致下述问题:
- 当 DM 重启同步任务,并从 checkpoint 重新开始增量数据同步时,checkpoint 之后的部分数据可能已经在异常退出前被处理过了,从而导致部分 SQL 语句重复执行。
- 如果重复执行
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
并执行后,依旧会向下游插入重复记录。
因此,如果上游存在主键重复的数据,业务可以接受丢失重复数据和性能损失,你可以开启安全模式来忽略数据重复错误。