概念

即数据库告诉我这次事务成功了,但当我下次读取数据时,却发现数据不正确。这就是数据丢失.

原因

看个场景, redo log丢失造成的主从不一致:

bin-log写入所以从库能够执行事务。但主库中trx_prepare的日志没有被写入到ib_logifle中,导致主库不执行事务。这样就会出现主从不一致的情况—主库没执行事务,而从库执行。成的主从不一致

redo log 刷盘策略由 innodb_flush_log_at_trx_commit 参数控制:

0:每秒刷新一次 1:每次commit刷新一次(默认值,MySQL5.6) 2:每次commit都 write os cache,然后根据 innodb_flush_log_at_timeout 参数(默认为1s) flush disk

mysql> show variables like '%innodb_flush_log_at_trx_commit%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
1 row in set (0.00 sec)

mysql> show variables like '%innodb_flush_log_at_timeout%';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| innodb_flush_log_at_timeout | 1     |
+-----------------------------+-------+
1 row in set (0.00 sec)

mysql> 

说下事务日志(MySQL里是 redo log, Oracle是 transaction log, 但都是指同一样东西)

bin log

一般是在$DATADIR目录下的*hostname*-bin.index以及一些*hostname*-bin.00001文件。用于replication(复制,以及时间点恢复)

redo

在MySQL的$DATADIR(即数据目录)下的ib_logfile0 and ib_logfile1两个文件,就是redo log(用于 崩溃时恢复)

ib_logfile文件个数由 innodb_log_files_in_group 配置决定,若为2,则在datadir目录下有两个文件,命令从0开始,分别为ib_logfile0和ib_logfile1.

bin log 与 redo log 的区别

1)二进制日志会记录所有与mysql有关的日志记录,包括InnoDB等其他存储引擎的日志,而InnoDB存储引擎的重做日志只记录有关其本身的事务日志.

redo logInnoDB特有的,而bin log(绝大部分)都是事务独立的,并且bin log是对于所有存储引擎的,但redo log并不是。 比如, MyISAM可以写bin log,而InnoDB可以写bin logredo log

2)记录的内容不同,不管你将二进制日志文件记录的格式设为哪一种,其记录的都是关于一个事务的具体操作内容,而InnoDB存储引擎的重做日志文件记录的关于每个页的更改的物理情况;

3)写入的时间也不同,二进制日志文件是在事务提交前进行记录的,而在事务进行的过程中,不断有重做日志条目被写入重做日志文件中。从日志缓冲写入磁盘上的重做日志文件的条件:在主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件中,不论事务是否提交。另一个触发这个 过程是由参数innodb_flush_log_at_trx_commit控制,表示在提交时,处理重做日志的方式。参数innodb_flush_log_at_trx_commit可设的值有0、1、2.

0代表当提交事务时,并不将事务的重做日志写入磁盘上的日志文件,而是等待主线程每秒的刷新,而1和2不同的地方在于:
1是在commit时将重做日志缓冲同步写到磁盘;
2是重做日志异步写到磁盘,即不能完全保证commit时肯定会写入重做日志文件,只是有这个动作。 

简单说来,可选值的安全性从0->2->1递增,分别对应于mysqld 进程crash可能丢失 -> OS crash可能丢失 -> 事务安全

值得注意的一点:因为重做日志有个capacity变量,该值代表了最后的检查点不能超过这个阀值。

同步的策略

  1. 异步(这个无解)
  2. 半同步(主库会在自己完成事务后,等待备库接收事务日志) 问题:  在master提交事务之后,而slave未来得及接收复制事件,这时候master crash的话,应用程序会切换到slave上,并重新发起事务,这正好是我们所需要的,满足高可用的初衷。但是这里存在一个缺陷,那就是在master恢复之后,原来的事务已经提交,这时候复制会出现问题。)(还存在数据丢失,只是丢失的数据量下降到每条线程最多一个事务丢失) 2节点情况下:无解 3节点情况下:更强(除非2个备库一起挂了。。。)

那么是不是半同步下,数据就不丢了呢?我们前面说过,当网络,和备库出现间歇性问题时,那么半同步会降级为异步,那么如果恰恰在此时,备库的IO线程正在追赶主库的binlog位点,但是还没有完全同步上,主库down了(也就是说此时出现延迟的情况下),主备数据就会出现不一致。

  1. 强同步

参考资料

stackexchange

Mysql 重做日志及与二进制日志的区别

aliapp

aliyun