区分binlog和redolog
binlog记录的是逻辑日志,把二进制转化一下,里面就是“UPDATE tb_student SET age=16 WHERE name='赵%' ”这样的sql语句,只记录增删改,不记录查。redolog是物理日志,记录的是磁盘上的数据发生了什么变化。
binlog主要为了保证主从一致性。redolog主要让InnoDB存储引擎拥有了崩溃恢复能力。
一、binlog
MySQL的二进制日志binlog可以说是MySQL最重要的日志.
binlog日志有两个最重要的使用场景。
(1)mysql主从复制:有两个数据库,一个是主数据库,另一个从数据库用来备份。主数据库把binlog传给从数据库就完成了主从复制。
具体操作:mysql replication在master端开启binlog,master把它的二进制日志传递给slaves来达到master-slave数据一致的目的。
(2)数据恢复:通过mysqlbinlog工具来恢复数据。
binlog日志包括两类文件:
(1)二进制日志索引文件(文件名后缀为.index)用于记录所有的二进制文件。
(2)二进制日志文件(文件名后缀为.00000*)记录数据库所有的DDL和DML(除了数据查询语句select)语句事件。
如何查看binlog日志文件?常用有两种方式
1、使用mysqlbinlog自带查看命令法
注意:
1)binlog是二进制文件,普通文件查看器cat、more、vim等都无法打开,必须使用自带的mysqlbinlog命令查看。
2)binlog日志与数据库文件在同目录中。
3)在Mysql5.5以下版本使用mysqlbinlog命令时如果报错,就加上"--no-defaults"选项
4)使用mysqlbinlog命令查看binlog日志内容,下面截取其中的一个片段分析分析:
解释:
server id 1:数据库主机的服务号
end_log_pos 796 :sql结束时的pos节点
thread_id=11:线程号
5)也可根据时间点查看
/home/software/mysql-5.1.72-linux-x86_64-glibc23/bin/mysqlbinlog --no-defaults mysql-bin.000720 --start-datetime="2018-09-12 18:45:00" --stop-datetime="2018-09-12:18:47:00"
2. show binlog events
上面这种办法读取出binlog日志的全文内容比较多,不容易分辨查看到pos点信息,下面介绍一种更为方便的查询命令:
mysql> show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count];参数解释:
a、IN 'log_name':指定要查询的binlog文件名(不指定就是第一个binlog文件)
b、FROM pos:指定从哪个pos起始点开始查起(不指定就是从整个文件首个pos点开始算)
c、LIMIT【offset】:偏移量(不指定就是0)
d、row_count :查询总条数(不指定就是所有行)
看这里:mysql binlog详解_mysqlbinlog_油焖大虫下的博客-CSDN博客
二、回滚日志 uodolog
记录数据的历史版本。
就俩作用:
- 单条命令/事务失败的时候,回滚到单条命令/事务开始前的历史数据。
- PS:单条命令也可能失败呀,比如你执行一条update要更新10万行,但是更新到50万行的时候断电了。
- MVCC
终于搞明白回滚和前滚的区别了,二者是反方向!
三、前滚/重做日志redolog
数据先写到缓冲中,再写入磁盘中,但是如果事务已经提交了,数据也写到了缓存中,在提交到硬盘的过程中断电了。
解决方法:必须先写redolog,再写数据库。
binlog和redolog应该先写谁?
假设binglog主要用来实现主从同步。
如果master先写binlog,让数据A+1,然后写redolog的时候断电了(断电重启后,系统会自动redo),redolog上没有A+1的日志记录,binlog和redolog上数据的修改不一致。那么maser重启redo的时候会丢失,但是传给slave的binlog里存在A+1,这就造成了主从不一致。
如果master先写redolog,让数据A+1,然后写binlog的时候断电了。master重启后,A+1生效,但是传给slave的binlog里不存在A+1,也造成了主从不一致。
所以,无论是先写binlog还是先写redolog,都存在数据不一致的风险。相信你应该看出来了,这俩应该要么一起写,要么一起不写,应该是原子性的才对。跟分布式事务的处理思路一样,解决这种“没法原子性但硬要原子性”问题的方式就是标记中间状态。
解决方法:两阶段提交,其实就是先写redolog再写binlog,但是给redolog设置一个状态位,写完redolog以后给他打个prepare标签,标志着这是一个中间状态,当binlog也写完了以后,再把这个标签变成commit。
使用两阶段提交后,如果写入binlog时崩了,因为MySQL(严格来说是innodb引擎)根据redo log日志恢复数据时,发现redo log还处于prepare阶段,并且没有对应binlog日志,就会回滚该事务。
看一个特殊情况,如果崩的时候已经写入binlog了,只不过还没来得及设置commit就崩了,那会不会回滚事务呢?
不会回滚,它会执行上图框住的逻辑,虽然一看redo log打着prepare的标签,但是如果能通过事务id找到对应的binlog日志,就MySQL认为是完整的,就会提交事务恢复数据。