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

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

binlog的写入机制

binlog的写入逻辑比较简单:事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。

系统给binlog cache分配了一片内存,每个线程一个,参数binlog_cache_size用于控制单个线程binlog cache所占内存的大小。如果超过了这个参数规定的大小,就要暂存磁盘。

事务提交的时候,执行器把binlog cache里的完整事务写入到binlog中,并清空binlog cache。

每个线程都有自己的binlog cache,但是共用一份binlog文件。

  • 图中write,是把日志写入到文件系统的page cache,并没有持久化到磁盘,速度比较快;
  • 图中fsync,持久化到磁盘。一般,认为fsync才占磁盘的IOPS。

write和fsync的时机,由参数sync_binlog控制:

  1. sync_binlog=0,每次提交事务只write,不fsync;
  2. sync_binlog=1,每次提交事务都会fsync;
  3. sync_binlog=N(N>1),每次提交事务都write,但累积N个事务后才fsync。

实际场景中,比较常见的是是将其设置成100~1000中的某个数值。这样对应的风险是:如果主机发生异常重启,会丢失对应数值的binlog日志。

redo log的写入机制

事务执行过程汇总,生成的redo log先写到redo log buffer中。

每次生成后不需要直接持久化到磁盘。

事务还没提交的时候,有可能redo log buffer中的部分日志也有可能被持久化到磁盘。

redo log可能存在的三种状态:

三种状态分别是:

  1. 存在redo log buffer中,物理上是在MySQL进程内存中,就是图中的红色部分;
  2. 写到磁盘(write),但是没有持久化(fsync),物理上是在文件系统的page cache里面,图中中黄色部分;
  3. 持久化到磁盘,对应的hard disk,图中绿色部分。

写到redo log很快,write到page cache也差不多,持久化到磁盘的速度就慢多了。

为了控制redo log的写入策略,InnoDB提供了innodb_flush_log_at_trx_commit参数,有三种可能取值:

  1. 0,每次提交事务都只是把redo log留在redo log buffer中;
  2. 1,每次提交事务都将redo log直接持久化到磁盘;
  3. 2,每次提交事务都都只是把redo log写到page cache。

InnoDB有一个后台线程,每隔1秒,会把redo logbuffer中的日志,调用write写到系统的page cache,然后条用fsync持久化到磁盘。

注意:事务执行过程的redo log也是直接写在redo log buffer中的,这些redo log也会被后台线程一起持久化到磁盘,就是说,一个没有提交的事务的redo log,也是可能已经持久化到磁盘的。

除了后台线程,还有两种场景也会让一个没有提交的事务的redo log写入到磁盘中:

  1. redo log占用的空间即将达到innodb_log_buffer_size一般的时候,后台线程会主动写盘。注意,由于事务没有提交,这个写盘动作只是write,没有调用fsync,就是只留在了文件系统的page cache。
  2. 并行的事务提交的时候,顺带将这个事务的redo logbuffer持久化到磁盘

MySQL的“双1”配置,指的是sync_binlog和innodb_flush_log_at_trx_commit都设置成1,意思是,一个事务完整提交前,需要等待两次刷盘,一次是redo log(prepare阶段),一次是binlog。

 

组提交机制

 

如果MySQL出现了性能瓶颈,而且瓶颈在IO上,可以通过哪些方法来提升性能:

  1. 设置binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count参数,减少binlog的写盘次数。这个方法是基于“额外的故意等待”来实现的,可能会增加语句的响应时间,但没有丢失数据的风险。
  2. 将sync_binlog设置为大于1的值(比较常见的是100~1000)。这样的风险是,主机掉电时会丢失binlog日志。
  3. 将innodb_flush_log_at_trx_commit设置为2,这样的风险是,主机掉电的时候会丢失数据。

不建议将innodb_flush_log_at_trx_commit设置成0。

 

上一篇:22 | MySQL有哪些“饮鸩止渴”提高性能的方法?

下一篇:24 | MySQL是怎么保证主备一致的?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值