MySQL 实战 45 讲
林晓斌
网名丁奇,前腾讯云数据库负责人
224874 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
实践篇 (37讲)
特别放送 (1讲)
结课测试 (1讲)
MySQL 实战 45 讲
15
15
1.0x
00:00/00:00
登录|注册

23 | MySQL是怎么保证数据不丢的?

binlog的优化
binlog的组提交
组提交过程
LSN的概念
binlog_group_commit_sync_no_delay_count
binlog_group_commit_sync_delay
组提交机制
并行事务提交时持久化到磁盘
后台线程持久化到磁盘
部分日志持久化到磁盘
异常重启时的丢失
组提交机制
参数sync_binlog的设置
binlog cache
写入机制
写入机制
redo log buffer
设置innodb_flush_log_at_trx_commit参数
设置sync_binlog参数
设置binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count参数
binlog
redo log
性能提升方法
crash-safe的保证
性能提升方法
WAL机制
总结
MySQL是怎么保证数据不丢的?

该思维导图由 AI 生成,仅供参考

今天这篇文章,我会继续和你介绍在业务高峰期临时提升性能的方法。从文章标题“MySQL 是怎么保证数据不丢的?”,你就可以看出来,今天我和你介绍的方法,跟数据的可靠性有关。
在专栏前面文章和答疑篇中,我都着重介绍了 WAL 机制(你可以再回顾下第 2 篇第 9 篇第 12 篇第 15 篇文章中的相关内容),得到的结论是:只要 redo log 和 binlog 保证持久化到磁盘,就能确保 MySQL 异常重启后,数据可以恢复。
评论区有同学又继续追问,redo log 的写入流程是怎么样的,如何保证 redo log 真实地写入了磁盘。那么今天,我们就再一起看看 MySQL 写入 binlog 和 redo log 的流程。

binlog 的写入机制

其实,binlog 的写入逻辑比较简单:事务执行过程中,先把日志写到 binlog cache,事务提交的时候,再把 binlog cache 写到 binlog 文件中。
一个事务的 binlog 是不能被拆开的,因此不论这个事务多大,也要确保一次性写入。这就涉及到了 binlog cache 的保存问题。
系统给 binlog cache 分配了一片内存,每个线程一个,参数 binlog_cache_size 用于控制单个线程内 binlog cache 所占内存的大小。如果超过了这个参数规定的大小,就要暂存到磁盘。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

MySQL数据保证机制的技术特点主要围绕binlog的写入流程和相关参数的设置展开。在binlog的写入机制中,事务执行过程中先将日志写入binlog cache,事务提交时再将binlog cache写入binlog文件中。每个线程有自己的binlog cache,但共用同一份binlog文件。参数sync_binlog控制了write和fsync的时机,可以根据实际情况设置以提升性能。然而,将sync_binlog设置为较大值会增加丢失日志的风险。因此,在实际业务中需要权衡性能和数据可靠性。此外,文章还介绍了redo log的写入机制和InnoDB提供的innodb_flush_log_at_trx_commit参数,以及组提交机制对磁盘IOPS消耗的影响。总的来说,文章通过详细解释binlog的写入流程和相关参数的设置,帮助读者了解MySQL数据保证机制的技术特点,为在业务高峰期临时提升性能提供了有益的参考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《MySQL 实战 45 讲》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(188)

  • 最新
  • 精选
  • 锅子
    置顶
    老师好,有一个疑问:当设置sync_binlog=0时,每次commit都只时write到page cache,并不会fsync。但是做实验时binlog文件中还是会有记录,这是什么原因呢?是不是后台线程每秒一次的轮询也会将binlog cache持久化到磁盘?还是有其他的参数控制呢?

    作者回复: 你看到的“binlog的记录”,也是从page cache读的哦。 Page cache是操作系统文件系统上的😄 好问题

    2019-01-04
    16
    184
  • WilliamX
    为什么 binlog cache 是每个线程自己维护的,而 redo log buffer 是全局共用的? 这个问题,感觉还有一点,binlog存储是以statement或者row格式存储的,而redo log是以page页格式存储的。page格式,天生就是共有的,而row格式,只跟当前事务相关

    作者回复: 嗯,这个解释也很好。👍🏿

    2019-01-04
    8
    159
  • alias cd=rm -rf
    事务A是当前事务,这时候事务B提交了。事务B的redolog持久化时候,会顺道把A产生的redolog也持久化,这时候A的redolog状态是prepare状态么?

    作者回复: 不是。 说明一下哈,所谓的 redo log prepare,是“当前事务提交”的一个阶段,也就是说,在事务A提交的时候,我们才会走到事务A的redo log prepare这个阶段。 事务A在提交前,有一部分redo log被事务B提前持久化,但是事务A还没有进入提交阶段,是无所谓“redo log prepare”的。 好问题

    2019-01-28
    17
    130
  • 倪大人
    老师求解sync_binlog和binlog_group_commit_sync_no_delay_count这两个参数区别 如果 sync_binlog = N binlog_group_commit_sync_no_delay_count = M binlog_group_commit_sync_delay = 很大值 这种情况fsync什么时候发生呀,min(N,M)吗? 感觉sync_binlog搭配binlog_group_commit_sync_delay也可以实现组提交? 如果 sync_binlog = 0 binlog_group_commit_sync_no_delay_count = 10 这种情况下是累计10个事务fsync一次?

    作者回复: 好问题,我写这篇文章的时候也为了这个问题去翻了代码,是这样的: 达到N次以后,可以刷盘了,然后再进入(sync_delay和no_delay_count)这个逻辑; Sync_delay如果很大,就达到no_delay_count才刷; 只要sync_binlog=0,也会有前面的等待逻辑,但是等完后还是不调fsync😄

    2019-01-04
    10
    84
  • Komine
    为什么binlog 是不能“被打断的”的呢?主要出于什么考虑?

    作者回复: 好问题 我觉得一个比较重要的原因是,一个线程只能同时有一个事务在执行。 由于这个设定,所以每当执行一个begin/start transaction的时候,就会默认提交上一个事务; 这样如果一个事务的binlog被拆开的时候,在备库执行就会被当做多个事务分段自行,这样破坏了原子性,是有问题的。

    2019-01-22
    4
    79
  • 猪哥哥
    老师 我想问下文件系统的page cache还是不是内存, 是不是文件系统向内核申请的一块的内存?

    作者回复: 你理解的是对的

    2019-01-10
    4
    43
  • 某、人
    有调到非双1的时候,在大促时非核心库和从库延迟较多的情况。 设置的是sync_binlog=0和innodb_flush_log_at_trx_commit=2 针对0和2,在mysql crash时不会出现异常,在主机挂了时,会有几种风险: 1.如果事务的binlog和redo log都还未fsync,则该事务数据丢失 2.如果事务binlog fsync成功,redo log未fsync,则该事务数据丢失。 虽然binlog落盘成功,但是binlog没有恢复redo log的能力,所以redo log不能恢复. 不过后续可以解析binlog来恢复这部分数据 3.如果事务binlog fsync未成功,redo log成功。 由于redo log恢复数据是在引擎层,所以重新启动数据库,redo log能恢复数据,但是不能恢复server层的binlog,则binlog丢失。 如果该事务还未从FS page cache里发送给从库,那么主从就会出现不一致的情况 4.如果binlog和redo log都成功fsync,那么皆大欢喜。 老师我有几个问题: 1.因为binlog不能被打断,那么binlog做fsync是单线程吧? 如果是的话,那么binlog的write到fsync的时间,就应该是redo log fsync+上一个事务的binlog fsync时间。 但是测试到的现象,一个超大事务做fsync时,对其它事务的提交影响也不大。 如果是多线程做fsync,怎么保证的一个事务binlog在磁盘上的连续性? 2. 5.7的并行复制是基于binlog组成员并行的,为什么很多文章说是表级别的并行复制?

    作者回复: 1. Write的时候只要写进去了,fsync其实很快的。连续性是write的时候做的(写的时候保证了连续) 2. 你的理解应该是对的。不是表级

    2019-01-06
    19
    40
  • xiaoyou
    老师,请教一个问题,文章说innodb的 redo log 在commit的时候不进行fsync,只会write 到page cache中。当sync_binlog>1,如果redo log 完成了prepare持久化落盘,binlog只是write page cache,此时commit标识完成write 但没有落盘,而client收到commit成功,这个时候主机掉电,启动的时候做崩溃恢复,没有commit标识和binglog,事务会回滚。我看文章说sync_binlog设置为大于1的值,会丢binlog日志,此时数据也会丢失吧?

    作者回复: 你说的对,分析得很好

    2019-01-09
    16
    24
  • Mr.Strive.Z.H.L
    老师你好,看了@倪大人的问题,个人认为: sync_binlog和binlog_group_commit_sync_no_delay_count的最大区别主要在于,数据的丢失与否吧? sync_binlog = N:每个事务write后就响应客户端了。刷盘是N次事务后刷盘。N次事务之间宕机,数据丢失。 binlog_group_commit_sync_no_delay_count=N: 必须等到N个后才能提交。换言之,会增加响应客户端的时间。但是一旦响应了,那么数据就一定持久化了。宕机的话,数据是不会丢失的。 不知道我这么理解对不对?

    作者回复: 你的理解很到位

    2019-01-08
    12
    22
  • 一大只😴
    你是怎么验证的?等于0的时候虽然有走这个逻辑,但是最后调用fsync之前判断是0,就啥也没做就走了 回复老师: 老师,我说的sync_binlog=0或=1效果一样,就是看语句实际执行的效果,参数binlog_group_commit_sync_delay我设置成了500000微秒,在=1或=0时,对表进行Insert,然后都会有0.5秒的等待,也就是执行时间都是0.51 sec,关闭binlog_group_commit_sync_delay,insert执行会飞快,所以我认为=1或=0都是受组提交参数的影响的。

    作者回复: 👍🏿 非常好 然后再补上我回答的这个逻辑,就完备了

    2019-01-05
    22
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部