【华为云MySQL技术专栏】MySQL Clone介绍
1、MySQL Clone简介
MySQL Clone是MySQL 8.0版本开始引入的一个插件,用于从本地或远程clone数据,如图1和图2所示。
图1 本地Clone
图2 远程Clone
简单来讲就是对数据目录取一个物理的备份快照,clone到本地或者远程,过程中源端(donor)几乎不受影响,支持DML、DDL的并发。
MySQL Clone仅支持InnoDB,会clone包含database、表空间、表、redo、undo、数据字典(元数据)等。Clone得到的数据目录可以用于创建备机。
2、使用方式
需要先安装MySQL Clone插件:
INSTALL PLUGIN clone SONAME 'mysql_clone.so';
然后执行clone命令:
-
本地clone,指定目标数据目录即可
CLONE LOCAL DATA DIRECTORY '/target_clone_dir';
-
远程clone
CLONE INSTANCE FROM 'root'@<远程MySQL Server地址>:<端口> IDENTIFIED BY '<MySQL密码>' DATA DIRECTORY '/clone_dir';
对于远程clone,命令在接收端(recipient)执行,从donor端拉取clone的数据到本地。
未指定DATA DIRECTORY的远程clone,recipient端会先删除当前的user data,包含schema和tablespace,然后clone到recipient端MySQL Server的数据目录。
Recipient端会持续循环的接收源端发来的数据,把数据写入相应文件的相应位置。
Clone完成后,对于未指定DATA DIRECTORY的场景,recipient端MySQL Server进程会自动退出,需要重启mysqld以使用新clone的数据,例如依赖mysqld_safe监控进程自动拉起。
3、Clone主要流程
MySQL Clone的流程如图3所示,主要分以下几个步骤。
-
File copy,copy数据文件,同时开始记录copy文件过程中又有修改的page id
-
Page copy,copy上一步过程中有修改的page,同时开始归档增量redo日志
-
Redo copy,copy上一步过程中归档的redo日志
-
clone完成后,接收端重启原有MySQL Server,或者启动新的MySQL Server进程,来进行恢复,开始使用新clone的数据
图3 Clone的主要流程
这里有一些值得注意的点:
-
数据字典也clone了,本质上相当于是表数据,因为也在innodb表中
-
gtid也被clone了(通过clone系统表mysql.gtid_executed),binlog pos会持久话在系统表空间,也被clone了
-
checkpoint信息在redo log文件中,也clone了
-
还会clone ib_buffer_pool文件
所以MySQL Clone取的是一个完整的物理快照,也可以用于创建数据库的备机。
3.1 File copy
这一步copy所有的InnoDB数据文件,同时记录过程中又被修改了的数据页面的page id,保证数据的一致性。
-
先开始记录修改的页面的ID:Page_Arch_Client_Ctx::start --> Arch_Page_Sys::start。首次执行,会启动page_archiver_thread后台线程。获取redo log的当前lsn作为track_page_lsn。做一个checkpoint,并等待其完成。对每个tablespace file进行flush,避免有数据还在os的cache中。
-
将每个innodb tablespace的文件加入列表:Clone_Snapshot::m_data_file_vector
-
处理每个文件的每个chunk,发送给远程,或者写到本地文件,主要调用过程如下:
#0 Clone_Handle::send_data
#1 Clone_Handle::process_chunk
#2 Clone_Handle::copy
#3 innodb_clone_copy
3.2 Page copy
对于copy数据文件过程中,又有修改的数据页面,在这一步中进行copy。同时,通过从此时开始归档新产生的redo log,来确保数据的一致性。
-
先从此时开始归档后续新增的redo log:Log_Arch_Client_Ctx::start --> Arch_Log_Sys::start
主要代码流程如下:
int Arch_Log_Sys::start(Arch_Group *&group, lsn_t &start_lsn, byte *header,
bool is_durable) {
// ...
// 做一个checkpoint
log_request_checkpoint(*log_sys, true);
// ..
// 如果是首次,启动log_archiver_thread后台线程
if (m_state == ARCH_STATE_INIT) {
auto err = start_log_archiver_background();
// ...
}
// ...
// 从checkpoint lsn开始归档redo log
/* Start archiving from checkpoint LSN. */
log_writer_mutex_enter(*log_sys); /* protects log_sys->last_checkpoint_lsn */
log_files_mutex_enter(*log_sys); /* protects log_sys->m_files */
start_lsn = log_sys->last_checkpoint_lsn.load();
const auto file = log_sys->m_files.find(start_lsn);
// ...
}
-
停止记录被修改的page的id,代码入口:
Page_Arch_Client_Ctx::stop
-
获取记录的每个有修改的页面,主要调用过程如下:
#0 Clone_Snapshot::get_page_for_write
#1 Clone_Snapshot::get_next_page
#2 Clone_Snapshot::get_next_block
#3 Clone_Handle::process_chunk
#4 Clone_Handle::copy
#5 innodb_clone_copy
像file copy一样,交由远程或本地写入页面所在文件的对应位置,代码入口为:Clone_Handle::send_data
3.3 Redo copy
这一步copy上一步所归档的redo log。代码入口:Clone_Snapshot::init_redo_copy。
先暂时阻塞XA事务避免binlog和innodb数据不一致,并等待binlog已prepare的事务提交或回滚,binlog位置持久化。
这里通过代码中的注释可以了解到,是为了避免GTID和持久化到InnoDB中的数据产生不一致。
/* Block external XA operations. XA prepare commit and rollback operations
are first logged to binlog and added to global gtid_executed before doing
operation in SE. Without blocking, we might persist such GTIDs from global
gtid_executed before the operations are persisted in Innodb. */
然后停止归档redo log,将donor端归档的redo log copy到远程或本地的对应文件。
3.4 基于clone的数据目录启动MySQL Server进行恢复
对于未指定数据目录的远程clone,接收端完成后会自动退出进程,如果没有类似mysqld_safe的机制拉起,则需要手动重新拉起mysqld进程。
对于其它clone场景,需要手动新启动mysqld进程来使用clone的数据目录。
从clone的redo log file读取checkpoint信息以及redo log进行恢复,与innodb恢复流程相同,主要是处理redo copy阶段所clone的redo log。
3.5 并发DDL的处理
MySQL Clone在运行过程中,实质上并不是和DDL并行,而是达到clone期间不完全禁止DDL执行的目的。可以通过参数clone_block_ddl控制,默认允许DDL并行。除了以下三种命令,都支持并发执行。
-
ALTER TABLE tbl_name DISCARD TABLESPACE;
-
ALTER TABLE tbl_name IMPORT TABLESPACE;
-
ALTER INSTANCE DISABLE INNODB REDO_LOG;
DDL执行时,在需要阻塞clone操作时,创建Clone_notify对象来通知clone模块。分如下类型:
/** Notification type. Currently used by various DDL commands. */
enum class Type {
/* Space is being created. */
SPACE_CREATE,
/* Space is being dropped. */
SPACE_DROP,
/* Space is being renamed. */
SPACE_RENAME,
/* Space is being discarded or imported. */
SPACE_IMPORT,
/* Space encryption property is altered. */
SPACE_ALTER_ENCRYPT,
/* Space encryption property of general tablespace is altered. */
SPACE_ALTER_ENCRYPT_GENERAL,
/* Space encryption flags of general tablespace are altered. */
SPACE_ALTER_ENCRYPT_GENERAL_FLAGS,
/* In place Alter general notification. */
SPACE_ALTER_INPLACE,
/* Inplace Alter bulk operation. */
SPACE_ALTER_INPLACE_BULK,
/* Special consideration is needed for UNDO as these DDLs
don't use DDL log and needs special consideration during recovery. */
SPACE_UNDO_DDL,
/* Redo logging is being disabled. */
SYSTEM_REDO_DISABLE
};
例如clone期间进行了inplace alter table,ha_innobase::inplace_alter_table中会创建以下对象来通知clone插件。
/* Notify clone during in place operations */
Clone_notify notifier(Clone_notify::Type::SPACE_ALTER_INPLACE,
dict_sys_t::s_invalid_space_id, false);
Clone_notify的构造函数中,对于SPACE_ALTER_INPLACE类型的DDL,不会对clone进行block。
if (fsp_is_system_temporary(space) || m_type == Type::SPACE_ALTER_INPLACE) {
/* No need to block clone. */
return;
}
而对于例如SPACE_CREATE,会调用Clone_Sys::begin_ddl_state --> Clone_Snapshot::begin_ddl_state来进行阻塞。
阻塞结束后,会在初始化page copy和初始化redo copy时,将DDL新建的tablespace文件加入列表进行处理。
4、总结
MySQL Clone可以对本地或远程MySQL Server的数据取一个物理快照,可以用于全量备份和创建备机,提供了mysqldump、Xtrabackup等之外的另一个选择。其通过File copy、page copy和redo copy三个阶段,保证了clone数据的完整与一致。
- 点赞
- 收藏
- 关注作者
评论(0)