MySQL中数据丢失概念及解决办法
Contents
概念
即数据库告诉我这次事务成功了,但当我下次读取数据时,却发现数据不正确。这就是数据丢失
.
原因
看个场景, 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 log
是InnoDB
特有的,而bin log
(绝大部分)都是事务独立的,并且bin log
是对于所有存储引擎的,但redo log
并不是。
比如, MyISAM
可以写bin log
,而InnoDB
可以写bin log
和redo 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变量,该值代表了最后的检查点不能超过这个阀值。
同步的策略
- 异步(这个无解)
- 半同步(主库会在自己完成事务后,等待备库接收事务日志) 问题: 在master提交事务之后,而slave未来得及接收复制事件,这时候master crash的话,应用程序会切换到slave上,并重新发起事务,这正好是我们所需要的,满足高可用的初衷。但是这里存在一个缺陷,那就是在master恢复之后,原来的事务已经提交,这时候复制会出现问题。)(还存在数据丢失,只是丢失的数据量下降到每条线程最多一个事务丢失) 2节点情况下:无解 3节点情况下:更强(除非2个备库一起挂了。。。)
那么是不是半同步下,数据就不丢了呢?我们前面说过,当网络,和备库出现间歇性问题时,那么半同步会降级为异步,那么如果恰恰在此时,备库的IO线程正在追赶主库的binlog位点,但是还没有完全同步上,主库down了(也就是说此时出现延迟的情况下),主备数据就会出现不一致。
- 强同步