MySQL · 引擎特性 · MySQL5.7 崩溃恢复优化

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 在MySQL5.7之前的版本中, InnoDB每次做crash recovery之前都需要扫描数据目录,打开每个文件并创建内存对象。当目录下文件个数特别多时,会严重影响到崩溃恢复的速度。 为了解决这个问题,MySQL5.7通过结合checkpoint + 标注被修改的文件的方式,从一个check

在MySQL5.7之前的版本中, InnoDB每次做crash recovery之前都需要扫描数据目录,打开每个文件并创建内存对象。当目录下文件个数特别多时,会严重影响到崩溃恢复的速度。

为了解决这个问题,MySQL5.7通过结合checkpoint + 标注被修改的文件的方式,从一个checkpoint点开始,可以找到所有崩溃恢复需要打开的文件,从而避免扫描数据目录。

本文简单的记录了相关的代码,以及一个相关的优化点。

提交mini transaction

入口函数:

mtr_commit -->    
    mtr_t::Command::execute
        mtr_t::Command::prepare_write()

// fil_names_write_if_was_clean

    /// 如果space->max_lsn 等于0,表示从最近一次checkpoint开始至今,这是第一次被修改
    
    /// fil_names_dirty_and_write: 
        1. 加入到链表fil_system->named_spaces的尾部
        2. 更新fil_space_t::max_lsn为当前LSN
        3. 写入一条MLOG_FILE_NAME,日志内容包括space id 及表空间文件路径

// 如果是从上次checkpoint后第一次修改该tablespace, fil_names_dirty_and_write返回true,表示一条 MLOG_FILE_NAME已经追加到当前mtr了,因此在日志组的尾部增加"MLOG_MULTI_REC_END"

// 否则,如果从上次checkpoint之后不止一次修改,则继续走之前的逻辑:单个rec,对第一个字节设置 MLOG_SINGLE_REC_FLAG的flag,或者多个rec的话追加一字节的MLOG_MULTI_REC_END,来标记日志组的结尾位置

在prepare_write中保证了从上次checkpoint后第一次修改的tablespace都有一个MLOG_FILE_NAME写到了日志组中. 随后调用mtr_t::Command::finish_write将日志拷贝到公共buffer中.

Make Checkpoint

入口函数: log_checkpoint

这里会在持有log_sys->mutex的情况下,在做checkpoint前追加MLOG_CHECKPOINT (但如果是一次clean的shutdown,则无需此步骤,因为已经保证了checkpoint后没有新的日志写入)

// fil_names_clear

/// 遍历fil_system->named_spaces链表:
1. 如果fil_space_t::max_lsn小于请求checkpoint的LSN(通常是BufferPool中最老的脏block的LSN),则清空fil_space_t::max_lsn为0,并从链表移除, 这样从当前位置开始,如果下次checkpoint之前这个表都没修改的话,就不需要写入该表名
2. 不管max_lsn是大于checkpoint的LSN还是小于,都会调用fil_names_write,  写入MLOG_FILE_NAME
/// 追加一条日志MLOG_CHECKPOINT,  记录checkpoint发生的LSN

在函数fil_names_clear中产生的日志聚合在一个mtr中提交。(但这个mtr中实际上包含两个log body, MLOG_CHECKPOINT被当做singl rec)。也就是说,除非clean shutdown之外,每个完整的checkpoint,必然要有对应的mlog_checkpoint日志.

随后将日志刷入磁盘: 这是一个临界点,假如在这里crash了,这意味着checkpoint还没更新下去, MLOG_CHECKPOINT已经写下去了,如果从上次checkpoint的点开始扫描,可能会找到两个MLOG_CHECKPOINT日志

Append on checkpoint:

在看代码时发现一个和旧版本不同的变量log_sys->append_on_checkpoint,指向的是一段redo cache。 在做checkpoint时写MLOG_FILE_NAME之前会先看这个指针是否为空,如果不为空,就将这段cache的日志写到全局Buffer。

在函数ha_innobase::commit_inplace_alter_table中被设置,在ddl的最后一步. 设置和重置append_on_checkpoint是在持有数据词典锁时进行的。如果DDL需要最后做临时表和用户表的交换, 此时会写两条MLOG_FILE_RENAME2日志,第一条是老表rename成一个临时表,第二个是完成DDL的新表rename为老表名

然后将这个日志组拷贝下来,并赋值到log_sys->append_on_checkpoint。根据commit log的描述,主要是解决如下场景:

1. The changes to SYS_TABLES were committed, and MLOG_FILE_RENAME2
records were written in a single mini-transaction commit.
2. A log checkpoint and a server kill was injected.
3. Crash recovery will see no records (other than the MLOG_CHECKPOINT).
4. dict_check_tablespaces_and_store_max_id() will emit a message about
a non-found table #sql-ib22*.
5. A mismatch is triggering the assertion failure.

Crash Recovery

入口函数: recv_recovery_from_checkpoint_start:

在从第一个日志文件ib_logfile0找到checkpoint点后,就可以从该点开始扫描日志:

scan 1: 找到MLOG_CHECKPOINT的位置(STORE_NO)

recv_sys_t::mlog_checkpoint_lsn 记录出现MLOG_CHECKPOINT的日志位置. 找到和checkpoint lsn匹配的MLOG_CHECKPOINT后结束第一次扫描

在扫描的过程中,如果遇到如下几类日志,调用fil_name_parse:


        case MLOG_FILE_NAME:
        case MLOG_FILE_DELETE:
        case MLOG_FILE_CREATE2:
        case MLOG_FILE_RENAME2:

对于涉及到的表名,会调用fil_name_process存储到recv_spaces_t中, 这是个map, 以space_id为Key. 对于MLOG_FILE_NAME or MLOG_FILE_RENAME2, 将对应的space载入内存( fil_ibd_load ). 对于MLOG_FILE_DELETE,如果map中已经存在,将flag设置为deleted,并释放fil_space_t

如果找不到MLOG_CHECKPOINT的话,就认为崩溃恢复失败了(clean shutdown除外)

scan 2:

开始扫描并存储到hash中(STORE_YES),解析到的日志被存储到hash中(不判断tablespace是否存在)。STORE_YES的意思是不去判断是否redo对应的tablespace是否存在或被修改. 因为第二次scan的另外一个目的是搜集所有在checkpoint后被修改过的表空间(MLOG_FILE_NAME)

如果内存不够用于存储redo log时,那就不再将redo存到hash中,但会继续扫描到日志尾部,确保所有被修改的表空间都被检测到了并维护下来。

调用recv_init_crash_recovery_spaces
// 对于被修改过的tablespace,加入到链表fil_system->named_spaces上(fil_names_dirty)
// 如果已经删除的tablespace,就将对应的日志设置为RECV_DISCARDED, 这些日志无需apply
// 根据double write buffer校验及载入(buf_dblwr_process)
// 开启后台进程, 用于flush dirty page (recv_writer_thread)

scan 3:

如果scan 2由于内存不足未完成, 会最后重新扫描,由于scan 2已经确保了 这一轮只将tablespace存在的日志加入到hash中(STORE_IF_EXISTS),如果内存不足了,则直接apply掉,再继续解析.

问题及优化

对于第一次扫描寻找mlog_checkpoint可以做一些优化,在做checkpoint时直接将对应的位点存到checkpoint信息里,这样在崩溃恢复时,就可以直接跳到对应的位置,从而避免扫描. 我们将这个Issue report到官方,已经得到确认,ref: (bug#80788)

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
2月前
|
SQL 存储 关系型数据库
MySQL内存引擎:Memory存储引擎的适用场景
MySQL Memory存储引擎将数据存储在内存中,提供极速读写性能,适用于会话存储、临时数据处理、高速缓存和实时统计等场景。但其数据在服务器重启后会丢失,不适合持久化存储、大容量数据及高并发写入场景。本文深入解析其特性、原理、适用场景与限制,并提供性能优化技巧及替代方案比较,助你合理利用这一“内存闪电”。
|
2月前
|
SQL 监控 关系型数据库
MySQL事务处理:ACID特性与实战应用
本文深入解析了MySQL事务处理机制及ACID特性,通过银行转账、批量操作等实际案例展示了事务的应用技巧,并提供了性能优化方案。内容涵盖事务操作、一致性保障、并发控制、持久性机制、分布式事务及最佳实践,助力开发者构建高可靠数据库系统。
|
2月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
|
2月前
|
关系型数据库 分布式数据库 数据库
阿里云数据库收费价格:MySQL、PostgreSQL、SQL Server和MariaDB引擎费用整理
阿里云数据库提供多种类型,包括关系型与NoSQL,主流如PolarDB、RDS MySQL/PostgreSQL、Redis等。价格低至21元/月起,支持按需付费与优惠套餐,适用于各类应用场景。
|
2月前
|
存储 关系型数据库 MySQL
介绍MySQL的InnoDB引擎特性
总结而言 , Inno DB 引搞 是 MySQL 中 高 性 能 , 高 可靠 的 存 储选项 , 宽泛 应用于要求强 复杂交易处理场景 。
79 15
|
3月前
|
缓存 关系型数据库 MySQL
降低MySQL高CPU使用率的优化策略。
通过上述方法不断地迭代改进,在实际操作中需要根据具体场景做出相对合理判断。每一步改进都需谨慎评估其变动可能导致其他方面问题,在做任何变动前建议先在测试环境验证其效果后再部署到生产环境中去。
133 6
|
2月前
|
关系型数据库 MySQL 数据库
MySql事务以及事务的四大特性
事务是数据库操作的基本单元,具有ACID四大特性:原子性、一致性、隔离性、持久性。它确保数据的正确性与完整性。并发事务可能引发脏读、不可重复读、幻读等问题,数据库通过不同隔离级别(如读未提交、读已提交、可重复读、串行化)加以解决。MySQL默认使用可重复读级别。高隔离级别虽能更好处理并发问题,但会降低性能。
|
2月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎,提供高性价比、稳定安全的云数据库服务,适用于多种行业与业务场景。
|
4月前
|
存储 SQL 关系型数据库
MySQL 动态分区管理:自动化与优化实践
本文介绍了如何利用 MySQL 的存储过程与事件调度器实现动态分区管理,自动化应对数据增长,提升查询性能与数据管理效率,并详细解析了分区创建、冲突避免及实际应用中的关键注意事项。
153 0
|
2月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
90 3

推荐镜像

更多
下一篇
开通oss服务