导游

  • 概述
  • 优缺
  • 开启binlog日志
  • 查看&删除二进制日志
  • 查看binlog日志文件内容
  • mysqlbinlog命令
  • 二进制日志恢复数据


概述

MySQL二进制日志(Binary Log,简称binlog)记录着数据库中所有更新数据的SQL语句,也就是数据库的增,删,改操作语句,将其写入到二进制日志中,以时间的形式保存。

优缺

优点:

  1. 恢复数据库
  2. 可用于MySQL数据库的主从架构

缺点:

  1. 消耗一部分性能
  2. 花费时间维护二进制日志

开启binlog日志

注:案例中MySQL版本为8.0.13

mysql --version
mysql  Ver 8.0.13 for Linux on x86_64 (Source distribution)

查看二进制日志是否开启

mysql> show variables like 'log_bin%';
+---------------------------------+-------------------------------+
| Variable_name                   | Value                         |
+---------------------------------+-------------------------------+
| log_bin                         | ON                            |
| log_bin_basename                | /data/mysql/data/binlog       |
| log_bin_index                   | /data/mysql/data/binlog.index |
| log_bin_trust_function_creators | OFF                           |
| log_bin_use_v1_row_events       | OFF                           |
+---------------------------------+-------------------------------+

log_bin为OFF表示binlog日志没有开启。

开启二进制日志
MySQL二进制日志默认是关闭的,可以通过编辑/etc/my.cnf配置文件

server-id=1
log-bin=/data/mysql/log/mysql-bin
expire_logs_days = 30
max_binlog_size = 200M

配置项说明:
sever-id:设置MySQL数据库id,MySQL5.7及以上版本需加
log-bin:binlog日志存放路径
expire_logs_days:binlog日志的保存时间,超过将会自动删除
max_binlog_size:binlog日志文件大小,根据环境而定

添加完成后,重启MySQL,首先确认有没有创建二进制日志文件

查看binlog文件

ls /data/mysql/log/
mysql-bin.000001  mysql-bin.index  mysqld.log

其中mysql-bin.000001 就是binlog文件,而mysql-bin.index的功能是记录所有Binary Log的绝对路径,保证MySQL各种线程能够顺利的根据他找到所有需要的Binary Log文件。

cat /data/mysql/log/mysql-bin.index 
/data/mysql/log/mysql-bin.000001

查看binlog是否开启

mysql> show variables like 'log_bin%';
+---------------------------------+---------------------------------+
| Variable_name                   | Value                           |
+---------------------------------+---------------------------------+
| log_bin                         | ON                              |
| log_bin_basename                | /data/mysql/log/mysql-bin       |
| log_bin_index                   | /data/mysql/log/mysql-bin.index |
| log_bin_trust_function_creators | OFF                             |
| log_bin_use_v1_row_events       | OFF                             |
+---------------------------------+---------------------------------+

其中log_bin为NO,表示二进制日志已经开启了。

除以上配置项外,binlog还有其他一些附加的选项参数:

max_binlog_size:设置binlog的最大存储上限,一般设置为512M或者1G,一般不能超过1G。当日志达到该上限时,MySQL 会重新创建一个日志开始继续记录。不过偶尔也有超出该设置的binlog 产生,一般都是因为在即将达到上限时,产生了一个较大的事务,为了保证事务安全,MySQL 不会将同一个事务分开记录到两个binlog 中。

注:已在my.cnf文件中设置为200MB

mysql> show variables like '%max_binlog_size%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| max_binlog_size | 209715200 |
+-----------------+-----------+

binlog_cache_size:一个事务在没有提交之前,产生的日志记录到cache中,等到事务提交的时候,则把日志持久化到磁盘。一般来说,如果我们的数据库中没有什么大事务,写入也不是特点频繁,2MB~4MB是个合适的选择。但是如果我们的数据库大事务较多,写入量比较大,可与适当调高binlog_cache_size,默认值32768。

mysql> show variables like 'binlog_cache_size%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| binlog_cache_size | 32768 |
+-------------------+-------+

binlog_format:二进制日志类型,共三种,分别是:STATEMENT,ROW,MIXED。

mysql> show variables like '%binlog_f%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+

查看&删除二进制日志

查看binlog日志

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       155 |
+------------------+-----------+

查看binlog日志内容

mysql> show binlog events in 'mysql-bin.000001';
+------------------+-----+----------------+-----------+-------------+-----------------------------------+
| Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                              |
+------------------+-----+----------------+-----------+-------------+-----------------------------------+
| mysql-bin.000001 |   4 | Format_desc    |         1 |         124 | Server ver: 8.0.13, Binlog ver: 4 |
| mysql-bin.000001 | 124 | Previous_gtids |         1 |         155 |                                   |
+------------------+-----+----------------+-----------+-------------+-----------------------------------+

查看master日志状态

注:MySQL开启主从复制时使用

mysql> show master status\G
*************************** 1. row ***************************
             File: mysql-bin.000001
         Position: 155
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set:

刷新binlog日志

注:刷新完成后,会自动创建一个新的二进制日志,是在当前二进制日志名称后基础上+1,例如,mysql-bin.000001刷新完成后名称为mysql-bin.000002,之后的数据更新的SQL语句将存放在mysql-bin.000002中。

mysql> flush logs;
mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       202 |
| mysql-bin.000002 |       155 |
+------------------+-----------+

清空binlog日志

注:其实过程是将之前的二进制日志删除,然后重新创建一个二进制日志,用于存放数据更新的SQL语句。

mysql> reset master;
mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       155 |
+------------------+-----------+

查看binlog日志文件内容

二进制日志为二进制格式存储,使用此格式可以存储更多的信息,并且可以使用写入二进制日志的效率更高。但缺点是无法直接linux命令(如cat,less等)查看二进制日志。

例如:

cat /data/mysql/log/mysql-bin.000001                                
`þbinVԡ^x|8.0.13Vԡ^               
**4

mysqlbinlog命令

想要查看二进制日志文件中具体的内容,还得借助MySQL组件中的mysqlbinlog这个工具。

语法格式:mysqlbinlog 参数 文件路径

具体参数可以通过- -help来自行查看,若是查看文件内容,只需要加上-v参数即可。

进入mysql数据库,执行一些SQL语句,并查看二进制日志内容。

create database test;
use test;
create table binlog(id int,name varchar(11));
insert into binlog values(1,'测试');

查看二进制日志内容

mysqlbinlog -v /data/mysql/log/mysql-bin.000001 
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#200611 15:02:53 server id 1  end_log_pos 124 CRC32 0xb8a56743 	Start: binlog v 4, server v 8.0.13 created 200611 15:02:53 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
BINLOG '
HdfhXg8BAAAAeAAAAHwAAAABAAQAOC4wLjEzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAd1+FeEwANAAgAAAAABAAEAAAAYAAEGggAAAAICAgCAAAACgoKKioAEjQA
CgFDZ6W4
'/*!*/;
# at 124
#200611 15:02:53 server id 1  end_log_pos 155 CRC32 0xa2e2079b 	Previous-GTIDs
# [empty]
# at 155
#200611 15:03:11 server id 1  end_log_pos 228 CRC32 0x553603b4 	Anonymous_GTID	last_committed=0	sequence_number=1	rbr_only=no	original_committed_timestamp=1591858992368103	immediate_commit_timestamp=1591858992368103	transaction_length=181
# original_commit_timestamp=1591858992368103 (2020-06-11 15:03:12.368103 CST)
# immediate_commit_timestamp=1591858992368103 (2020-06-11 15:03:12.368103 CST)
/*!80001 SET @@session.original_commit_timestamp=1591858992368103*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 228
#200611 15:03:11 server id 1  end_log_pos 336 CRC32 0xa17df524 	Query	thread_id=10	exec_time=1	error_code=0	Xid = 45
SET TIMESTAMP=1591858991/*!*/;
SET @@session.pseudo_thread_id=10/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1168113696/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=45,@@session.collation_connection=45,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
/*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/;
/*!80013 SET @@session.sql_require_primary_key=0*//*!*/;
create database test
/*!*/;
# at 336
#200611 15:03:38 server id 1  end_log_pos 409 CRC32 0xad6609b8 	Anonymous_GTID	last_committed=1	sequence_number=2	rbr_only=no	original_committed_timestamp=1591859018545646	immediate_commit_timestamp=1591859018545646	transaction_length=205
# original_commit_timestamp=1591859018545646 (2020-06-11 15:03:38.545646 CST)
# immediate_commit_timestamp=1591859018545646 (2020-06-11 15:03:38.545646 CST)
/*!80001 SET @@session.original_commit_timestamp=1591859018545646*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 409
#200611 15:03:38 server id 1  end_log_pos 541 CRC32 0x0bbfaccc 	Query	thread_id=10	exec_time=0	error_code=0	Xid = 50
use `test`/*!*/;
SET TIMESTAMP=1591859018/*!*/;
/*!80013 SET @@session.sql_require_primary_key=0*//*!*/;
create table binlog(id int,name varchar(11))
/*!*/;
# at 541
#200611 15:03:54 server id 1  end_log_pos 616 CRC32 0xd6ca34b1 	Anonymous_GTID	last_committed=2	sequence_number=3	rbr_only=yes	original_committed_timestamp=1591859034487911	immediate_commit_timestamp=1591859034487911	transaction_length=288
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
# original_commit_timestamp=1591859034487911 (2020-06-11 15:03:54.487911 CST)
# immediate_commit_timestamp=1591859034487911 (2020-06-11 15:03:54.487911 CST)
/*!80001 SET @@session.original_commit_timestamp=1591859034487911*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 616
#200611 15:03:54 server id 1  end_log_pos 693 CRC32 0xa6d0298b 	Query	thread_id=10	exec_time=0	error_code=0
SET TIMESTAMP=1591859034/*!*/;
/*!80013 SET @@session.sql_require_primary_key=0*//*!*/;
BEGIN
/*!*/;
# at 693
#200611 15:03:54 server id 1  end_log_pos 751 CRC32 0x388491fc 	Table_map: `test`.`binlog` mapped to number 88
# at 751
#200611 15:03:54 server id 1  end_log_pos 798 CRC32 0xf79be854 	Write_rows: table id 88 flags: STMT_END_F

BINLOG '
WtfhXhMBAAAAOgAAAO8CAAAAAFgAAAAAAAEABHRlc3QABmJpbmxvZwACAw8CIQADAQEAAgEh/JGE
OA==
WtfhXh4BAAAALwAAAB4DAAAAAFgAAAAAAAEAAgAC/wABAAAABua1i+ivlVTom/c=
'/*!*/;
### INSERT INTO `test`.`binlog`
### SET
###   @1=1
###   @2='测试'
# at 798
#200611 15:03:54 server id 1  end_log_pos 829 CRC32 0x41beb43c 	Xid = 51
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

在二进制日志记录中,有两种查看的方式:

1)第一种是基于时间查看,每条保存的SQL语句都有唯一的时间保存。
2)第二种是基于所在位置,每条保存的SQL语句再前面都有一个at并用唯一id标记。

例如以上例子中,at228 下就是创建test数据库的SQL语句,插入的第一条记录则在at751后。

二进制日志恢复数据

查看的方式有两种,恢复的方式也有两种,基于时间点恢复,基于位置恢复。个人比较喜欢基于位置恢复。

首先,删除创建的test数据库,模拟数据丢失。

mysql> drop database test;

刷新一个新的二进制日志

mysql> flush logs;

之前查看二进制日志可以知道,at228-at751是全部的测试语句,之后就是其他SQL语句及误操作的删除语句。

基于位置恢复:
–start-position 从二进制日志中读取指定position 事件位置作为开始。

–stop-position 从二进制日志中读取指定position 事件位置作为结束。

注:将其理解为从at哪里开始,到at哪里结束即可

拿此案例为例,恢复语句为

mysqlbinlog --start-position="228" --stop-position="798" /data/mysql/log/mysql-bin.000001 | mysql -uroot

可以发现–stop-position=“798” ,而不是751,这是因为结束机制的问题,不会执行指定结束位置的SQL语句,所以结束位置要稍大于原位置。

再次进入数据库,查看是否恢复

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+