MySQL的二进制日志(binlog)

MySQL binary log

Posted by alovn on October 13, 2021

简介

MySQL的二进制日志(binary log)记录了对数据库执行更改的所有操作,但是不包括SELECT和SHOW这些查询的操作,因为它们没有对数据本身修改。若执行更新的SQL并没有使数据产生变化,那么这个执行更新的SQL也会被写入二进制日志。例如:

1
2
mysql> update t_user set age=18 where user_id=1; # 原本age=18,数据无变化
Query OK, 0 rows affected

如果想要记录SELECT和SHOW的查询记录,那么需要查询日志,而不是二进制日志。

作用

二进制日志(binlog)的作用:

  • 恢复:某些数据的恢复需要二进制日志。例如数据库全备文件恢复后,可以通过binlog进行point-in-time的恢复。
  • 复制:通过复制和执行binlog使另一台MySQL进行实时同步,一般称为slave。
  • 审计:可以通过binlog日志中的信息进行审计,判断是否有对数据进行注入攻击等。

启用

二进制日志文件默认没有启动,需要配置参数来启动。启用这个选项对数据库性能会有性能影响,不过性能损失十分有限。MySQL官方手册中表名,启用二进制日志会使性能下降大约1%。但是考虑到可以使用复制(replication)和point-in-time恢复,这些性能损失是可以被接受的。

可以先查询下是否启用了binlog:

1
2
3
4
5
6
7
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | OFF   |
+---------------+-------+
1 row in set

如果没有则通过配置文件参数 log-bin=[fiel-name] 启动二进制日志。若MySQL版本是5.7及以上的话,还需要指定另外一个参数server-id,注意不能与集群中其它MySQL配置重复。

1
log-bin=/var/lib/mysql/mysql-bin

然后可以通过以下命令查看日志:

1
mysql> show binlog events in 'mysql-bin.000001';

影响参数

max_binlog_size

max_binlog_size: 指定单个二进制文件的最大值。若超出该值,则会产生新的二进制文件,后缀名+1,并记录到.index文件中。默认值为 1073741824,代表1G。

binlog_cache_size

binlog_cache_size: 当使用事务的表引擎时(如InnoDB),所有未提交的二进制日志会记录到缓存中去,等到事务提交时直接将缓冲中的二进制日志写入二进制日志文件中,binlog_cache_size就是该缓冲的大小,默认值为32768,代表32KB。该参数是基于会话(session)的,也就是说,当一个线程开始一个事务时,MySQL会自动分配一个binlog_cache_size大小的缓存。

sync_binlog

sync_binlog: 默认情况下,二进制日志并不是每次写的时候同步到磁盘。所以当系统宕机时,可能会有最后一部分数据没有写入二进制文件中,这会给复制和恢复带来问题。sync_binlog=N表示每写缓冲多少次就同步到磁盘。如果设置为1,就表示采用同步写磁盘的方式(不使用缓冲)。即使这样还是可能会导致问题发生,事务没有完全写入日志就宕机了,那么下次MySQL启动时,由于Commit操作没有发生,这个事务会被回滚掉。但是二进制日志已经记录了该事务信息,不能被回滚。这个问题可以通过参数innodb_support_xa设置为1来解决。

binlog-do-db

binlog-do-db: 写入哪些库的日志,默认空,表示同步所有库的日志到二进制日志中。

binlog-ignore-db

binlog-ignore-db: 忽略哪些库的日志。

binlog-format

binlog-format: 记录二进制的日志格式,这个参数很重要。可设置的值有STATEMENT、ROW和MIXED。默认为STATEMENT。

  1. STATEMENT 语句级,二进制日志文件记录是原始逻辑SQL语句。它是会有一些问题产生的,如在主服务器上运行rand、uuid等函数时,又或者使用触发器时,这些操作可能会导致主从服务器上的数据不一致。

  2. ROW 行级,在ROW格式下,二进制日志记录不再是简单的SQL语句了,而是记录行更改的信息。对STATEMENT格式下复制的问题予以解决。

  3. MIXED 混合级,前两种模式的混合结合。MySQL默认采用STATEMENT格式进行二进制日志文件的记录,但是在一些情况下会使用ROW格式。MySQL会根据实际情况选择使用哪种模式。

在通常情况下,我们将参数binlog_format设置为ROW,这可以为数据库的恢复和复制带来更好的可靠性。但是不能忽略的是,这样会使二进制文件的大小增加。如执行批量更新的SQL语句。

1
2
mysql> show variables like 'binlog_format';
mysql> set global binlog_format='ROW';

查看日志

查看二进制日志文件的内容,需要通过MySQL提供的工具mysqlbinlog。对于STATEMENT格式的二进制日志文件,在使用mysqlbinlog后,看到的就是执行的逻辑SQL语句。

1
[root@mysql]# mysqlbinlog --no-defaults --start-position=1 mysql-bin.000001

如果是ROW格式的二进制日志,就看不到执行的SQl了,这时需要加上参数-v或-vv就可以看到执行的具体信息了。-vv比-v会多显示处更新的类型。

1
[root@mysql]# mysqlbinlog --no-defaults -vv --start-position=1 mysql-bin.000001