MySQL二进制日志—binlog


文章目录

  • MySQL二进制日志—binlog
  • 一、什么是二进制日志
  • 1.概念
  • 2.具体分析
  • 二、二进制日志的作用
  • 1.基于时间点的恢复原理
  • 三、二进制日志的模式以及相关参数
  • binlog的模式:statement、row、mixed
  • 参数1:log_bin
  • 参数2:sql_log_bin
  • 参数3:binlog_format
  • 参数4:max_binlog_size
  • 参数5:sync_binlog
  • 四、具体测试
  • 五、关于mysqlbinlog命令


一、什么是二进制日志

1.概念

  二进制日志被称为binlog,它会记录所有的修改数据库的语句或者有可能改变数据库的语句,但是像select,show等不会对数据库进行写操作的语句不会被记录。

2.具体分析

  二进制日志,内容是二进制的也就是说使用cat等命令是无法直接查看的,在二进制日志中有着“事件”,“位置”的概念的。
事件: events。在binlog中每一条记录都可以当作是一个“事件”,因为二进制日志记录的是对数据库的修改,也就是每有一次修改就有一个“事件”被记录在了二进制日志中。
位置: position。因为是二进制的文件,所以其内容可以当作是一个很长的序列。二进制日志从为空到记录事件,整个事件长度为10个字节,那么这个事件开始的位置就是1,结束的位置就是10。下一个事件开始的位置起始点就是11。这个在主从结构搭建中从定位主的日志起到关键作用。

二、二进制日志的作用

  使用二进制日志的主要目的是最大可能的恢复数据库。因为二进制日志包含备份后进行的所有更新,不记录没有修改任何数据的语句。同时二进制日志也被应用与主从复制结构。

1.基于时间点的恢复原理

  现在假设一个场景,每天凌晨2点开始备份数据库并且备份成功,在当天9点数据库崩溃,那么该如何恢复?我们可以利用2点的备份进行恢复,但是只能将数据库恢复到凌晨2点,那么2点到9点这部分数据就会丢失。这个时候就需要使用二进制日志。首先将数据库恢复到凌晨2点的状态,利用二进制日志将这期间的操作重做一次,那么就保证了数据的安全性不会丢失,这就是二进制日志的恢复作用。

三、二进制日志的模式以及相关参数

  根据上面所说的我们已经知道了binlog日志记录的是对数据库的所有操作。如果现在我们用自己的账户在对数据库进行操作其中使用了user()函数并且做了修改,binlog顺利记录但是只记录了user()这个语句并没有记录是哪个用户操作的,需要恢复时用的是其他用户恢复的,那么和user()相关的数据恢复完是和原来的数据不一致的,这种数据恢复就是失败的。所以为了确保数据恢复的准确性除了相应的SQL还需要记录对应的SQL到底修改了数据库中的哪些行以及如何修改,这样才能保证我们在进行恢复的时候数据的准确性。但是相应的这也带来了一个问题,如果这个更新语句是一个update并且是针对一个列做出的修改,假设被修改的表有10000行数据,那么我的binlog就需要把涉及修改的10000行数据都记录下来,这对资源是极大的占用,这种情况其实我只要记录一下这个SQL就可以没必要去记录所有涉及改动的数据。所以综合来看,这两种binlog的记录方式还是各有千秋都有自己的优势和劣势。对DBA而言,二进制日志的记录模式是完全可控的,只需要修改binlog的记录模式就可以实现。

binlog的模式:statement、row、mixed

  • statement:只记录对数据库做出修改的语句,例如上例所说的update语句,这时binlog会把更新的语句完整的记录下来。这种模式的优点就是需要记录的日志量很小,相应的对IO的压力也会小性能上也是最好的。缺点也是上面所说的,使用一些特定的函数可能会导致恢复出现问题。
  • row:记录对数据库做出修改的语句所影响到的数据行以及这些行的修改,还是上面update语句,除了记录语句本身,在row模式下还会把涉及修改的数据行数据和怎样被修改全部记录到binlog中。这种模式的优点就是可以完全的还原或者复制日志被记录时的操作,缺点是记录日志量较大,IO压力大,性能消耗较大。
  • mixed:混合使用上述两种模式,一般的语句使用statment方式进行保存,如果遇到一些特殊的函数,则使用row模式进行记录,这种记录方式被称之为mixed,看上去这种方式似乎比较完美,但是在生产环境中为了保险起见,一般会使用row模式。

修改binlog模式:
可以使用binlog_format变量设置二进制日志的记录方式,也可以在my.cnf配置文件中加入如下配置使其永久生效

[root@mysql8 mysql_3306]# vim my_3306.cnf
...
binlog_format = row
....

参数1:log_bin

  这个变量控制着数据库是否启动了二进制日志,并且这个变量只读。只读的意义在于这个变量无法在线通过set进行设置,只能通过修改参数文件来进行开启。需要注意的是这个变量不存在ON和OFF的值,只要它在配置文件中生效就说明已经开启了二进制日志,而它的值会变成数据文件目录下二进制日志文件名字的前缀。想要关闭二进制日志要么把这个变量在配置文件注释要么直接删除。开启后我们在配置文件中通过这个变量的值来设置日志文件的前缀而后缀会由数据库自动进行编号当这个日志文件慢了或者被切换这个值会自动加1。 需要重启数据库才会生效。

参数2:sql_log_bin

  首先这是一个会话级别的变量,所以配置文件中不能有这个。想要修改只能在线通过set修改并且不能使用set global,只在当前会话生效。这个变量主要是控制当前会话中的对数据库起到修改作用的SQL是否会被记录在binlog中。假设我的数据库已经开启了binlog,我连接上我的数据库并且在我的这个会话中把sql_log_bin这个变量设置为了OFF,那么我在这个会话中做的所有对数据库有修改的语句都不会被记录在binlog中。在主从同步的场景因为没有被记录在binlog所以这些操作也不会被同步到从节点上。

参数3:binlog_format

  这个变量在上文已经介绍的差不多了,决定了数据库binlog的模式,推荐生产环境使用row模式保证数据的安全性。

参数4:max_binlog_size

  设置单个二进制日志文件的大小,单位是字节,当日志文件的大小超过这个限制日志文件自动滚动并且后缀自动加1。

参数5:sync_binlog

  这个变量用来控制二进制日志同步。二进制日志是在内存中被记录的,这点和Oracle中的redo buffer cache一样存在缓存区,而二进制日志在内存中的binlog_cache中存放。如果将这个变量设置为1,那么每当一个事务被提交那么存放在内存中的binlog信息就会落盘到数据文件上。如果为0,那么这个落盘基于文件系统的缓存机制来确定。总得来说为0时性能最好但是安全性最差,一旦断电内存中的数据全部丢失。值为1性能最差但是安全性也是最好的。除此之外,这个值可以是其他数字如,2,3,4等意味着几次事务落一次盘。所以究竟使用几还需要视情况而定,性能影响也是很大的。

四、具体测试

  • 查询当前数据库是否开启二进制日志
mysql> show variables like '%log_bin'; #默认通常是不开启的
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
| sql_log_bin   | ON    |
+---------------+-------+
2 rows in set (0.00 sec)
  • 手动开启二进制日志
# 1.首先修改配置文件
[root@mysql8 mysql_3306]# pwd
/data/mysql/mysql_3306
[root@mysql8 mysql_3306]# vim my_3306.cnf 
...
log-bin = /data/mysql/mysql_3306/logs/mysql-bin #我这里填写的是mysql-bin作为前缀
...
# 2.重启数据库
[root@mysql8 mysql_3306]# systemctl start mysqld #我用的MySQL8自己配置的服务,启动方式可能不同,我在之前的文章中写过具体配置
[root@mysql8 logs]# pwd
/data/mysql/mysql_3306/logs
[root@mysql8 logs]# ls
error.log  mysql-bin.000001  mysql-bin.000002  mysql-bin.000003  mysql-bin.000004  mysql-bin.index  slow.log
  • 在MySQL中查看二进制日志的文件列表(两种方式均可,最后一列为是否加密,这应该是8的新特性)
mysql> show binary logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000001 |       178 | No        |
| mysql-bin.000002 |      2322 | No        |
| mysql-bin.000003 |      1851 | No        |
| mysql-bin.000004 |       195 | No        |
+------------------+-----------+-----------+
4 rows in set (0.00 sec)

mysql> show master logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000001 |       178 | No        |
| mysql-bin.000002 |      2322 | No        |
| mysql-bin.000003 |      1851 | No        |
| mysql-bin.000004 |       195 | No        |
+------------------+-----------+-----------+
4 rows in set (0.00 sec)
  • 查看当前数据库binlog的记录模式
mysql> show variables like '%binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.00 sec)
  • 接下来对数据库进行一些操作,看看日志文件大小是否会变化
mysql> select * from test;
+------+------+
| id   | name |
+------+------+
|    1 | zs   |
|    2 | ls   |
|    3 | zzl  |
+------+------+
3 rows in set (0.00 sec)

mysql> insert into test values (4,'zzzl');
Query OK, 1 row affected (0.00 sec)

mysql> show binary logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000001 |       178 | No        |
| mysql-bin.000002 |      2322 | No        |
| mysql-bin.000003 |      1851 | No        |
| mysql-bin.000004 |       483 | No        | #和上面相比这个是变大的
+------------------+-----------+-----------+
4 rows in set (0.00 sec)
# 做一次查询
mysql> select * from test;
+------+------+
| id   | name |
+------+------+
|    1 | zs   |
|    2 | ls   |
|    3 | zzl  |
|    4 | zzzl |
+------+------+
4 rows in set (0.00 sec)

mysql> show binary logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000001 |       178 | No        |
| mysql-bin.000002 |      2322 | No        |
| mysql-bin.000003 |      1851 | No        |
| mysql-bin.000004 |       483 | No        | #说明查询并不会被二进制日志记录下来
+------------------+-----------+-----------+
4 rows in set (0.00 sec)
  • 查看二进制日志记录的内容
#接着上面的操作继续就可以,可以看到483位置结束其上面就是所做的操作。
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    |      3306 |         124 | Server ver: 8.0.15, Binlog ver: 4                                  |
| mysql-bin.000004 | 124 | Previous_gtids |      3306 |         195 | 32415cb9-d5ff-11ea-a561-000c29135205:1-14                          |
| mysql-bin.000004 | 195 | Gtid           |      3306 |         274 | SET @@SESSION.GTID_NEXT= '32415cb9-d5ff-11ea-a561-000c29135205:15' |
| mysql-bin.000004 | 274 | Query          |      3306 |         349 | BEGIN                                                              |
| mysql-bin.000004 | 349 | Table_map      |      3306 |         407 | table_id: 69 (test.test)                                           |
| mysql-bin.000004 | 407 | Write_rows     |      3306 |         452 | table_id: 69 flags: STMT_END_F                                     |
| mysql-bin.000004 | 452 | Xid            |      3306 |         483 | COMMIT /* xid=24 */                                                |
+------------------+-----+----------------+----------- +-------------+--------------------------------------------------------------------+
7 rows in set (0.00 sec)
  • 查看当前使用哪个二进制日志以及所处的位置点以及如何刷新
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                         |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000004 |      770 |              |                  | 32415cb9-d5ff-11ea-a561-000c29135205:1-16 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
# 刷新二进制日志,会把内存中的信息落盘并切换日志
mysql> flush logs;
Query OK, 0 rows affected (0.00 sec)

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                         |
+------------------+----------+--------------+------------------+-------------------------------------------+
| mysql-bin.000005 |      195 |              |                  | 32415cb9-d5ff-11ea-a561-000c29135205:1-16 |
+------------------+----------+--------------+------------------+-------------------------------------------+
1 row in set (0.00 sec)
  • 开始测试时指定的二进制日志存放位置,在其路径下mysql-bin.index的作用
[root@mysql8 logs]# ls
error.log  mysql-bin.000001  mysql-bin.000002  mysql-bin.000003  mysql-bin.000004  mysql-bin.000005  mysql-bin.index  slow.log
[root@mysql8 logs]# cat mysql-bin.index #就是单纯的记录了有哪些二进制日志文件
/data/mysql/mysql_3306/logs/mysql-bin.000001
/data/mysql/mysql_3306/logs/mysql-bin.000002
/data/mysql/mysql_3306/logs/mysql-bin.000003
/data/mysql/mysql_3306/logs/mysql-bin.000004
/data/mysql/mysql_3306/logs/mysql-bin.000005

五、关于mysqlbinlog命令

  这个命令主要就是为了我们可以在文件系统层面查看对应的二进制日志

# 查看全部
[root@mysql8 logs]# mysqlbinlog mysql-bin.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#200804 11:04:22 server id 3306  end_log_pos 124 CRC32 0x8d4aeafb       Start: binlog v 4, server v 8.0.15 created 200804 11:04:22 at startup
ROLLBACK/*!*/;
BINLOG '
NtAoXw/qDAAAeAAAAHwAAAAAAAQAOC4wLjE1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA20ChfEwANAAgAAAAABAAEAAAAYAAEGggAAAAICAgCAAAACgoKKioAEjQA
CgH76kqN
'/*!*/;
# at 124
#200804 11:04:22 server id 3306  end_log_pos 155 CRC32 0x13706bcc       Previous-GTIDs
# [empty]
# at 155
#200804 11:04:24 server id 3306  end_log_pos 178 CRC32 0x9604c00a       Stop
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*/;

# 查看指定位置点
[root@mysql8 logs]# mysqlbinlog --start-position 317 --stop-position 100 mysql-bin.000001 
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
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*/;

# 查看指定时间
[root@mysql8 logs]# mysqlbinlog --start-datetime "2020-08-05 15:08:00"  --stop-datetime "2020-08-05 15:13:00" mysql-bin.000004
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#200805 11:29:42 server id 3306  end_log_pos 124 CRC32 0xc90b4f28       Start: binlog v 4, server v 8.0.15 created 200805 11:29:42 at startup
ROLLBACK/*!*/;
BINLOG '
picqXw/qDAAAeAAAAHwAAAAAAAQAOC4wLjE1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACmJypfEwANAAgAAAAABAAEAAAAYAAEGggAAAAICAgCAAAACgoKKioAEjQA
CgEoTwvJ
'/*!*/;
# at 770
#200805 15:08:17 server id 3306  end_log_pos 817 CRC32 0x16e772f3       Rotate to mysql-bin.000005  pos: 4
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*/;