1. 结论:
只要redo log 和 binlog 保证持久化到磁盘,就能确保MySQL异常重启后,数据可以恢复。
2. 机制
WAL机制,(Write Ahead Log): 事务先写入日志,后持久化到磁盘。
3. binlog 写入机制
流程
- 每个线程内都有一个binlog cache,记录先写入binlog cache,所有线程共享一个binlog文件
- binlog cache write into binlog file, binlog file 是存储在文件操作系统的page cache中。
- binlog file 通过 fsync持久化到磁盘。
解释
- write是内存之间的操作,速度很快。
- fsync是内存和磁盘之间的操作,速度慢,占据磁盘的IOPS。
写入控制策略
write和fsync的时机可调,参数sync_binlog可以控制
- sync_binlog = 0 ,每次提交事务只write, 不fsync.
- sync_binlog = 1, 每次提交事务都会执行fsync。
- sync_binlog= N, 每次提交事务都write, 但累积N个事务后才fsync,N 的取值范围为(100,1000)。
通俗理解,sync_binlog 控制的是fsync的时机,处于数据恢复和效率,一般不取0和1,
4. redo log 写入机制
流程
- redo log 先写入 redo log buffer中,存储在mysql的进程中。(内存)
- 写到(write)page cache, 存储在文件系统的页缓存中。(内存)
- 持久化(fsync)到磁盘。
写入控制策略
redo log的写入控制同样是通过参数去调整:innodb_flush_log_at_trx_commit
从参数名就可以看出, 是innodb提供的在事务提交时redo_log的刷盘策略
- 设置为0表示 每次事务提交时都把redo log留在 redo log buffer。
- 设置为1表示 每次事务提交时都将 redo log 直接持久化到磁盘中。
- 设置为2表示 每次事务提交时都只是把redo log 写到page cache。
此外,Innodb存在一个后台线程,每隔1秒,机会将redo lo个buffer中的日志,刷盘到page cache,然后持久化到磁盘中。
5. 两阶段提交机制
MySQL一般采用的是双“1”策略,就是sync_binlog 和 innodb_flush_log_at_trx_commit都为1。
换言之,一次完整的事务提交需要等待两次刷盘,一次是在redo log(prepare) fsync,一次是在写binlog中fsync。
引发新的问题:
如果MySQL的TPS为每秒2万,按照两阶段提交,每秒机会有四万次写磁盘,但是
磁盘能力就2万每秒,如何实现两万的TPS?
换言之:就是在遇到磁盘瓶颈时,如何优化,减少刷盘次数
组提交机制(group commit)
LSN
在介绍组提交之前,需要了解日志逻辑序列号(log sequence number, LSN),这是一个单调递增,且对应redo log的写入点,每次写入长度为length的redo log, LSN的值就会加上length。
这段话比较难理解,可以看图理解。
redo log 采用组提交的示例
图片来自《MySQL45讲》
- trx1 是第一个到达的,会被选为这组的 leader;
- 等 trx1 要开始写盘的时候,这个组里面已经有了三个事务,这时候 LSN 也变成了 160;
- trx1 去写盘的时候,带的就是 LSN=160,因此等 trx1 返回时,所有 LSN 小于等于 160 的 redo log,都已经被持久化到磁盘;
- 这时候 trx2 和 trx3 就可以直接返回。
总结:一次组提交里面,组员越多,节约磁盘 IOPS 的效果越好。
在并发场景下,为了尽可能多的的在一次组提交内包含更多的组员,第一个事务在写完redo log buffer之后,接下来的fsync需要尽可能的晚调用。
优化
在MySQL 中就有这样的优化:为了让一次fsync带的组员更多,采取拖时间。
将redo log prepare分成两个阶段文章来源:https://www.toymoban.com/news/detail-484957.html
- write: 将redolog cache 写入 page cache
- fsync:: 将page cache中的redo log 日志持久化到磁盘中。
将binlog 分成两个阶段: - write : 将日志从binlog cache写入page cache中的binlog文件
- fsync: 将binlog文件持久化到磁盘。
本着拖时间的原则来分析:
将 prepare 阶段的 fsync 拖到binlog的write之后,
同样binlog的fsync 拖到了 redo log的fsync之后,
优化后的方案:redo log 和bin log 都实现了组提交。
区别在于 binlog的组提交带来的优化效果不如 redo log,主要原因是拖的时间不长
大佬原话:
但是可以通过参数来控制:文章来源地址https://www.toymoban.com/news/detail-484957.html
- binlog_group_commit_sync_delay ;表示延迟多少微秒后才调用 fsync;
-
binlog_group_commit_sync_no_delay_count ,表示累积多少次以后才调用 fsync。
两条件是或的关系,满足一个就会调用fsync。
到了这里,关于MySQL如何保证数据的可靠性(保证数据不丢失)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!