InnoDB事务已经提交,数据库崩了,数据却丢失???

先说说redo log吧

  • 事务提交后,必须将事务对数据页的修改刷(fsync)到磁盘上,才能保证事务的ACID特性。

  • 这个刷盘,是一个随机写,随机写性能较低,如果每次事务提交都刷盘,会极大影响数据库的性能

随机写性能差,有什么优化方法呢?

  • (1)先写日志(write log first),将随机写优化为顺序写;

  • (2)将每次写优化为批量写;

将对数据的修改先顺序写到日志里,这个日志就是redo log。

  • 假如某一时刻,数据库崩溃,还没来得及将数据页刷盘,数据库重启时,会重做redo log里的内容,以保证已提交事务对数据的影响被刷到磁盘上。

  • 既然redo log能保证事务的ACID特性,那为什么还会出现“数据库崩了,丢数据”的问题呢?

  • 先看innodb的三层架构见InnoDB简要架构

优化为批量写有两个维度

  • 数据先写入Log Buffer里,然后统一WriteRedoLog

  • 数据先写入OS cache里,然后统一flush

redo log最终落盘的步骤如何?

  • 首先,事务提交的时候,会写入Log Buffer,这里调用的是MySQL自己的函数WriteRedoLog;

  • 接着,只有当MySQL发起系统调用写文件write时,Log Buffer里的数据,才会写到OS cache。注意,MySQL系统调用完write之后,就认为文件已经写完,如果不flush,什么时候落盘,是操作系统决定的;

  • 最后,由操作系统(当然,MySQL也可以主动flush)将OS cache里的数据,最终fsync到磁盘上;

这个副作用,就是可能丢失数据:

  • 1)事务提交时,将redo log写入Log Buffer,就会认为事务提交成功;(2)如果写入Log Buffer的数据,write入OS cache之前,数据库崩溃,就会出现数据丢失

  • (3)如果写入OS cache的数据,fsync入磁盘之前,操作系统崩溃,也可能出现数据丢失;

MySQL有一个参数能够控制事务提交时,刷redo log的策略。

策略一:最佳性能

innodb_flush_log_at_trx_commit=0

  • 每隔一秒,才将Log Buffer中的数据批量写入OS cache,同时MySQL主动fsync。

    mysql或linux宕机会丢失1秒数据,os cache基本无用

策略二:强一致

innodb_flush_log_at_trx_commit=1

  • 每次事务提交,都将Log Buffer中的数据write入OS cache,同时MySQL主动fsync。

    最多丢失一条未提交的事务,但是性能差

策略三:折衷

innodb_flush_log_at_trx_commit=2

  • 每次事务提交,都将Log Buffer中的数据write入OS cache;每隔一秒,MySQL主动将OS cache中的数据批量fsync。

    linux宕机会丢失1秒数据,但是linux比mysql宕机几率小很多

本文使用 文章同步助手 同步

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容