读mysql45讲-日志完整性

binlog的写入机制

binlog的写入过程是在事务执行过程中,先把日志写到binlog cache中,然后在事务提交的时候,把binlog cache写入到binlog文件中。

事务是不能分开的,所以不管事务多大,都是将日志一次性的写入到binlog cache中的。而且binlog cache是每个线程独有的,也就是每一个事务独有的,这样保证隔离性。 binlog_cache_size这个参数是配置单个线程中binlog cache的内存大小的,如果超过这个大小,就需要暂存到磁盘中,就是为了保证事务能够一次性的全部写入。

在这里插入图片描述

可以看到,每个线程是有单独的binlog cache的,但是公用一份binlog文件。

  • 其中将binlog cache中write到binglog files的过程是指将binlog cache中的日志写入到page cache中,并没有直接写入到磁盘中。
  • fsync这个过程才是将日志写入到磁盘文件中。

参数sync_binlog的作用

  • sync_binlog=0表示每次提交事务都只是将日志write到page cache中
  • sync_binlog=1表示每次提交事务都是fsync到磁盘文件中
  • sync_binlog=N表示每次提交事务都是先write到page cache中,等事务个数累积到N的时候才会一起fsync到磁盘里面。

为了减少写磁盘的次数,正常都是将sync_binlog设置为100-1000的一个数,但是这样配置可能会有一个问题:如果主机异常重启的话,会导致binlog日志的缺失。

redo log的写入机制

redo log buffer就是一块内存,事务在执行过程中也是先将日志写到redo log buffer中,在执行commit语句的时候才会将日志写到redo log文件中(文件名ib_logfile)。

redo log buffer每次生成新的内容的时候是不需要写到磁盘中的,因为如果执行期间MySQL发生了异常重启的话,因为这个时候并没有提交,所以哪怕日志丢了也不影响。

redo log 的三种状态:

在这里插入图片描述

  • 存在于redo log buffer中,物理上是在MySQL分配的内存中
  • 写入(write)磁盘,但是没有持久化(fsync),物理上是在文件系统的page cache中,
  • 持久化到磁盘文件中。

日志写到redo log buffer中是很快的,因为是操作内存,write到page cache中也是很快的,但是持久化到磁盘中的速度是相对于来说慢的。为了控制redo log 的写入策略,InnoDB提供了innodb_flush_log_at_trx_commit参数。

  1. innodb_flush_log_at_trx_commit=0表示每次提交事务都只是将redo log日志写到redo log buffer中。
  2. innodb_flush_log_at_trx_commit=1表示每次提交事务都是将redo log持久化到磁盘中
  3. innodb_flush_log_at_trx_commit=2表示每次提交事务都是将redo log写到page cache中。

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

正常配置innodb_flush_log_at_trx_commit参数的时候是不会配置成0的,因为如果MySQL发生异常重启的话,就会丢失redo log日志。但是因为后台线程每隔一秒就会持久化磁盘的操作,所以设置成1和2其实差异不大。

在事务执行过程中可能redo log日志已经持久化到磁盘中了:

  • 后台线程每秒的轮询操作
  • 因为redo log buffer是公用的,所以并行的事务是会将redo log buffer日志持久化到磁盘中的。A线程正在执行,还未提交,B线程执行完毕提交事务了,这个时候会将redo log buffer中的日志都一起写到page cache中然后持久化到磁盘中吗,包括A线程的日志。
  • redo log buffer中实际占用的内存即将达到innodb_log_buffer_size的一半,这个时候后台线程会将redo log日志写到page cache中,但是因为事务没有提交,所以只会写到page cache中,不会持久化到磁盘中。

组提交(group commit)机制

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

如果多个事务都准备写入到磁盘的时候,并不会一个一个写入磁盘,那是会一起组团写入到磁盘中。在并发更新场景下,第一个事务写完redo log buffer以后,接下来这个fsync越晚调用,组员可能 越多,节约IOPS的效果就越好。为了让一次fsync带的组员更多,MySQL有一个很有趣的优化:拖时间。

在这里插入图片描述

这样一来,binlog和redo log都是组提交的方式来提交,通常第三步会执行的很快,所以binlog的write和fsync间隔的时间很短,组员就会很少,所以binlog的组提交的效果不如redo log的效果那么好。

如果你想提升binlog组提交的效果,可以通过设置 binlog_group_commit_sync_delay和 binlog_group_commit_sync_no_delay_count来实现。

  • binlog_group_commit_sync_delay;表示延迟多少微秒后才调用fsync;
  • binlog_group_commit_sync_no_delay_coun,表示累积多少次以后才调用fsync。

这两个条件是或的关系,只要有一个满足条件就会调用fsync。通过设置这两个参数就可以累计更多的组员,从而让组提交的效果可以更好。所以当binlog_group_commit_sync_delay=0的时候其实设置binlog_group_commit_sync_no_delay_coun多少都无所谓,同样的将binlog_group_commit_sync_no_delay_coun=1,那么binlog_group_commit_sync_delay设置也毫无意义。

WAL机制主要得益于两个方面:

  1. redo log和binlog都是顺序写,磁盘的顺序写比随机写的速度要快
  2. 组提交机制可以大幅度的降低磁盘的IOPS消耗。

如果MySQL出现了性能瓶颈,可以考虑的方法:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值