Bravoboy Software Development Engineer

基于redo log的强一致mysql集群--DDL

2024-06-15

背景

今天篇文章介绍一下为了支持强一致,DDL相关的改动。临时表不用做到强一致同步给follower节点,所以下面说的都是普通的用户表。我们之前的文章也介绍了raft模块嵌入到innodb存储引擎中,所以我们只支持innodb表强一致。
先介绍一下crash recover流程里面关于ibd文件的操作:

1. fil_scan_for_tablespaces扫描磁盘上的ibd文件,获取space_id和name信息<br/>
2. apply redo log,文件操作的redo log是在文件操作之后才写的,看到这类log说明文件操作已经成功,对于这类redo log,只是检查一下文件状态<br/>
3. Validate_files::validate检查mysql.tablespaces表里面的信息和ibd文件信息是否一致,包括文件名字,同时如果不是shutdown的话,还会检查space_id等信息<br/>
4. log_ddl->recover会扫描DDL_Log_Table表,回放文件操作<br/>

实现

create table

create table流程

1. 检查ibd文件是否存在,存在就直接返回失败<br/>
2. dd::create_table 创建内存dd::table对象,然后store, 要等整个DDL事务commit生效<br/>
3. innodb::create<br/>
3.1 分配table_id和space_id<br/>
3.2 写ddl_log,写入的操作都是刚好和create table相反的操作,用于回滚DDL操作<br/>
3.3 创建ibd文件<br/>
3.4 写redo log MLOG_FILE_CREATE<br/>
4 trx commit/rollback  DD数据生效,ddl_log删除<br/>
5 post_ddl commit操作啥都不干,rollback就回放DDL log<br/>

针对DDL操作的修改点:

1. 为了支持follower节点执行文件操作,MLOG_FILE_CREATE等类型的redo log需要在follower节点执行对应的文件操作<br/>
2. log_ddl->recover只能在leader节点执行,follower节点跳过,leader节点执行recover以后会把redo log发给follower节点,follower节点apply redo log保证和leader节点状态一致<br/>
3. 如果创建了ibd文件,leader节点现在比follower节点多了一个ibd文件,再还没有写入MLOG_FILE_CREATE类型的log之前leader节点出现了crash,leader节点变成follower节点, follower节点成为新的leader节点以后会执行log_ddl->recover,调用replay_delete_space_log函数删除ibd文件,那么需要写入redo log(MLOG_FILE_DELETE)告诉原来的leader节点(现在的follower节点删除ibd文件), 新的follower节点apply这条redo log的时候需要去删除ibd文件。<br/>
4. leader节点创建完ibd文件,写完MLOG_FILE_CREATE redo log以后出现crash,leader节点变成follower节点以后重新apply这条日志的时候会发现ibd文件已经存在,需要兼容这种情况。<br/>

drop table

drop table流程

1. 前置检查
2. table cache里面删除table
3. DDL_Log_Table表先插入drop log,后插入delete space log, 要等整个DDL事务commit生效
4. 删除dd::tablespace信息
5. 删除dd::table信息
6. trx commit/rollback
7. post_ddl 事务commit后,DDL_Log_Table表记录可见,搜索出来,写入MLOG_FILE_DELETE,然后删除ibd文件

和create table最大的不同是DDL_Log_Table表插入不是相反操作,事务commit以后才会删除ibd文件
如果trx commit之前,leader出现crash,因为文件还没有操作,所以回归事务就可以了。如果trx commit成功以后出现crash, 那么log_ddl->recover会扫描DDL_Log_Table表,回放文件操作

rename table

rename table流程

1. 前置检查
2. DDL_Log_Table表插入rename space log(马上生效),同时delete record(整个DDL事务commit生效)
3. 写MLOG_FILE_RENAME redo log
4. rename ibd文件
5. DDL_Log_Table表插入rename table log(马上生效),同时delete record(整个DDL事务commit生效)
6. 更新dd::tablespace信息
7. 更新dd::table信息
8. trx commit/rollback
9. post_ddl commit操作啥都不干,rollback就回放DDL log

假设各种crash场景:

  1. 如果步骤2执行结束出现crash,新leader调用log_ddl->recover会扫描DDL_Log_Table表,发现ibd文件名字没有修改会直接返回
  2. 如果步骤3执行结束出现crash, 在前面create table里面我们说过,为了支持follower节点操作ibd文件,follower apply MLOG_FILE_RENAME redo log的时候,需要去rename ibd文件
    和前面场景1一样,log_ddl->recover会扫描DDL_Log_Table表,会重新rename回去
  3. 如果步骤4执行结束出现crash, 和步骤3一样,log_ddl->recover会扫描DDL_Log_Table表,回放文件操作

Content