MySQL(十) Binlog二进制日志恢复数据

MySQL Binlog二进制日志恢复数据

二进制日志配置管理

二进制日志:(逻辑层)
# 二进制日志到底记录了什么?
    已提交的数据记录,以event(事件)的形式记录到二进制文件中,所有的DDL、DCL、DML(insert、update、delete)

# 二进制日志记录格式有哪些?
    statement:  语句模式(就是记录执行的SQL语句),DDL、DCL只能以语句模式记录。
    row:        数据行模式(就是数据行的变化过程),只针对DML语句有效。
    mixed:      以上两者的混合模式

# binlog的作用?
    备份恢复,数据复制
    只要有全量的binlog文件,可以将数据库恢复到任意时间点

# row与statement优缺点?
    1、语句模式在批量操作时,日志量更少
    2、row模式记录数据更加严谨
    3、mixed不用
查看默认日志格式:
#5.7版本默认以ROW数据行格式记录
mysql> show variables like '%format%';
+---------------------------+-------------------+
| Variable_name             | Value             |
+---------------------------+-------------------+
| binlog_format             | ROW               |
| date_format               | %Y-%m-%d          |
| datetime_format           | %Y-%m-%d %H:%i:%s |
| default_week_format       | 0                 |
| innodb_default_row_format | dynamic           |
| innodb_file_format        | Barracuda         |
| innodb_file_format_check  | ON                |
| innodb_file_format_max    | Barracuda         |
| time_format               | %H:%i:%s          |
+---------------------------+-------------------+

img

重点:
二进制日志` 与 `慢日志
配置错误日志:
#配置文件内指定错误日志存放路径(默认存放在数据路径下)
log_error=/var/log/mysql.log
日志配置参数:(骚操作)
  • log-bin=[base_name]:该参数表示是否开启binary log。默认情况下MySQL会使用host_name-bin.xxxx作为文件的名字,其中xxxx是以数字递增的后缀。如果该参数指定了 base_name,则二进制文件会以base_name.xxxx来命名。
  • binlog-do-db=db_name: 该参数决定了哪些库下的修改会被记录到bin log中其行为与replicate-do-db类型,在基于SQL语句复制的环境下,只记录在当前数据库下的修改。
  • binlog-ignore-db=db_name:该参数决定了在bin log中忽略的数据库,其行为与 replicate-ignore-db类型。
开启MySQL二进制日志:
mkdir /usr/local/mysql/blog/ && chown mysql.mysql /usr/local/mysql/blog/
#通过配置文件开启binlog,并指定以row类型记录,启动binlog功能就要加入server_id,这是5.7版本的bug。(mysql-bin是日志的前缀名)
vim /usr/local/mysql/conf/my.cnf

log_bin=/usr/local/mysql/blog/mysql-bin        指定binlog日志存放路径及文件名前缀
binlog_format=row                              指定以row类型记录
sync_binlog=1                                  每次commit时都会刷新日志到磁盘
server_id=1
systemctl restart mysqld
binlog查询:
#前154个位置是二进制文件默认大小
#查询二进制存放的位置,或者通过配置文件查看
mysql> show variables like 'log_bin%';
+---------------------------------+-----------------------------------------+
| Variable_name                   | Value                                   |
+---------------------------------+-----------------------------------------+
| log_bin                         | ON                                      |
| log_bin_basename                | /usr/local/mysql/binlog/mysql-bin       |
| log_bin_index                   | /usr/local/mysql/binlog/mysql-bin.index |
| log_bin_trust_function_creators | OFF                                     |
| log_bin_use_v1_row_events       | OFF                                     |
+---------------------------------+-----------------------------------------+
查看使用的binlog文件:
#可以刷新二进制文件,类似于nginx日志的切割
flush logs;
#这个命令可以看到一共有多少二进制日志文件
mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       201 |
| mysql-bin.000002 |       154 |
+------------------+-----------+
#这个命令可以看到二进制日志文件,并且可显示正在写入的二进制文件
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000002 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
events二进制日志事件:
对于DDL\DCL来讲,一条语句就是一个事件
对于DML来讲,是一个事务有多个事件,一个事务中有多个语句

每一个event,都有一个开始位置(position),结束位置(position)
查看binlog的事件信息:
#可以看到有两个事件
mysql> show binlog events in 'mysql-bin.000002';
+------------------+-----+----------------+-----------+-------------+---------------------------------------+
| Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                                  |
+------------------+-----+----------------+-----------+-------------+---------------------------------------+
| mysql-bin.000002 |   4 | Format_desc    |         0 |         123 | Server ver: 5.7.22-log, Binlog ver: 4 |
| mysql-bin.000002 | 123 | Previous_gtids |         0 |         154 |                                       |
+------------------+-----+----------------+-----------+-------------+---------------------------------------+
测试binlog记录:
#创建一个good的库并创建一张表,然后查询二进制文件,查询类语句不会记录
mysql> create database good charset utf8;
mysql> use good;
mysql> create table t1 (id int)engine=innodb;

#然后查看二进制文件内容,发现多出来四条新记录,记录的第二条与第四条操作的是语句
mysql> show binlog events in 'mysql-bin.000002';
+------------------+-----+----------------+-----------+-------------+---------------------------------------------------+
| Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                                              |
+------------------+-----+----------------+-----------+-------------+---------------------------------------------------+
| mysql-bin.000002 |   4 | Format_desc    |         0 |         123 | Server ver: 5.7.22-log, Binlog ver: 4             |
| mysql-bin.000002 | 123 | Previous_gtids |         0 |         154 |                                                   |
| mysql-bin.000002 | 154 | Anonymous_Gtid |         0 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'              |
| mysql-bin.000002 | 219 | Query          |         0 |         326 | create database good charset utf8                 |
| mysql-bin.000002 | 326 | Anonymous_Gtid |         0 |         391 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'              |
| mysql-bin.000002 | 391 | Query          |         0 |         502 | use `good`; create table t1 (id int)engine=innodb |
+------------------+-----+----------------+-----------+-------------+---------------------------------------------------+
查看文件最大自动滚动大小值:
##### mysql> show variables like 'max_binlog_size';
+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| max_binlog_size | 1073741824 |
+-----------------+------------+
binlog什么时候会滚动出一个新文件?
#刷新会自动滚动出新文件
flush logs;

#重启MySQL时会自动滚动新文件
systemctl restart mysqld

#达到max_binlog_size伐值时,会自动生成新文件
mysql> show variables like '%%max_binlog_size';
+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| max_binlog_size | 1073741824 |
+-----------------+------------+
1 row in set (0.01 sec)

#备份时,加入-F会自动滚动新文件
binlog文件保存的时间?
# 默认保留 30天的binlog日志文件
mysql> show variables like '%binlog_ex%';
+----------------------------+---------+
| Variable_name              | Value   |
+----------------------------+---------+
| binlog_expire_logs_seconds | 2592000 |
+----------------------------+---------+
1 row in set (0.00 sec)
清空所有binlog文件:
#清空所有binlog文件,从000001开始重新记录,一般是在全量备份之后可以执行
reset master;
根据名称清理binlog文件:
  • 可以在 master中执行这条指令 , 将 binlog 文件删除至 mysql-bin.000009 前
purge master logs to 'mysql-bin.000009';
根据时间清理binlog文件:
  • 将 binlog文件删除至此日期前
purge master logs before '2014-11-18 00:00:00';
查看binlog详细内容:
#这是mysql的命令,不是SQL语句,后面跟上那个文件就看那个文件的详细内容
mysqlbinlog /usr/local/mysql/binlog/mysql-bin.000002

#常用参数使用(类似于以人类可读形式显示)
mysqlbinlog --base64-output=decode-rows -vvv /usr/local/mysql/binlog/mysql-bin.000002

#指定查看olda库详细的binlog日志语句
mysqlbinlog --base64-output=decode-rows -vvv -d olda /usr/local/mysql/binlog/mysql-bin.000003
查看relay-log详细内容:
mysqlbinlog -vvv /usr/local/mysql-8.0.16/data/olda-study0-relay-bin.000002 

基于时间点恢复数据

Binlog时间恢复:
  • 根据dump全量备份全量和二进制日志增量恢复数据到指定时间点。
  • 模拟每天晚上的12点整进行mysqldump全量备份
  • 在第二天早上 9点出现数据故障,需要基于全量备份恢复 12点到 9点的数据
  • 当前为普通模式,没有开启GTID模式,否则恢复无效?暂定疑问???
模拟前天数据:
mysql> create database course charset utf8mb4;
Query OK, 1 row affected (0.01 sec)

mysql> use course
Database changed
mysql> create table temp(id int,name varchar(64));
Query OK, 0 rows affected (0.03 sec)

mysql> insert into temp values(1,'a'),(2,'b');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0
数据库全量备份:
  • 当前时间为晚上12点整,进行了数据库全量备份。
[root@db01 ~]# mysqldump -uroot -p123456 -B course -R --triggers --master-data=2 --single-transaction > /tmp/full.sql
模拟数据变化:
  • 当前是前天晚上12点整 - 今天早上9点的数据变化。
mysql> insert into temp values(3,'a'),(4,'b');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> update temp set name='cc' where id=3;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from temp;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | cc   |
|    4 | b    |
+------+------+
4 rows in set (0.01 sec)
模拟删除course库:
  • 早上9点时误操作删除了course数据库
mysql> drop database course;
Query OK, 1 row affected (0.03 sec)

全量恢复:
mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)

mysql> source /tmp/full.sql

mysql> use course
Database changed

mysql> select * from temp;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
+------+------+
2 rows in set (0.00 sec)
增量恢复
  • 利用二进制日志恢复数据到早上9点的状态
  • 在截断日志时要把最后一个事务的commit操作也包含进去,不然数据恢复失败。
[root@db01 data]# mysqlbinlog -v --start-datetime="2019-11-05 00:00:00" --stop-datetime="2019-11-05 09:00:00" binlog.000001  | mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.

mysql> select * from temp;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | cc   |
|    4 | b    |
+------+------+
4 rows in set (0.00 sec)

重要(部分恢复):
如果一个生产库中的某一个表损坏了,那就截取对应库的binlog日志,然后在一个新数据库实例中恢复整个库,最后把损坏的表导出,然后再导入到生产库
#导出db库中的t1表
mysqldump -uroot -predhat db t1 >/tmp/t1.sql

删除binlog:
reset master
清空所有binlog,从000001开始重新记录,一般是在全备份之后可以执行。
(2)过期时间设置
SET GLOBAL expire logs days =7;
注意:这个时间设置,要考虑,全备的周期。
(3)删除到几天之前
PURGE BINARY LOGS BEFORE now()-INTERVAL 3 day;
(4)根据文件名删除日志:
PURGE BINARY LOGS TO 'mysql-bin.000010;

基于position位置点恢复数据

模拟数据及删除:
刷新日志:
flush logs;
创建一个db的库:
create database db charset utf8;
创建一张表:
use db;
create table t1(id int) engine=innodb;
插入3条数据:
insert into t1 values(1);
insert into t1 values(2);
insert into t1 values(3);
提交数据:
commit;
删除db库:
drop database db;

恢复数据:

需求:恢复到drop database db之前

截取binlog日志:
根据创建语句的起始位到提交的结束位进行binlog日志截取。
#经过分析后,从创建db库到删除db库之前是219~907日志位置

mysql> show binlog events in 'mysql-bin.000004';
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------+
| Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                                            |
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------+
| mysql-bin.000004 |   4 | Format_desc    |         0 |         123 | Server ver: 5.7.22-log, Binlog ver: 4           |
| mysql-bin.000004 | 123 | Previous_gtids |         0 |         154 |                                                 |
| mysql-bin.000004 | 154 | Anonymous_Gtid |         0 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'            |
| mysql-bin.000004 | 219 | Query          |         0 |         320 | create database db charset utf8                 |
| mysql-bin.000004 | 320 | Anonymous_Gtid |         0 |         385 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'            |
| mysql-bin.000004 | 385 | Query          |         0 |         492 | use `db`; create table t1(id int) engine=innodb |
| mysql-bin.000004 | 492 | Anonymous_Gtid |         0 |         557 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'            |
| mysql-bin.000004 | 557 | Query          |         0 |         627 | BEGIN                                           |
| mysql-bin.000004 | 627 | Table_map      |         0 |         670 | table_id: 105 (db.t1)                           |
| mysql-bin.000004 | 670 | Write_rows     |         0 |         710 | table_id: 105 flags: STMT_END_F                 |
| mysql-bin.000004 | 710 | Table_map      |         0 |         753 | table_id: 105 (db.t1)                           |
| mysql-bin.000004 | 753 | Write_rows     |         0 |         793 | table_id: 105 flags: STMT_END_F                 |
| mysql-bin.000004 | 793 | Table_map      |         0 |         836 | table_id: 105 (db.t1)                           |
| mysql-bin.000004 | 836 | Write_rows     |         0 |         876 | table_id: 105 flags: STMT_END_F                 |
| mysql-bin.000004 | 876 | Xid            |         0 |         907 | COMMIT /* xid=16 */                             |
| mysql-bin.000004 | 907 | Anonymous_Gtid |         0 |         972 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'            |
| mysql-bin.000004 | 972 | Query          |         0 |        1058 | drop database db                                |
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------+
截取之前数据日志:(Postion恢复)
#指定导出db库被截取的binglog日志信息
mysqlbinlog -d db --start-position=219 --stop-position=907 /usr/local/mysql/binlog/mysql-bin.000004 > /tmp/recover.sql
临时关闭记录binlog:
  • (恢复时不建议记录binlog)
#恢复时也是产生SQL语句,这个时候不建议恢复语句也被记录到binlog日志中,不方便以后分析起始与结束
mysql> set sql_log_bin=0;
恢复db数据库:
mysql> source /tmp/recover.sql
查看是否恢复:
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db                 |
| good               |
| mysql              |
| olda               |
| performance_schema |
| sys                |
| world              |
+--------------------+
mysql> use db;
Database changed
mysql> select * from t1;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+

重要(部分恢复):
如果一个生产库中的某一个表损坏了,那就截取对应库的binlog日志,然后在一个新数据库实例中恢复整个库,最后把损坏的表导出,然后再导入到生产库
#导出db库中的t1表
mysqldump -uroot -predhat db t1 >/tmp/t1.sql

删除binlog:
reset master
清空所有bin1og,从000001开始重新记录,一般是在全备份之后可以执行。
(2)过期时间设置
SET GLOBAL expire logs days =7;
注意:这个时间设置,要考虑,全备的周期。
(3)删除到几天之前
PURGE BINARY LOGS BEFORE now()-INTERVAL 3 day;
(4)根据文件名删除日志:
PURGE BINARY LOGS TO 'mysql-bin.000010;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在输入中…………

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值