
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
Page cache 本质上是由操作系统直接管理的一块内存空间,应用程序写文件时,会先写到 page cache 上,然后操作系统择机进行刷盘。当然,这样的机制会带来的一个隐患,即当机器 crash 时,没有从 page cache 刷到磁盘的数据会丢失。很多应用程序不能容忍这样的数据丢失,因此操作系统也为应用程序提供了主动刷盘的接口。
Flush 和 Sync 的含义
参数含义
当 sync_binlog 设置为 1 时,每个事务提交时,都会主动 binlog 刷盘,这种配置下,不会出现已提交的事务的 binlog 丢失的现象,基于 binlog 的复制和备份都能保证可靠性。配合 innodb 中的参数innodb_flush_log_at_trx_commit = 1(每个事务 redo log 都主动刷盘),可以达到数据和日志完全一致的高可靠性,这种配置俗称双一,下文讨论过程中,我们都默认实例处于双一配置。
两阶段提交

上图是一个两阶段提交的示意图,所谓两阶段,就是将事务提交分为 prepare 和 commit 两个阶段,将事务分为了 active 和 prepared 两种状态。
Prepare 阶段
在早期的 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 阶段
在完成 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。这导致了极大的性能问题。

为了优化性能,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 流程

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

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。

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
在开启了 binlog_order_commits 或者 clone 过程中需要依赖提交顺序时,完成 sync stage 的事务会再次进入 commit stage;没有开始顺序提交的实例,commit stage会被跳过,每个事务自己进行事务提交。
Binlog in Redo
极致 IO 优化
Binlog in redo 架构

Crash Recovery 机制

性能优化效果
测试环境:32Core, 64G Ram, ESSD存储。
测试工具:sysbench
oltp_update_non_index


oltp_insert


oltp_write_only


结论
欲知后事如何,请听下回分解。
作者简介
推荐阅读


点击“阅读原文”查看云数据库RDS SQL Server版更多信息





