MySQL · TokuDB · checkpoint过程

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
简介:

TokuDB的buffer pool(在TokuDB中被称作cachetable)维护几个后台工作线程定期处理一些任务。
其中有一个工作线程叫做checkpointer线程,每60秒启动一次把cachetable中所有脏页写回到磁盘上。
TokuDB只支持这一种checkpoint方式,用MySQL术语来说就是sharp checkpoint。
每次checkpoint过程写的脏页数目可能会比较多,而且在写回的过程中需要一直持有节点的读写锁,因此,checkpoint时索引的访问性能会受到一定程度的影响。
为了降低checkpoint对性能影响,TokuDB对每个脏页clone一份用于写回,在clone的过程中是持有节点的读写锁的,clone结束会放掉读写锁。

TokuDB checkpoint过程分为如下五个步骤:

  • 获取全局的checkpoint锁
  • Begin checkpoint
  • End checkpoint
  • 清理redo日志
  • 释放全局的checkpoint锁

下面我们一起看一下begin checkpoint和end checkpoint的详细过程。

Begin checkpoint

在checkpoint开始时刻要做一些准备工作,诸如:

  1. pin FT
    给CACHEFILE对应的FT加pinned_by_checkpoint标记,保证CACHEFILE不会从内存里移除。CACHEFILE记录了索引包含的数据节点列表和描述索引对应文件的相关信息。

  2. 对每个CACHEFILE加for_checkpoint标记
    标识此CACHEFILE数据属于当前的checkpoint。
  3. 记redo日志
    记录checkpoint开始时刻的lsn。
    写redo日志:begin checkpoint日志项,checkpoint打开索引文件日志项,live txn日志项
  4. 对每个PAIR(数据页)加checkpoint_pending标记
    遍历cachetable里面每个数据页,如果数据页对应的索引文件(CACHEFILE)属于checkpoint,对数据页加checkpoint_pending标记,并加入到全局m_pending_head双向链表里面。
  5. 更新checkpoint header信息
    clone一份FT header,记做ft->checkpoint_header,记录checkpoint开始时刻BTT(Block Translation Table)的位置。
    TokuDB每次checkpoint都会把数据写到一个新的地方,索引逻辑页号(或者块号)到索引文件offset的映射关系记录在BTT里面。
    ft->checkpoint_header的类型为FT_CHECKPOINT_INPROGRESS,lsn为checkpoint开始时刻的lsn。
  6. 克隆BTT,BTT里面有个translation表,记录逻辑页号到索引文件offset的映射关系。这个表有三个版本:
  • _current(当前的,类型为TRANSLATION_CURRENT)
  • _inprogress(checkpoint开始时刻的,类型为TRANSLATION_INPROGRESS)
  • _checkpointed(上次checkpont的,类型为TRANSLATION_CHECKPOINTED) 
    就是把TRANSLATION_CURRENT复制一份,并把类型设置为TRANSLATION_INPROGRESS。

注:
1, 2阶段在m_cf_list->read_lock保护下进行
4, 5阶段在此过程在pair list的锁和m_cf_list->read_lock保护下进行。。
注意是拿了pair list上所有的锁,m_list_lock读锁,m_pending_lock_expensive写锁,m_pending_lock_cheap写锁,保证不能向pair list添加/删除数据页;不能把pair list的数据页evict出内存;同时也阻止在get_and_pin的过程中client线程池帮助写回属于checkpoint的脏页。这三个锁都是保护pair list的,按照不同的功能拆分成三个锁。

void checkpointer::begin_checkpoint() {
    // 1. Initialize the accountability counters.
    m_checkpoint_num_txns = 0;

    // 2. Make list of cachefiles to be included in the checkpoint.
    m_cf_list->read_lock();
    m_cf_list->m_active_fileid.iterate<void *, iterate_note_pin::fn>(nullptr);
    m_checkpoint_num_files = m_cf_list->m_active_fileid.size();
    m_cf_list->read_unlock();

    // 3. Create log entries for this checkpoint.
    if (m_logger) {
        this->log_begin_checkpoint();
    }

    bjm_reset(m_checkpoint_clones_bjm);

    m_list->write_pending_exp_lock();
    m_list->read_list_lock();
    m_cf_list->read_lock(); // needed for update_cachefiles
    m_list->write_pending_cheap_lock();

    // 4. Turn on all the relevant checkpoint pending bits.
    this->turn_on_pending_bits();

    // 5. Clone BTT and FT header
    this->update_cachefiles();
    m_list->write_pending_cheap_unlock();
    m_cf_list->read_unlock();
    m_list->read_list_unlock();
    m_list->write_pending_exp_unlock();
}

End checkpoint

在end checkpoint的阶段

  • 把所有的CACHEFIlE记录在checkpoint_cfs数组里面,为后面的步骤做准备。
  • 然后调用checkpoint_pending_pairs函数把m_pending_head双向链表的数据页写回到磁盘上。
    Checkpoint_pending_pairs遍历m_pending_head链表,对每个数据页判断是否真的需要写回。
    因为一次checkpoint的时间比较长,有的数据页可能是被client线程池帮忙写回了,这里就不需要再做一次写回操作。如果需要写回,就调用clone_callback克隆一份。
    在clone的过程中是持有数据页的读写锁和disk_nb_mutex(mutex语义,表示有I/O在进行),克隆结束后,释放读写锁,只持有disk_nb_mutex锁,由checkpointer线程把数据页写回(cloned副本)。写回结束后,释放disk_nb_mutex。
    如果数据页没有设置clone_callback(缺省是都会设置的),由checkpointer线程把数据页(注意,是数据页本身)写回,写回过程中是持有读写锁和disk_nb_mutex的。
    写回结束后清除checkpoint_pending标记和dirty标记。
    函数checkpoint_pending_pairs把所有的数据页写回到磁盘上,后面要做的就是metadata的修改。
  • 对checkpoint_cfs数组的每个CACHEFILE调用checkpoint_userdata回调函数(实际上是ft_checkpoint函数)把BTT(Block Translation Table)和ft->checkpoint_header序列化到磁盘上。
    BTT的rootnum
    在FT索引文件里有两个位置可以保存ft->header:偏移0和偏移4096。
    TokuDB采用round robin的方式,把奇数次(1,3,5…)checkpoint的header存储在偏移为0的地方;
    把偶数次(2,4,6,…)checkpoint的header存储在偏移为4096的位置上。
    然后更新ft->h->checkpoint_lsn为checkpoint开始时刻的lsn。
  • 写redo日志:end checkpoint日志项。
  • 通知logger子系统logger->last_completed_checkpoint_lsn为checkpoint开始时刻的lsn。
  • 对checkpoint_cfs数组保存的每个CACHEFILE调用end_checkpoint_userdata回调函数(实际上是ft_end_checkpoint)把_checkpointed记录的上次checkpoint写回的数据页所占用空间释放掉。并且把这次checkpoint的BTT保存在_checkpointed,然后清空_inprogress,表示checkpoint结束,当前没有正在进行的checkpoint。在ft_end_checkpoint里面还做了一个事情就是把ft->checkpoint_header释放并置为空,到这里checkpoint的工作就完成了。
  • unpin FT
void checkpointer::end_checkpoint(void (*testcallback_f)(void*),  void* testextra) {
    toku::scoped_malloc checkpoint_cfs_buf(m_checkpoint_num_files * sizeof(CACHEFILE));
    CACHEFILE *checkpoint_cfs = reinterpret_cast<CACHEFILE *>(checkpoint_cfs_buf.get());

    this->fill_checkpoint_cfs(checkpoint_cfs);
    this->checkpoint_pending_pairs();
    this->checkpoint_userdata(checkpoint_cfs);
    // For testing purposes only.  Dictionary has been fsync-ed to disk but log has not yet been written.
    if (testcallback_f) {
        testcallback_f(testextra);
    }
    this->log_end_checkpoint();
    this->end_checkpoint_userdata(checkpoint_cfs);

    // Delete list of cachefiles in the checkpoint,
    this->remove_cachefiles(checkpoint_cfs);

}

Checkpoint的redo日志

下面我们一起看一下checkpoint过程记录的redo日志:

  • Begin_checkpoint:表示begin checkpoint的日志项
  • Fassociate:表示打开的索引的日志项
  • End_checkpoint:表示end checkpoint的日志项

./tdb_logprint < data/log000000000002.tokulog27
begin_checkpoint         'x': lsn=88 timestamp=1455623796540257 last_xid=153 crc=470dd9ea len=37
fassociate               'f': lsn=89 filenum=0 treeflags=0 iname={len=15 data="tokudb.rollback"} unlink_on_close=0 crc=8606e9b1 len=49
fassociate               'f': lsn=90 filenum=1 treeflags=4 iname={len=18 data="tokudb.environment"} unlink_on_close=0 crc=92dc4c1c len=52
fassociate               'f': lsn=91 filenum=3 treeflags=4 iname={len=16 data="tokudb.directory"} unlink_on_close=0 crc=86323b7e len=50
end_checkpoint           'X': lsn=92 lsn_begin_checkpoint=88 timestamp=1455623796541659 num_fassociate_entries=3 num_xstillopen_entries=0 crc=5cde4ff2 len=45


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
9月前
|
存储 算法 关系型数据库
【MySQL的CheckPoint技术】
【MySQL的CheckPoint技术】
|
1月前
|
存储 缓存 关系型数据库
【MySQL技术内幕】2.4-Checkpoint技术
【MySQL技术内幕】2.4-Checkpoint技术
12 1
|
2月前
|
存储 SQL 关系型数据库
MySQL之深入InnoDB存储引擎——Checkpoint机制
一、引入 由于页的操作首先都是在缓冲池中完成的,那么如果一条DML语句改变了页中的记录,那么此时页就是脏的,即缓冲池中页的版本要比磁盘的新。那么数据库需要将新版本的页刷新到磁盘。倘若每次一个页发生变化就刷新,那么开销会很大,若热点数据集中在某几个页中,那么数据库的性能将变得非常差。 同时如果在缓冲池将新版本的页刷新到磁盘时发生了宕机,那么数据就不能恢复了。为了避免发生数据丢失的问题,当前事务数据库普遍都采用了 Write Ahead Log 策略,即当事务提交时,先写重做日志,再修改页。当由于发生宕机而导致数据丢失时,通过重做日志来完成数据的恢复,从而满足事务的持久性要求。
|
11月前
|
存储 SQL 关系型数据库
MySQL之深入InnoDB存储引擎——Checkpoint机制
一、引入 由于页的操作首先都是在缓冲池中完成的,那么如果一条DML语句改变了页中的记录,那么此时页就是脏的,即缓冲池中页的版本要比磁盘的新。那么数据库需要将新版本的页刷新到磁盘。倘若每次一个页发生变化就刷新,那么开销会很大,若热点数据集中在某几个页中,那么数据库的性能将变得非常差。
|
存储 关系型数据库 MySQL
mysql 数据库无法启动(Ignoring the redo log due to missing MLOG_CHECKPOINT between the checkpoint .... and)
数据库机器的CPU和主板都换了,重新开机,发现mysql数据库无法启动!
212 0
|
存储 算法 关系型数据库
MySQL · 源码分析 · Tokudb序列化和反序列化过程
序列化和写盘 Tokudb数据节点写盘主要是由后台线程异步完成的: checkpoint线程:把cachetable(innodb术语buffer pool)中所有脏页写回 evictor线程:释放内存,如果victim节点是dirty的,需要先将数据写回。
3158 0
|
存储 监控 JavaScript
《MySQL技术内幕:InnoDB存储引擎第2版》——2.4 Checkpoint技术
本节书摘来自华章计算机《MySQL技术内幕:InnoDB存储引擎第2版》一书中的第2章,第2.4节,作者:姜承尧著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1122 0
|
存储 算法 关系型数据库
TokuDB · 引擎特性 · HybridDB for MySQL高压缩引擎TokuDB 揭秘
HybridDB for MySQL(原名petadata)是面向在线事务(OLTP)和在线分析(OLAP)混合场景的关系型数据库。HybridDB采用一份数据存储来进行OLTP和OLAP处理,解决了以往需要把一份数据多次复制来分别进行业务交易和数据分析的问题,极大地降低了数据存储的成本,缩短了数据分析的延迟,使得实时分析决策称为可能。 HybridDB for MySQL兼容MySQL的语法及
3097 0
|
关系型数据库 数据库 MySQL
mysql innodb checkpoint
mysql checkpoint分为两种 sharp checkpoint fuzzy checkpoint sharp checkpoint sharp checkpoint会把所有已提交事务相关的脏页刷到磁盘,并记录最新的已提交事务的LSN号。
2268 0

相关产品

  • 云数据库 RDS MySQL 版