MySQL 拿锁 即乐观等待的方式来拿锁MDL-X。问题:会导致DDL后续DML的阻塞。
第三方插件 pt-osc / gh-ost 采用copying method,空表然后select + insert,最后rename操作切换。问题:1. 饥饿。2.无脑copying,有一些instance DDL 秒级可完成。
MySQL DDL 分为三类:
Online DDL通常是instant 和大部分 inplace,特点是:执行DDL期间绝大多数时刻不锁表, 只有修改元数据的时候会锁表。
Binlog简介
Mysql
中有一个binlog
二进制日志,这个日志会记录下主服务器
所有修改了的SQL
语句,从服务器
把主服务器上的binlog
二进制日志,在指定的位置开始复制主服务器
所有修改的语句,在从服务器
上执行一遍。
简而言之就是,主服务器
会把create、update、delete
语句都记录到一个二进制文件中(binlog),从服务器
读取这个文件,执行一遍文件中记录的create、update、delete
语句。从而实现主从数据同步。
以一写多读为例,写节点在做DDL操作时,多个只读节点都会看到DDL过程中的实时数据。
避免长事务 + DDL导致 QPS为0的解决方案:DDL拿锁失败,进入短暂sleep,以允许DML进行,接着重新请求拿锁。
背景是分布式场景下,只读节点存在大查询、长事务导致DDL 拿不到MDL锁,需要手动kill拿到MDL锁的事务。或者开启Preemptive DDL,当只读节点通过物理复制,解析到当前表上有DDL操作时,只读节点会尝试获取表的MDL锁。如果此时表上存在大查询或长事务时,开启Preemptive DDL后,如果只读节点在预期时间内无法获得MDL锁,便会尝试kill掉占有MDL锁的线程,从而保证MDL锁同步的成功,解决DDL的饥饿问题。
实现DDL与DML更细粒度的并发控制,类似于InnoDB MVCC能力,DDL涉及到:文件操作/表数据变更/元信息变更/表缓存处理等一系列流程。
目前第一阶段,满足高频DDL和DML的MVCC能力,例如Instant Add Column。
目前云原生数据库基本都是存算分离+共享存储的架构,提供一写多读。云原生数据库依赖redo log (物理复制)来完成不同节点之间的数据同步,DDL做出的修改也需要进行同步(元数据/表数据/文件变更),同时又依赖分布式MDL锁提供实时和一致性的保证,MDL锁和物理复制(redo log耦合)会产生一系列问题。
主节点加快DDL写日志速度
只读节点加快物理复制速度