MySQL如何保证数据的可靠性(保证数据不丢失)

1. 结论:

只要redo logbinlog 保证持久化到磁盘,就能确保MySQL异常重启后,数据可以恢复。

2. 机制

WAL机制,(Write Ahead Log): 事务先写入日志,后持久化到磁盘。

3. binlog 写入机制

binlog写入流程图,选自《MySQL45讲》

流程

  • 每个线程内都有一个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可以控制

  1. sync_binlog = 0 ,每次提交事务只write, 不fsync.
  2. sync_binlog = 1, 每次提交事务都会执行fsync。
  3. sync_binlog= N, 每次提交事务都write, 但累积N个事务后才fsync,N 的取值范围为(100,1000)。
    通俗理解,sync_binlog 控制的是fsync的时机,处于数据恢复和效率,一般不取0和1,

4. redo log 写入机制

redo log的三种状态

流程

  1. redo log 先写入 redo log buffer中,存储在mysql的进程中。(内存)
  2. 写到(write)page cache, 存储在文件系统的页缓存中。(内存)
  3. 持久化(fsync)到磁盘。

写入控制策略

redo log的写入控制同样是通过参数去调整:innodb_flush_log_at_trx_commit
从参数名就可以看出, 是innodb提供的在事务提交时redo_log的刷盘策略

  1. 设置为0表示 每次事务提交时都把redo log留在 redo log buffer。
  2. 设置为1表示 每次事务提交时都将 redo log 直接持久化到磁盘中。
  3. 设置为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讲》
在这里插入图片描述

  1. trx1 是第一个到达的,会被选为这组的 leader;
  2. 等 trx1 要开始写盘的时候,这个组里面已经有了三个事务,这时候 LSN 也变成了 160;
  3. trx1 去写盘的时候,带的就是 LSN=160,因此等 trx1 返回时,所有 LSN 小于等于 160 的 redo log,都已经被持久化到磁盘;
  4. 这时候 trx2 和 trx3 就可以直接返回。

总结:一次组提交里面,组员越多,节约磁盘 IOPS 的效果越好。
在并发场景下,为了尽可能多的的在一次组提交内包含更多的组员,第一个事务在写完redo log buffer之后,接下来的fsync需要尽可能的晚调用。

优化

在MySQL 中就有这样的优化:为了让一次fsync带的组员更多,采取拖时间。
将redo log prepare分成两个阶段

  • 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,主要原因是拖的时间不长
大佬原话:
在这里插入图片描述
但是可以通过参数来控制:

  1. binlog_group_commit_sync_delay ;表示延迟多少微秒后才调用 fsync;
  2. binlog_group_commit_sync_no_delay_count ,表示累积多少次以后才调用 fsync。
    两条件是或的关系,满足一个就会调用fsync。

猜你喜欢

转载自blog.csdn.net/YuannaY/article/details/131209498