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

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 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
相关文章
|
11天前
|
存储 缓存 负载均衡
mysql的性能优化
在数据库设计中,应选择合适的存储引擎(如MyISAM或InnoDB)、字段类型(如char、varchar、tinyint),并遵循范式(1NF、2NF、3NF)。功能上,可以通过索引优化、缓存和分库分表来提升性能。架构上,采用主从复制、读写分离和负载均衡可进一步提高系统稳定性和扩展性。
32 9
|
27天前
|
人工智能 Cloud Native Java
云原生技术深度解析:从IO优化到AI处理
【10月更文挑战第24天】在当今数字化时代,云计算已经成为企业IT架构的核心。云原生作为云计算的最新演进形态,旨在通过一系列先进的技术和实践,帮助企业构建高效、弹性、可观测的应用系统。本文将从IO优化、key问题解决、多线程意义以及AI处理等多个维度,深入探讨云原生技术的内涵与外延,并结合Java和AI技术给出相应的示例。
92 1
|
2月前
|
存储 SQL 关系型数据库
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
MySQL调优主要分为三个步骤:监控报警、排查慢SQL、MySQL调优。 排查慢SQL:开启慢查询日志 、找出最慢的几条SQL、分析查询计划 。 MySQL调优: 基础优化:缓存优化、硬件优化、参数优化、定期清理垃圾、使用合适的存储引擎、读写分离、分库分表; 表设计优化:数据类型优化、冷热数据分表等。 索引优化:考虑索引失效的11个场景、遵循索引设计原则、连接查询优化、排序优化、深分页查询优化、覆盖索引、索引下推、用普通索引等。 SQL优化。
551 15
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
|
30天前
|
存储 关系型数据库 MySQL
MySQL性能优化实践指南
【10月更文挑战第16天】MySQL性能优化实践指南
46 0
|
30天前
|
存储 关系型数据库 MySQL
MySQL性能优化指南
【10月更文挑战第16天】MySQL性能优化指南
36 0
|
2月前
|
存储 关系型数据库 MySQL
mysql-性能优化(一)
mysql-性能优化(一)
|
2月前
|
关系型数据库 MySQL 数据处理
针对MySQL亿级数据的高效插入策略与性能优化技巧
在处理MySQL亿级数据的高效插入和性能优化时,以上提到的策略和技巧可以显著提升数据处理速度,减少系统负担,并保持数据的稳定性和一致性。正确实施这些策略需要深入理解MySQL的工作原理和业务需求,以便做出最适合的配置调整。
354 6
|
2月前
|
SQL 存储 关系型数据库
深入 MySQL 的执行计划与性能优化
深入 MySQL 的执行计划与性能优化
39 0
|
3月前
|
存储 关系型数据库 MySQL
"深入探索MySQL临时表:性能优化利器,数据处理的灵活之选"
【8月更文挑战第9天】MySQL临时表专为存储临时数据设计,自动创建与删除,仅在当前会话中存在,有助于性能优化。它分为本地临时表和全局临时表(通过特定逻辑模拟)。创建语法类似于普通表,但加TEMPORARY或TEMP关键字。适用于性能优化、数据预处理和复杂查询,需注意内存占用和事务支持问题。合理使用可大幅提升查询效率。
215 2
|
3月前
|
缓存 Linux 调度
[kvm]硬盘IO优化
[kvm]硬盘IO优化

相关产品

  • 云数据库 RDS MySQL 版
  • 云数据库 RDS
  • 下一篇
    无影云桌面