无锁结构变更方案对比

锁表变更对业务甚至是致命的,DDL无锁变更通过引入非触发器的方式可以解决大表无锁变更这个难题。本文介绍几种无锁结构变更方案的对比。

线上业务不建议直接进行DDL操作,通常有几种做法来避免影响业务:

  • 业务低峰期变更:

    合适的变更窗口以及窗口长度直接影响变更结果。过大的表由于在变更窗口内未执行完成,仍将影响业务。

  • 备库修改后切换主备:

    需要存在主备实例,并能够在合适窗口进行主备切换。

  • Online修改工具:

    • PT-Online(PT-Online-Schema-Change):工作原理是创建和源表A一样的表A_gst执行DDL操作,同时在A上创建一个DML触发器,然后将A中的数据拷贝到A_gst,在拷贝过程中产生的增量变更就用触发器完成同步更新。拷贝结束后执行两张表的rename操作完成变更。

    • OSC(OnlineSchemaChange):工作原理和pt-online-schema-change基本一致,不同的地方是它采用的是异步模式,在A_gst的基础上创建了一张日志表,触发器的条目更新将直接落在日志表中,后台进程将日志表中的条目应用到A_gst表。这样整个流程上是异步的,也能够控制回放速度。

    • gh-ost:与上面两种变更流程基本一致,但是没有使用触发器的设计,所以增量变更的数据来源不是触发器,而是Binlog文件。订阅读取该文件中A表的变更记录,将记录解析并应用到A_gst表。这样的数据对于gst表回放非常有利,Binlog中存储的都是A表的记录,易于直接读取和应用。

      说明

有无触发器对比

  • 有触发器:

    基于触发器设计的工具代码逻辑相对简单,大部分数据上的工作交给了触发器去完成,包含数据库的隐式处理、数据类型以及切换等相关操作,简化了进行实时表迁移的大量流程。

  • 无触发器:

    无触发器设计最大的优点是和数据库的工作负载解耦。触发器的设计无论何种情况下,源表的DML都会同时在另外一张表上同步操作。非触发器设计将这个过程解耦,即新表的写入和源表的写入不存在直接依赖。

对比项

有触发器

无触发器

数据库开销

触发器是一个存储过程,随着业务的DML,触发器的执行必然存在开销,业务繁忙时更甚。

触发器开销占用的问题不存在。

作为一个伪装的SLAVE订阅主、备的Binlog事件,将其中的源表事件过滤下来并回放到目标表。这个过程和源表的变更没有任何关系,也不需要数据库上任何存储过程等干涉这个写入。

触发器将两张表的操作关联到一个事务空间中,所以锁的竞争会增加,即一个事务中的两张表锁并集。触发器的设计中拷贝数据和变更数据只能并行,无疑将会增加锁竞争。

无触发器解耦了源表和目标表的依赖,所以锁竞争也就不复存在。

关于目标表上的拷贝和更新时的竞争,我们在逻辑上使用交叉执行的方式避免和降低锁竞争,虽然会影响变更效率,但是很显然降低了数据库负载。

异常处理

触发器的设计,意味着触发器永远保持运行无法暂停。当服务器繁忙、主备延迟、异常等情况时,在变更流程中的任何一个阶段都无法取消触发器,强行取消将导致变更中断或数据丢失,从而导致A_gst表数据不准确。

订阅Binlog的线程随时可以暂停或者放慢速度,在系统繁忙和主备延迟较大时对工作中的应用开启节流,避免问题扩大。

可靠性验证

在验证方案上我们期望得到任务的预期时间等信息,在备库上创建触发器并模拟,前提需要在Statement模式下。

ROW模式下无法模拟,因为在主库上的触发器产生的数据效果重放到了备库上。另外,即使是Statement模式,MySQL的回放是单线程的,Statement的单线程执行无法模拟、复现主库上的并发场景,也就无法验证和测试并发和锁相关的问题。

基于Binlog在主库和备库上操作Online没有任何区别,避免对线上业务的干扰或资源争用。另外,通过在备库上模拟操作变更,实际并不切换源表和目标表,可以对源表和目标做校验来持续验证可靠性。

代码复杂性

主要依赖触发器的同步和数据库内部操作,工具的作用相对较小。

非触发器的设计基于Binlog,有很大的自由度,但是复杂度会大幅增加。

需要注册为一个SLAVE、订阅事件并转为SQL重新写入,异常处理相对简单的如处理连接失败、复制延迟以及数据类型等,其他程序的异常诸如程序负载、不可控异常等都要在代码上进行关注。同时逻辑中需要包含大量的代码以及更复杂的并发控制逻辑。

网络流量

触发器在数据库的内部处理数据。

非触发器需要订阅事件流以及回写数据,这将使用到主机间的流量,占用MySQL的进程流量。

代码的复杂性依赖缜密的算法逻辑,完善的测试用例集来保证健壮性和稳定性。但是相比之下,它带来了更多的好处,比如可以指定时间切表、拷贝或者增量流量控制等一些额外的功能。

DMS无锁结构变更与gh-ost工具对比

DMS无锁结构变更与同样采用无触发器的gh-ost工具的优劣势对比:

对比项

DMS无锁结构变更

gh-ost

全量拷贝阶段

拷贝限流

Y:手动或自动

Y:手动

数据一致性校验

Y

N

异常容错

Y

Y:部分支持

拷贝性能自适应

Y

N

增量回放阶段

回放限流

Y:手动或自动

Y:手动

多线程回放

Y

N

数据一致性校验

Y

N

异常容错

Y

Y:部分支持

回放性能自适应

Y

N

备库订阅

N

Y

切换表阶段

切换原子性

Y

Y

表副本延迟删除

Y

N

切换窗口设置

Y

Y

锁保护机制

Y

N

功能性

备库变更

N

Y

DTS(数据传输)无缝衔接

Y

N

变更策略设置(DDL算法识别)

Y

N

RocksDB引擎

Y

N

ToKuDB引擎

Y

N

InnoDB引擎

Y

Y

虚拟列变更

Y

N

Json列变更

Y

Y

多值索引和函数索引

Y

-

优化表空间(Optimize)

Y

N

表副本延迟删除

Y

N

安装部署

Y:免安装

Y:本地安装

白屏化运维

Y

N

执行进度可视化

Y

N

  • Y:支持该功能。

  • N:不支持该功能。

  • -:不明确是否支持该功能。