Binlog 日志的作用
一、Binlog 日志的作用
Binlog日志,即binary log,是二进制日志文件,有两个作用,一个是增量备份,另一个是主从复制,即主节点维护一个binlog日志文件,从节点从binlog中同步数据,也可以通过binlog日志来恢复数据。
二、Binlog 三种模式
Statement Level 模式 5.5默认模式
Row Level 模式 5.7默认模式
Mixed 模式(混合模式)
2.1 Statement Level模式
记录每一条修改数据的SQL语句(批量修改时,记录的不是单条SQL语句,而是批量修改的SQL语句事件)。
优点:statement模式记录的更改的SQ语句事件,并非每条更改记录,所以大大减少了binlog日志量,节约磁盘IO,提高性能。
缺点:statement level下对一些特殊功能的复制效果不是很好,比如:函数、存储过程的复制。由于row level是基于每一行的变化来记录的,所以不会出现类似问题
2.2 Row Level模式
记录的方式是行,即如果批量修改数据,记录的不是批量修改的SQL语句事件,而是每条记录被更改的SQL语句,因此,ROW模式的binlog日志文件会变得很“重”。
优点:row level的binlog日志内容会非常清楚的记录下每一行数据被修改的细节。而且不会出现某些特定情况下存储过程或function,以及trigger的调用和触发器无法被正确复制的问题。
缺点:row level下,所有执行的语句当记录到日志中的时候,都以每行记录的修改来记录,这样可能会产生大量的日志内容,产生的binlog日志量是惊人的。批量修改几百万条数据,那么记录几百万行……
2.3 Mixed模式(混合模式)
实际上就是前两种模式的结合,在mixed模式下,mysql会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也是在statement和row之间选择一种。
企业场景如何选择binlog的模式
- 如果生产中使用MySQL的特殊功能相对少(存储过程、触发器、函数)。选择默认的语句模式,
Statement Level
。 - 如果生产中使用MySQL的特殊功能较多的,可以选择
Mixed
模式。 - 如果生产中使用MySQL的特殊功能较多,又希望数据最大化一致,此时最好
Row level
模式;但是要注意,该模式的binlog非常“沉重”。
例如:
Statement Level模式
1 | 100w条记录 |
ROW 行级模式
1 | 100w条记录 |
MIXED混合模式
1 | 100w条记录 |
对于函数、触发器、存储过程会自动的使用row-level模式
三、修改 Binlog 模式
查看安装的mysql是否开启binlog日志功能
1 | mysql> show variables like 'log_bin%'; |
查看 Binlog 的模式
1 | mysql> show variables like 'binlog_format'; |
开启 Binlog 并设置 Binlog模式
1 | # vim /etc/my.cnf |
四、查看 Binlog
Binlog是二进制文件,普通文件查看器cat
、more
、vi
等都无法打开,必须使用自带的 mysqlbinlog 命令查看
1 | # mysqlbinlog --no-defaults --base64-output='decode-rows' -v /var/lib/mysql/mysql-bin.000001 |
at 后面的数字就是开始的 pos 点,end_log_pos 后面的数字则是结束的pos点
也可以使用 mysql 查询语句查看
语法:
show binlog events [IN ‘log_name’] [FROM pos] [LIMIT [offset,] row_count];
IN ‘log_name’: 指定要查询的binlog文件名(不指定就是第一个binlog文件);
FROM pos:指定从哪个pos起始点开始查起(不指定就是从整个文件首个pos点开始算);
LIMIT [offset,]:偏移量(不指定就是0);
row_count:查询总条数(不指定就是所有行)。
查看总共有几个binlog
文件
1 | mysql> show master logs; |
查看Binlog
1 | mysql> show binlog events in 'mysql-bin.000004' limit 5; |
五、通过Binlog恢复数据
恢复命令的语法格式:
mysqlbinlog –start-position=121 –stop-position=257 -d 数据库名 /tmp/mysql-bin.000004|mysql -u用户名 -p’密码’ 数据库名| mysql -u用户名 -p密码 数据库名
常用参数选项:
–start-position=121 起始pos点
–stop-position=257 结束pos点
–start-datetime=”2018-7-25 10:18:18” 起始时间点
–stop-datetime=”2018-7-25 10:28:46” 结束时间点
–d xxx 指定只恢复xxx数据库
实际是将读出的binlog日志内容,通过管道符传递给mysql命令。这些命令、文件尽量写成绝对路径;
数据库只读模式
在对生产数据库进行恢复操作前,如果业务允许尽量先将数据库设置为只读模式
1 | mysql> set global read_only=1; |
这样可以避免在恢复过程中普通用户又对数据进行修改,造成数据二次污染
在恢复完后再关闭数据库只读模式
1 | mysql> set global read_only=0; |
5.1 恢复全量数据
使用.sql
文件全量恢复(记得剔除掉问题语句比如drop
)
1 | mysqlbinlog /opt/backup/mysql-bin.000004 > /opt/backup/000004.sql |
5.2 全量备份 + binlog还原
例如现在有一个学生表 student
1 | mysql> select * from student; |
不小心将 sname 为 张三 的数据删掉了
1 | mysql> delete from student where sname='张三'; |
现在开始恢复数据的步骤
查询最新的binlog日志,binlog存放路径
1 | mysql> show master logs; |
解析binlog日志,根据刚刚执行的SQL语句查找到pos的起始和结束值
1 | # mysqlbinlog --no-defaults --base64-output='decode-rows' -v /var/lib/mysql/mysql-bin.000004 |
刚才删除的 张三 的SQL在pos 12812开启了事务,该 pos 12812就是我们要还原的结束点
第一步:找到离刚刚删除 张三 最近的 pos 12812
第二步:将距离最近全量备份数据到现在的binlog 拷贝到其它目录
第三步:将最近的全量备份还原到数据库,并查看post节点
1 | # mysql -uroot -p'123456' < /opt/backup/all_databases.sql |
找出全量备份的pos结束点
1 | cat /opt/backup/all_databases.sql|grep -i 'CHANGE MASTER TO MASTER_LOG_FILE' |
第四步:还原binlog pos 10729到 pos 12812的数据
1 | # mysqlbinlog --start-position=10729 --stop-position=12812 -d school /var/lib/mysql/mysql-bin.000004|mysql -uroot -p'123456' school |
最后查看数据已恢复
1 | mysql> select * from student; |
5.3 binlog 还原
这个得找到离删除 张三 最近的数据修改,然后才能还原到张三删除前的数据
还是刚刚的student,以继续往上查找binlog
1 | # mysqlbinlog --no-defaults --base64-output='decode-rows' -v /var/lib/mysql/mysql-bin.000004 |
找到了离delete 张三 前最近的数据改动是 insert 插入的张三数据,起始pos 10540 结束 pos 10685
那么就可以使用该起始和结束pos来还原
1 | # mysqlbinlog --start-position=10540 --stop-position=10685 -d school /var/lib/mysql/mysql-bin.000004|mysql -uroot -p'123456' school |
最后查看数据已恢复
1 | mysql> select * from student; |
5.4 恢复单个表的数据
通常在从全库备份恢复中可以指定--one-database
简写-o
,参数来指定要恢复的库
1 | # mysql -uroot -p'123456' -o school < /opt/backup/all_databases.sql |
那么如何从全库备份中抽取某张表呢,全库恢复,再恢复某张表小库还可以,大库就很麻烦了,那我们可以利用正则表达式来进行快速抽取,具体实现方法如下
先从全库备份中抽取出student
表的表结构
1 | # sed -e'/./{H;$!d;}' -e 'x;/CREATE TABLE `student`/!d;q' /opt/backup/all_databases.sql |
再从全库备份中抽取出student
表的内容
1 | # grep 'INSERT INTO `student`' /opt/backup/all_databases.sql |
然后分别将DDL
和DML
写入数据库中,接着再通过 binlog恢复到两个pos点之间的数据即可完成单个表的数据恢复