知识卡片
Online DDL问题的解法:从原生锁表到基于影子表的异步数据迁移
内容
原生MySQL执行DDL(如加字段、加索引)时需要锁表,锁表期间业务完全无法写入数据,对一个数据量大、访问频繁的核心表而言,这个影响是灾难性的——大表做DDL长期以来是DBA最痛苦的操作之一。这个问题的解法(以Facebook OSC和后来被Percona用Perl重写、如今广泛使用的pt-online-schema-change为代表)核心思路是绕开”直接在原表上加锁修改”这条路径:先创建一张和原表结构一致、但已经应用了目标DDL变更的新表(影子表),然后通过触发器或类似机制,把原表上后续发生的所有写操作同步应用到这张影子表上,同时后台异步、分批地把原表里的存量数据迁移拷贝到影子表,等增量同步和存量迁移都追平之后,再用一次原子的表名切换操作,把影子表替换成正式表——整个过程业务侧几乎感知不到锁表带来的写入阻塞。这个方案不是没有代价:改表所需要的总时间比直接执行alter table要长得多(因为多了一整套建影子表、同步增量、迁移存量的流程),被修改的表还必须有唯一键或主键(同步和迁移逻辑依赖这个来做数据比对和定位),同一个MySQL端口上不能有太多这类操作并发执行(会给数据库带来额外负载)。这个案例给出了一条应对”某个操作天然需要独占资源、但又不能接受长时间阻塞”这类问题的通用思路:与其想办法缩短”独占式操作”本身的耗时,不如干脆绕开对原资源的直接独占——先在一份影子副本上完成变更,再通过持续同步让影子副本追平原资源的最新状态,最后用一次原子切换完成交接,把原本”长时间独占”的问题转化成”额外的迁移时间成本+一次极短的原子切换”,用总耗时的增加换取业务无感知这个更重要的目标。
参考来源
- 位置:《高可用架构(第1卷)》第5章《运维保障》"5.3 单表60亿记录等大数据场景的MySQL优化和运维之道"节,"5.3.3 数据库运维规范"(源文件:_epub-src/OEBPS/Text/Chapter5_3_4.xhtml)
- 结论依据:原文说明"原生MySQL执行DDL时需要锁表,且在锁表期间业务无法写入数据……现在建议使用Facebook OSC,这种思路更优雅……pt-online-schema-change……使用的优点有:无阻塞写入……使用的限制有:改表时间会比较长……修改的表需要有唯一键或主键",直接支撑本卡片结论。
- 原始内容:原生MySQL执行DDL时需要锁表,且在锁表期间业务无法写入数据,这对服务影响很大……使用pt-online-schema-change的优点有:无阻塞写入……使用pt-online-schema-change的限制有:改表时间会比较长(和直接alter table改表相比)。修改的表需要有唯一键或主键。