MYSQL的日志写入磁盘的理解

BinLog的写入机制

在这里插入图片描述

binlog日志在事务没有提交之前会想写入到binlog cache中, 每个线程都有一个binlog cache。
在事务提交后才会一次性写入到文件系统的缓存file page中。

然后mysql会根据你的sync_binlog配置决定是否马上刷新到磁盘中。

  • sync_binlog=0 的时候,表示每次提交事务都只 write到file page中,不 fsync到磁盘;
  • sync_binlog=1 的时候,表示每次提交事务都会执行 fsync;
  • sync_binlog=N(N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync。

fsync到磁盘也是顺序写入磁盘的,没有磁盘的寻址消耗。为了安全起见建议sync_binlog设置成1. 每次写入一个事务都落盘。 但是也可以根据情况设置成N。 设置成N会提高写入的效率,但是如果操作系统被断电,那么写入file cache中的N个事务数据会丢失掉。

redo log 的写入机制

redo log 也在自己的内存缓存区redo log buffer。事务在执行过程中会放入到这个缓存中,在提交后会写入到redo log磁盘文件中。 所以在redo log buffer中的事务都是没有提交的事务。

但是也有情况导致事务没有提交的时候也会落盘的情况。 redo 的写入磁盘也和上面的bin log一样有一个file cache区间。 对应也有一个配置:innodb_flush_log_at_trx_commit

  • 设置为 0 的时候,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中 ;
  • 设置为 1 的时候,表示每次事务提交时都将 redo log 直接持久化到磁盘;
  • 设置为 2 的时候,表示每次事务提交时都只是把 redo log 写到 file cache。
  1. MYSQL 会有一个后台线程,每隔1秒把redo log buffer 持久化到磁盘, 直接经过file cache到磁盘。
  2. 如果并发的事务提交落盘后也会连带着把另外一个事务的redo log buffer持久化到磁盘。
  3. redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动写盘来减少 redo log buffer 的空间占用

所以没有提交的事务也会被MYSQL写入到磁盘。

我们知道redo 日志提供了崩溃回复的功能, 并且它和bin log一起配合采用两阶段提交的方式保证Mysql的崩溃恢复。

redo log和bin log是如何高效写入的

如果我们把sync_binlog =1 和innodb_flush_log_at_trx_commit=1 都设置上, 那么每次事务提交都至少有两次磁盘操作,按理来说, mysql不会有这么高的性能的。

这里MYSQL使用了组提交的机制, 和磁盘顺序写入的功能。

组提交机制

磁盘在每次读取数据的时候,都是按块读取的,比如你要读取1个字节的内容,但是磁盘会给你读取4k的内容到内存中, 然后从内存中取出一个字节返回给应用程序, Mysql的B+tree索引就是使用了这个特性。

当然写入如果每次写入很小的数据(一个事务),对于磁盘来说是很不划算的, 如果每次写入的数据很多, 这次写入的性价比才高。

基于这个特性, mysql会把redo 的写入积攒起来一起写入, 还会把redo的日志积攒到和binlog一起fsync到磁盘中。

磁盘顺序写入

顺序写入的时候,磁盘减少了寻址的空间, 这样也会大大提高性能

碰到磁盘IO瓶颈

如果你预算充足,无脑SSD就可以,但是避免浪费我们还是需要榨干每块磁盘的性能的,

上文说道组提交的时候,redo 的写入会积攒等待到bin log一起fsnyc的。 同样bin log也会积攒等待到redo log一起提交, bin log的等待时间是可以配置的,binlog_group_commit_sync_delay 表示binlog的的积攒延迟时间, binlog_group_commit_sync_no_delay_count 表示binlog累计积攒多少次。

  • 设置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count 参数,减少 binlog 的写盘次数。这个方法是基于“额外的故意等待”来实现的,因此可能会增加语句的响应时间,但没有丢失数据的风险。
  • 设置 sync_binlog为大于1的值, 会有丢失binlog的风险
  • 设置innodb_flush_log_at_trx_commit的值大于1。 会有断电后丢失事务数据的风险

sync_binlog和innodb_flush_log_at_trx_commit设置成大于1的话, 这里只是承受linux系统断电的风险,不用承受MYSQL崩溃重启的风险。 而现实中服务器意外断电的可能会小很多,反而MYSQL崩溃的可能更大。 所以不建议把innodb_flush_log_at_trx_commit设置成0 。 sync_binlog也一样。

sync_binlog和binlog_group_commit_sync_no_delay_count 都有累计积攒多少次的意思,那么他们之间是否会互相影响呢?
MYSQL会先判断sync_binlog的是否达到, 达到之后会进入binlog_group_commit_sync_no_delay_count 的判断逻辑,会判断它是否达到,都达到之后会落盘。

sync_binlog表示事务参与积攒后写入到file cache后就返回到客户端了

binlog_group_commit_sync_no_delay_count 表示事务没有积攒够,参与积攒的事务都会堵塞, 这个值设置的不好会导致事务延时变长。

在数据库事务提交成功后,但是没有返回给客户端,此时网络断开了,这种情况会怎么办?

其实客户端也有自己的处理事务的原则的。 下面三点所说的异常都是值数据库的异常,不要弄混了。

  1. 客户端收到成功消息了, 那么数据库肯定已经提交成功了
  2. 客户端收到数据库的异常消息,比如主键冲突异常。 这个时候数据库一定是事务失败了。
  3. 如果客户端收到数据库的执行异常消息, 这个时候客户端需要重新访问数据库询问事务的状态

网络断开属于执行异常, 客户端收到数据库连接的网络断开消息后,客户端是需要重新连接上数据库来询问事务是否成功还是失败的。 这符合第三点的情况

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值