Mysql如何保证数据不丢失
一、前置问题
- binlog, redolog区别
二、InnoDB实现原子级的持久性
1. 直接把buffer中的修改页写到磁盘的挑战
1)如何保证Mysql底层数据页的完整性
首先写磁盘操作的非原子性,事务提交后,直接把buffer中的修改页写入磁盘,如果此过程中数据库宕机,则可能导致事务写入不完整,且重启后无法恢复;
2)如何避免频繁写Mysql数据页导致性能下降
随机写盘的IO效率低和响应时间长。因为数据库数据按B+数的结构存储,其数据必然是不连续的;持久化操作必然是非顺序写,IO的操作必然导致客户端响应时间变大;
2. Innodb的解决方案——redo log
1)double write
来避免partial page write
,保证页完整性。
双写的原则是任何时候不破坏页的完整性。BufferPoll中的脏页会先把他保存到其他地方,保存成功后再去覆盖原有位置的页。这样无论何时都有一个完整的数据页。
2)通过AOF日志记录避免频繁刷盘
redo log是Innodb存储引擎引入的,用来解决事务级别的持久化和原子性;redo log的使用是建立在页完整的基础上的。
I、redo log存储了本次的事务的操作,其最后的行end trx_num
来标识事务是否已完成;通过该行来原子性标识是否事务是否完成;
II、redo log顺序写的特性保证其IO效率高,响应快;
通过同步写redo log,异步刷新修改页到磁盘实现高响应;如果写磁盘发生宕机则通过重放redo log实现crash recovery,实现数据不丢失;
三、bin log
bin log是mysql server层的日志,主要用来实现主从同步;
四、redo log的二段式提交
innoDB为了使redo log和bin log保持同步,即保证主库和从库的同步,在收到事务的commit操作后,采用二段式提交实现;
1)第一步:pepare redo log,第一次提交
1 | start tx_num; |
2)第二步:write bin log
1 | write binlog; |
3)第三步:end tx_num,第二次提交
1 | end tx_num; |
此时,有三种场景:
1)第一步失败(redo log中无prepare tx_num
行)- mysql认为事务提交失败,忽略事务;
2)第二步失败(redo log中存在prepare tx_num
行)- mysql通过redo log恢复bin log,继续执行第三步,事务提交成功;
3)第三步失败(redo log中存在prepare tx_num
行)- 重启后继续执行第三步,事务提交成功;