诡异!高并发场景下,事务已提交,数据却丢了?

场景:数据库是mysql,存储引擎是InnoDB

可以先了解一下什么是redo log、undo log和binlog?

  InnoDB事务日志包括redo log和undo log。

  redo log是重做日志文件,用于记录事务操作的变化,,记录的是数据修改之后的值,不管事务是否提交都会记录下来。在数据库奔溃时,还没有来得及将数据页刷盘,数据库重启时,会重做redo log里的内容,以保证已提交事务对数据的影响被刷到磁盘上。简单来讲,redo log是为了保证已提交事务的ACID特性,同时能够提高数据库性能的技术。(InnoDB层维护的)

  undo log是回滚日志文件,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC)。(InnoDB层维护的)

  binlog记录了对mysql数据库执行更改的所有操作,但是不包括select和show之类操作

今天就来了解redo log,它跟本主题关系紧密,先看看从redo log buffer写日志到磁盘的redo log file的过程:

images

图解:

redo log和undo log是一种顺序写,上图中关键词有:

  • InnoDB Engine(即mysql应用层):log buffer
  • OS Buffer:操作系统内存
  • log file:操作系统日志文件

mysql支持用户自定义在commit时如何将redo log buffer中的日志刷到log file中,这种控制通过变量innodb_flush_log_at_trx_commit的值来决定,该变量有3种值:0、1、2,默认为1。

这是设置三种值刷到log file的过程图:

下面来说说设置这三种值的区别:
  • innodb_flush_log_at_trx_commit=0:事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file中,如果数据库奔溃,会有一秒的数据丢失。(性能最佳)
  • innodb_flush_log_at_trx_commit=1:事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file中,这种方式不会丢失任何数据,但是因为每次提交都写入磁盘,io的性能较差,但是保证了事务ACID特性,InnoDB默认就是这种配置。(一致性好)
  • innodb_flush_log_at_trx_commit=2:每次提交都仅写入到os buffer,然后每秒调用fsync()将os buffer中的日志写入到log file。如果操作系统奔溃,最多有一秒的数据丢失。(是前面两种的折衷)
小结

在高并发业务中,最佳实践应该是innodb_flush_log_at_trx_commit=2,原因是操作系统奔溃的概率相比mysql应用程序奔溃的概率小很多,设置为2,只要操作系统不奔溃,也绝对不会丢失数据。

参考:

1、https://www.linuxidc.com/Linux/2018-01/150614.htm

2、https://blog.csdn.net/wanbin6470398/article/details/81941586

欢迎关注我的微信公众号,里面有很多干货,各种面试题
在这里插入图片描述

发布了222 篇原创文章 · 获赞 20 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/qq_17555933/article/details/102558857