RDS AliSQL 面向 Binlog 的性能优化大揭密(上)—— 极致 IO 优化

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS SQL Server,基础系列 2核4GB
简介: RDS MySQL使用AliSQL内核,为用户提供了MySQL所有的功能,同时提供了企业级的安全、备份、恢复、监控、性能优化、只读实例、Serverless等高级特性

image.png

RDS AliSQL简介

AliSQL是阿里云RDS团队深度优化的独立 MySQL 分支,除了社区版的所有功能外,AliSQL提供了类似于MySQL企业版的诸多功能,如企业级备份恢复、审计日志、线程池、Binlog in Redo 等。RDS MySQL使用AliSQL内核,为用户提供了MySQL所有的功能,同时提供了企业级的安全、备份、恢复、监控、性能优化、只读实例、Serverless等高级特性。


Binlog 是谓何物

Binlog (Binary log)是 MySQL Server 层维护的一种二进制日志,以事务级别记录了对数据库的所有修改操作。


事务级别是指:一个事务的日志,是在事务提交时被写入 binlog 文件中的。具体来说,事务在执行过程中,会不断的生成 binlog events,暂存在 session 级别的 binlog cache 中;事务提交时,会一次将 binlog cache 中所有内容写到 binlog 文件中。


Binlog 的一致性保证

在 MySQL 中,binlog 是为数不多可以做到 “准” 的日志(另一个 “准” 的是 redo log),即保证日志中存在的修改,数据中一定存在,反之亦然。也正因为它可以做到 “准”,MySQL 才可以基于 binlog 做复制和备份。


Sync_binlog

Sync_binlog 是 binlog 相关的一个重要参数,它控制了 binlog 的刷盘方式。在了解这个参数的具体含义前,先要了解一下 Linux 系统的 page cache 机制。


Page Cache

我们知道计算机的存储介质笼统上说分三层,其读写速度从高到低分别是 cpu cache,memory 和磁盘。Linux 内核为了优化文件的读写速度,在磁盘之前加入了一层缓存,叫做 page cache。


Page cache 本质上是由操作系统直接管理的一块内存空间,应用程序写文件时,会先写到 page cache 上,然后操作系统择机进行刷盘。当然,这样的机制会带来的一个隐患,即当机器 crash 时,没有从 page cache 刷到磁盘的数据会丢失。很多应用程序不能容忍这样的数据丢失,因此操作系统也为应用程序提供了主动刷盘的接口。


Flush 和 Sync 的含义

在 binlog 中,写 binlog events 到 binlog 文件的 page cache 的行为被称为 flush,binlog 文件刷盘的行为被称为 sync。需注意,这个叫法是 binlog 语境中的习惯,redo log 中的叫法又有不同。


参数含义

Sync_binlog 参数控制了 binlog 刷盘的频率,当配置为 0 时,binlog 不主动进行刷盘;当配置为 n (n > 0) 时,binlog 每 n 个事务一起刷盘。


当 sync_binlog 设置为 1 时,每个事务提交时,都会主动 binlog 刷盘,这种配置下,不会出现已提交的事务的 binlog 丢失的现象,基于 binlog 的复制和备份都能保证可靠性。配合 innodb 中的参数innodb_flush_log_at_trx_commit = 1(每个事务 redo log 都主动刷盘),可以达到数据和日志完全一致的高可靠性,这种配置俗称双一,下文讨论过程中,我们都默认实例处于双一配置。


两阶段提交

在双一的配置下,MySQL 使用两阶段机制,保证 Binlog 与 innodb 的崩溃一致性(crash safe)。也就是说,无论实例在什么时间 crash,重启后通过 crash recovery,Binlog 与 innodb 都可以达到一致性状态。

image.png

上图是一个两阶段提交的示意图,所谓两阶段,就是将事务提交分为 prepare 和 commit 两个阶段,将事务分为了 active 和 prepared 两种状态。


Prepare 阶段

Prepare 阶段最主要的动作是将事务从 active 状态置为 prepared 状态,并将 undo 回滚段也置为 prepared。这个动作的意义是,标记事务所有操作都已经结束,在 crash recovery 过程中,处在 prepared 状态的事务是可以回滚也可以提交的(active 状态事务只能回滚不能提交)。有了这个状态,redo log 和 binlog 才能在 commit 阶段和 crash recovery 过程中相互协调。需注意,这个阶段修改事务状态的动作是内存态的,只有记录 undo 回滚段的 redo log 刷盘,事务状态才算被持久化到磁盘。这是由于 innodb 的 WAL 机制导致的,有兴趣的同学可以去查阅相关资料学习。


在早期的 MySQL 上,prepare 阶段还会进行 redo log 的刷盘操作。但随着 binlog group commit 优化的诞生,刷盘操作的性能有了巨大提升,因此 redo log 的刷盘操作被移到了 commit 阶段的 binlog group commit 流程中以优化 IO 性能。这部分细节将在 binlog group commit 优化的章节中详细讲解。值得一提的是,这个改动和 AliSQL 的早期成员印风有很大关联,他在性能测试中首先发现了这个问题,并将 idea 和 code patch 一并贡献给了 MySQL 官方。对这段历史感兴趣的可以参照 http://bugs.mysql.com/bug.php?id=73202


Commit 阶段

Commit 阶段除了事务提交的操作外,还包括 redo log 的刷盘,binlog 的写入和刷盘。这里对这两个日志文件的操作顺序很重要。Binlog 刷盘,就意味着事务已经可以被传给从库,此时就算实例没有完成 commit 就 crash 了,crash recovery 过程中也需要能够提交此事务,这样才不会造成主从不一致。而事务在 crash recovery 过程中事务可提交,就需要事务的 prepared 状态已经被持久化到磁盘,也就是 redo log 已经刷盘。因此必须先将 redo log 刷盘,才可以写 binlog 文件并刷盘。因此,在提交阶段,以 binlog 刷盘完成为标志,刷盘完成前发生 crash,事务回滚,刷盘完成后发生 crash,事务提交。


在完成 binlog 刷盘后,事务就可以提交。提交时会把事务从 prepared 状态改为 commit 状态,这个操作是需要写 redo log 的,但是事务完成提交并不需要等待这个 redo log 刷盘。刚才说过,只要 binlog 刷盘完成,就可以认为这个事务已经持久化的提交了,因此不必再等待一次 redo log 刷盘,直接返回事务提交成功即可。


各时间点 Crash 分析

当实例发生 crash 时(我们这里假设一种最严重的 crash——机器故障导致重启,所有page cache全丢)


  • 如果 redo log 刷盘没有完成,事务的 prepared 状态还没有刷盘,还是 active 的状态,直接回滚即可。
  • 如果 redo log 刷盘完成,binlog 刷盘没有完成,重启时事务是 prepared 状态,在启动阶段这样的事务又叫未决事务,可以选择提交或回滚。通过扫描 binlog,发现事务没有完整的存在于 binlog 中,因此选择回滚;
  • 如果 binlog 完成刷盘,重启时事务是 prepared 状态,binlog 中也完整的记录了这个事务,必须选择提交。


IO 性能问题

上述机制中,为了保证 binlog 的完整和 crash safe,每个事务在提交时,都需要等待两次 IO 操作,一次 redo log,一次 binlog。这导致了极大的性能问题。

image.png

为了优化性能,MySQL 官方引入了 Binlog Group Commit 优化来合并 IO 操作。


Binlog Group Commit 优化

BGC (Binlog Group Commit)优化是 MySQL 官方做的,针对 binlog 提交阶段的一个性能优化,目的是合并 IO 操作。


合并 IO 操作

在文件系统中,IO 操作是成批进行的,在一般情况下,10 次 1KB 的 IO 要比 1 次 10KB 的 IO 慢得多,这就是合并 IO 操作的意义。这个思想在 MySQL server 和 innodb 的众多设计中都有体现。


Binlog Group Commit 流程

image.png

Group Commit 顾名思义,就是把若干事务组成一个组,一起提交。MySQL 将 Binlog 提交阶段分成 flush stage,sync stage 和 commit stage。


Flush stage

image.png

Flush stage 中包含 sync redo 和 flush binlog。进入提交阶段的事务,首先会等待进入 flush stage。为什么会等待呢?具体来说,正在 flush stage 中进行 sync redo 和 flush binlog 的 group,会持有一把 lock_log 锁,这样就阻塞住了新来的事务,它们需要等待当前 group 结束释放 lock_log 锁,才能进入 flush stage。在等待的过程中,系统可以积攒很多等待进入 flush stage 的事务,把他们全部组成一个 group。Group 中的第一个事务作为 leader,flush stage 中所有的操作都由 leader 的线程完成。这样一来,原先多个事务进行多次 sync redo 的操作,就变成了一次 sync redo,最大限度合并了 IO 操作。


MySQL-80 上 redo log 引入了无锁化设计后,sync redo 的动作变为后台线程完成 。Flush stage 中主动进行 sync redo 的操作就变为了等待后台线程完成 sync redo。这种设计下,group commit 也非常有意义,因为等待后台线程是需要拿锁的,很多事务独立等待时,会造成严重的锁冲突。在这种情况下 group commit 实质上是合并了锁等待,避免了锁冲突。


Sync stage

Sync stage 中包含 sync binlog 的操作。完成 flush stage 的 flush group,在进入 sync stage 前还需要再次组队,由几个 flush group 组成一个 sync group,进一步合并 IO。

image.png

Sync stage 组队的机制和 flush stage 类似,由正在 sync binlog 的 sync group 持有一把 lock_sync 锁,准备进入 sync stage 的 flush group 在等待这把锁的过程中积攒,组成一个 sync group。当上一组 sync binlog 完成 lock_sync 被释放,由本组第一个 flush group 的 leader 作为新组的 leader,完成本组的 sync stage。


Commit stage

Commit stage 中包含事务的提交操作。Commit stage的目的并非合并 IO,而是为了让 binlog 中事务的顺序和事务真实提交的顺序一致。

在开启了 binlog_order_commits 或者 clone 过程中需要依赖提交顺序时,完成 sync stage 的事务会再次进入 commit stage;没有开始顺序提交的实例,commit stage会被跳过,每个事务自己进行事务提交。


Binlog in Redo--极致 IO 优化

BGC 优化通过分组的方式,可以将很多小的 IO 操作合并,但是事务提交需要等待的 IO 次数(sync redo 和 sync binlog 两次 IO)并没有改变。为了进一步优化 IO,AliSQL 引入了 Binlog in redo 优化,旨在将事务提交阶段的两次 IO 操作合并为一次 IO 操作。


而具体如何实施优化,以及如何验证优化效果,会在后续文章中进行讲述。


Binlog in redo 架构

image.png

前章曾提到过 Innodb 的 WAL 机制,innodb 写任何数据前,都需要先写下数据的 redo log,随后提交时,只需要同步等待 redo log 刷盘,数据后续异步的刷盘即可。即便出现了 crash,只要 redo log 完整,数据也可被准确无误的恢复。


Binlog in redo 顾名思义,将 binlog 写到 redo log 中。在这个架构下,binlog 对于 redo log 来说也是一份“数据”,受到 redo log 的保护;binlog 的刷盘由异步线程完成,事务提交过程中,无需等待 binlog 刷盘。如果发生 crash,根据 redo log 恢复binlog 文件即可。 这样一来,提交阶段需要等待的 IO 次数就变为了 1 次,能够大幅提升性能。


Crash Recovery 机制

image.png

Binlog in redo 架构中,当实例 crash 后,binlog 中的内容有可能丢失,因此需要在重启后的 recovery 过程中补齐。Server 层中实现了一个 Binlog applier 去补齐 binlog。在 crash recovery 期间 apply redo 时,每次在 redo log 中读到 binlog event,就解析他的 binlog position,如果这个位置已经存在于 binlog文件中,就不需要回填,如果这个位置不在了,就需要回填一下。


性能优化效果

测试环境:32Core, 64G Ram, ESSD存储。

测试工具:sysbench


oltp_update_non_index

image.png

image.png

oltp_insert

image.png

image.png

oltp_write_only

image.png

image.png

结论

Binlog In Redo 功能在不损失可靠性的前提下,减少了 1 次IO。在不超过 256 并发的情况 下,Binlog In Redo 功能对性能的提升和延迟的降低都非常显著。但是对于大并发的场景,性能提升效果有限。这是由于大并发下,BGC 合并 IO 的作用更加明显,Binlog 提交期间的瓶颈来到了串行化的 Flush binlog。为了优化这一瓶颈,AliSQL 引入了 Binlog Parallel Flush 优化,最终使实例达到全业务场景的大幅性能提升。


欲知后事如何,请听下回分解。



作者简介


武根泽(子堪) RDS MySQL内核团队核心研发,擅长 MySQL 内核代码研发,性能调优和技术问题探索,在 MySQL Binlog,Innodb 等领域多有涉猎。关于RDS MySQL内核方面的问题,欢迎致电: vogts.wangt@alibaba-inc.com 咨询。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
15天前
|
存储 SQL 关系型数据库
mysql 的ReLog和BinLog区别
MySQL中的重做日志和二进制日志是确保数据库稳定性和可靠性的关键组件。重做日志主要用于事务的持久性和原子性,通过记录数据页的物理修改信息来恢复未提交的事务;而二进制日志记录SQL语句的逻辑变化,支持数据复制、恢复和审计。两者在写入时机、存储方式及配置参数等方面存在显著差异。
|
3月前
|
canal 消息中间件 关系型数据库
Canal作为一款高效、可靠的数据同步工具,凭借其基于MySQL binlog的增量同步机制,在数据同步领域展现了强大的应用价值
【9月更文挑战第1天】Canal作为一款高效、可靠的数据同步工具,凭借其基于MySQL binlog的增量同步机制,在数据同步领域展现了强大的应用价值
810 4
|
4月前
|
SQL 关系型数据库 MySQL
【揭秘】MySQL binlog日志与GTID:如何让数据库备份恢复变得轻松简单?
【8月更文挑战第22天】MySQL的binlog日志记录数据变更,用于恢复、复制和点恢复;GTID为每笔事务分配唯一ID,简化复制和恢复流程。开启binlog和GTID后,可通过`mysqldump`进行逻辑备份,包含binlog位置信息,或用`xtrabackup`做物理备份。恢复时,使用`mysql`命令执行备份文件,或通过`innobackupex`恢复物理备份。GTID模式下的主从复制配置更简便。
523 2
|
4月前
|
SQL 关系型数据库 MySQL
【MySQL】根据binlog日志获取回滚sql的一个开发思路
【MySQL】根据binlog日志获取回滚sql的一个开发思路
|
15天前
|
SQL 存储 缓存
MySQL进阶突击系列(02)一条更新SQL执行过程 | 讲透undoLog、redoLog、binLog日志三宝
本文详细介绍了MySQL中update SQL执行过程涉及的undoLog、redoLog和binLog三种日志的作用及其工作原理,包括它们如何确保数据的一致性和完整性,以及在事务提交过程中各自的角色。同时,文章还探讨了这些日志在故障恢复中的重要性,强调了合理配置相关参数对于提高系统稳定性的必要性。
|
1月前
|
关系型数据库 MySQL 数据库
【赵渝强老师】MySQL的binlog日志文件
MySQL的binlog日志记录了所有对数据库的更改操作(不包括SELECT和SHOW),主要用于主从复制和数据恢复。binlog有三种模式,可通过设置binlog_format参数选择。示例展示了如何启用binlog、设置格式、查看日志文件及记录的信息。
|
1月前
|
存储 SQL 关系型数据库
mysql 的ReLog和BinLog区别
MySQL中的重做日志(Redo Log)和二进制日志(Binary Log)是两种重要的日志系统。重做日志主要用于保证事务的持久性和原子性,通过记录数据页的物理修改信息来恢复未提交的事务更改。二进制日志则记录了数据库的所有逻辑变化操作,用于数据的复制、恢复和审计。两者在写入时机、存储方式、配置参数和使用范围上有所不同,共同确保了数据库的稳定性和可靠性。
|
3月前
|
消息中间件 canal 关系型数据库
Maxwell:binlog 解析器,轻松同步 MySQL 数据
Maxwell:binlog 解析器,轻松同步 MySQL 数据
387 11
|
2月前
|
存储 关系型数据库 MySQL
MySQL中的Redo Log、Undo Log和Binlog:深入解析
【10月更文挑战第21天】在数据库管理系统中,日志是保障数据一致性和完整性的关键机制。MySQL作为一种广泛使用的关系型数据库管理系统,提供了多种日志类型来满足不同的需求。本文将详细介绍MySQL中的Redo Log、Undo Log和Binlog,从背景、业务场景、功能、底层实现原理、使用措施等方面进行详细分析,并通过Java代码示例展示如何与这些日志进行交互。
212 0
|
4月前
|
监控 关系型数据库 MySQL
MySQL如何快速获取binlog的开始时间和结束时间
【8月更文挑战第17天】在MySQL中快速获取binlog的开始与结束时间可通过多种途径:1) 使用`mysqlbinlog`结合`head`和`tail`命令查看单个或多个binlog文件的时间范围;2) 查询`information_schema.binlog_events`表获取近似的开始与结束时间戳;3) 利用第三方工具如Percona Toolkit的`pt-mysql-summary`获取binlog信息。选择适当方法前应考虑操作环境及数据安全性。
485 2

相关产品

  • 云数据库 RDS MySQL 版
  • 云数据库 RDS
  • 下一篇
    DataWorks