MySQL二进制日志(Binary log)

  • 错误日志(Error log):记录启动、运行或停止mysqld遇到的问题;
  • 通用查询日志(General query log):记录服务器接收到的每一个命令,包括客户端连接以及sql执行记录等;
  • 二进制日志(Binary log):记录引起或可能引起数据更改的SQL,用于数据还原以及主从复制;
  • 中继日志(Relay log):从复制源服务器收到的数据更改日志;
  • 慢查询日志(Slow query log):执行时间超过long_query_time和没有使用索引的sql,用来发现并调优一些慢sql;
  • DDL日志(DDL log (metadata log)):DDL语句执行的元数据操作。

  二进制日志包含描述所有的数据库更改(例如表创建操作或表数据更改)的“事件”,记录SQL语句发生的时间、执行时长、数据更改等信息,二进制日志有两个重要目的:

  • 用于主从复制,主库上的二进制日志提供要发送到备库的数据更改记录,主库将二进制日志中包含的信息发送到备库,备库应用这些日志进行与主库相同的数据更改操作。

  • 用于数据库恢复,恢复备份后,将重新执行二进制日志中在备份后记录的事件以保证数据库的最新状态。

   二进制日志不用于诸如SELECT或SHOW这样的没有修改任何数据的语句,启用二进制日志会使数据库性能有所降低,但是有利于数据库复制和还原,利大于弊,推用。

  MySQL服务器会重写二进制日志中的SQL语句中的密码,以使它们不会以纯文本的形式出现。从MySQL 8.0.14开始,可以对二进制日志文件和中继日志文件进行加密,从而有助于保护这些文件以及其中包含的潜在敏感数据,使其免受外部攻击者的滥用,并防止其所在的操作系统的未经授权的用户查看。可以通过设置binlog_encryption=ON在MySQL服务器上启用加密。

   默认情况下启用二进制日志记录( log_bin=ON),使用mysqld通过 --initialize或者 --initialize-insecure手动调用数据目录来初始化数据目录 --log-bin,要禁用二进制日志记录,可以在启动时指定 --skip-log-bin 或 --disable-log-bin,如果指定了这些参数中的任何一个,同时也指定了 --log-bin,则以最后指定的为准。

  MySQL服务器创建新二进制文件的条件:

  • 服务器已启动或重新启动
  • 服务器刷新日志
  • 当前日志文件的大小达到max_binlog_size

  使用large transactions时,二进制日志文件大小可能超过max_binlog_size,这是因为事务是一个整体写入文件中,而不是分割到多个文件。

  二进制日志文件和二进制日志.index文件的默认位置是MySQL的数据存储目录:

mysql> SHOW VARIABLES LIKE 'log_bi%';
+---------------------------------+--------------------------------+
| Variable_name                   | Value                          |
+---------------------------------+--------------------------------+
| log_bin                         | ON                             |
| log_bin_basename                | /home/mysql8/data/binlog       |
| log_bin_index                   | /home/mysql8/data/binlog.index |
| log_bin_trust_function_creators | ON                             |
| log_bin_use_v1_row_events       | OFF                            |
+---------------------------------+--------------------------------+
5 rows in set (0.00 sec)

  可以使用RESET MASTER语句删除所有二进制日志文件,也可以使用PURGE BINARY LOGS删除它们的子集。

  如果使用复制,那么在确定备库都不需要它们之前,不应删除源上的旧二进制日志文件。例如,如果备库从未运行超过三天,则可以每天一次在源上执行mysqladmin flush-logs,然后删除任何超过三天的日志;可以手动删除文件,但是最好使用PURGE BINARY LOGS,它同时安全地更新二进制日志索引文件(并且可以使用date参数)。

  可以使用mysqlbinlog实用程序显示二进制日志文件的内容,中继日志与二进制日志格式相同,同样可以使用mysqlbinlog查看日志内容:

[root@chengyu ~]# mysqlbinlog /home/mysql8/data/binlog.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#200728 10:36:19 server id 1  end_log_pos 125 CRC32 0xe02b6256 	Start: binlog v 4, server v 8.0.20 created 200728 10:36:19 at startup
ROLLBACK/*!*/;
BINLOG '
I48fXw8BAAAAeQAAAH0AAAAAAAQAOC4wLjIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAjjx9fEwANAAgAAAAABAAEAAAAYQAEGggAAAAICAgCAAAACgoKKioAEjQA
CigBVmIr4A==
'/*!*/;
# at 125
#200728 10:36:20 server id 1  end_log_pos 156 CRC32 0x8ad6d546 	Previous-GTIDs
# [empty]
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*/;

  在未提交的事务中,所有更改事务表(例如表)的更新操作(UPDATE,DELETE或INSERT)都会被缓存,直到COMMIT服务器接收到一条语句,此时,mysqld在COMMIT执行之前将整个事务写入二进制日志。对非事务表的修改不能回滚,如果回滚的事务包括对非事务表的修改,则将记录整个事务ROLLBACK并在末尾添加一条语句,以确保复制对这些表的修改。

  当处理事务的线程启动时,会根据binlog_cache_size分配一个缓冲区,如果事务语句大于此值,则线程将打开一个临时文件来存储事务,当线程结束时,将删除临时文件;从MySQL 8.0.17开始,如果服务器上的二进制日志加密处于活动状态,则对临时文件进行加密。max_binlog_cache_size系统变量(默认4GB,这也是最大)可被用来限制用于高速缓存的多语句事务的总大小,如果事务大于该值,执行将失败并回滚,最小值是4096。

  如果使用二进制日志和基于ROW的日志记录格式,则并发插入将转换为CREATE … SELECT或 INSERT … SELECT语句的普通插入,这样做是为了确保可以通过在备份操作期间应用日志来重新创建表的精确副本,如果使用的是基于语句的日志记录,则原始语句将写入日志。

  默认情况下,二进制日志在每次写入(sync_binlog=1)时都会同步到磁盘,如果 sync_binlog未启用它,并且操作系统或计算机(不仅是MySQL服务器)崩溃,则二进制日志的最后一条语句可能会丢失,为防止这种情况,请sync_binlog在每个N提交组之后启用系统变量以将二进制日志同步到磁盘 。

1. 设置二进制日志格式

  二进制日志中记录事件的格式取决于二进制日志格式,支持三种格式类型:基于行的日志(row-based),基于语句的日志(statement-based)和基于混合的日志(mixed-base)。

  • --binlog-format=STATEMENT:基于语句的日志记录格式,MySQL中的复制功能最初是基于SQL语句从源数据库到备库传播。

  • --binlog-format=ROW:在基于行的日志记录(默认)中,源数据库将事件写入二进制日志,以指示各个表行的影响方式。

  • --binlog-format=MIXED:混合日志格式,对于混合日志记录,默认情况下使用基于语句的日志记录,但是在某些情况下,日志记录模式会自动切换为基于行的记录。

--默认是基于行的格式
mysql> SHOW VARIABLES LIKE '%binlog_f%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.00 sec)

--可以通过系统变量的全局值来更改日志记录格式
mysql> SET GLOBAL binlog_format = 'STATEMENT';
mysql> SET GLOBAL binlog_format = 'ROW';
mysql> SET GLOBAL binlog_format = 'MIXED';

--单个客户端可以通过将会话值设置为来控制其自己的语句的日志记录格式binlog_format
mysql> SET SESSION binlog_format = 'STATEMENT';
mysql> SET SESSION binlog_format = 'ROW';
mysql> SET SESSION binlog_format = 'MIXED';

  更改全局binlog_format值需要足够的特权来设置全局系统变量,更改会话binlog_format值需要足够的特权来设置受限制的会话系统变量。

  客户端可能要基于每个会话设置二进制日志记录的原因有几个:

  • 对数据库进行许多小更改的会话可能要使用基于行的日志记录;

  • 执行与WHERE子句中的许多行匹配的更新的会话可能要使用基于语句的日志记录,因为与多行记录相比,记录几条语句效率更高;

  • 有些语句需要在源上执行很多时间,但是导致仅修改了几行,因此,使用基于行的日志记录来复制它们可能是有益的。

  无法在运行时切换复制格式的情况:

  • 复制格式不能从存储的函数或触发器中更改;

  • 如果启用了NDB存储引擎;

  • 如果会话打开了临时表,则不能为该会话(SET @@SESSION.binlog_format)更改复制格式;

  • 如果任何复制通道都有打开临时表,则不能全局(SET @@GLOBAL.binlog_format或SET @@PERSIST.binlog_format)更改复制格式;

  • 如果当前正在运行复制通道应用程序线程,则不能全局(SET @@GLOBAL.binlog_format或 SET @@PERSIST.binlog_format)更改复制格式。

  在以上这些情况下尝试切换复制格式(或尝试设置当前复制格式)都会导致错误,但是,可以随时使用PERSIST_ONLY(SET @@PERSIST_ONLY.binlog_format)更改复制格式,因为此操作不会修改运行时全局系统变量值,并且仅在服务器重启后才生效。不存在任何临时表时,建议不要在运行时切换复制格式,因为仅在使用基于语句的复制时才记录临时表,而对于基于行的复制和混合复制,则不记录它们。

  在复制进行过程中切换复制格式也会导致问题,每个MySQL Server都可以设置自己的并且只能设置自己的二进制日志记录格式(无论binlog_format是全局范围还是会话范围,都为true)。这意味着更改复制源服务器上的日志记录格式不会导致对应的备库更改日志记录格式,使用STATEMENT模式时,系统变量binlog_format不会复制,使用MIXED或 ROW记录模式时,会被复制但被备库忽略。

  备库无法将接收的ROW格式的二进制日志转换为自身的STATEMENT格式日志,因此这种情况下,备库必须使用ROW或 MIXED格式,更改源库二进制日志STATEMENT格式为ROW或MIXED,因为备库使用STATEMENT格式可能会导致复制失败,报错如:Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT.

  如果使用InnoDB表,并且事务隔离级别为READ COMMITTED或READ UNCOMMITTED,则只能使用基于ROW的日志记录;可以更改日志格式STATEMENT,但在运行时更改会马上报错,因为InnoDB不能再执行插入操作。二进制日志格式设置为ROW时,数据库更改就以ROW格式写入二进制日志,但是,某些更改仍然基于STATEMENT的格式,比如所有DDL(数据定义语言)语句,例如CREATE TABLE,ALTER TABLE或 DROP TABLE。

2. 混合二进制记录格式

  当以MIXED日志记录格式运行时,服务器在以下情况下会自动从statement-based的记录格式切换为row-based记录格式:

  • 当函数包含UUID()时;

  • 当一个或多个带有AUTO_INCREMENT列的表被更新并且触发器或存储的函数被调用时,像所有其他不安全的语句一样,如果binlog_format = STATEMENT则会生成警告;

  • 当视图主体需要基于行的复制时,创建视图的语句也将使用它,例如,当创建视图的语句使用该UUID()函数时,就会发生这种情况;

  • 当涉及到UDF的调用时;

  • 使用FOUND_ROWS()或 ROW_COUNT()时; (Bug #12092, Bug #30244)

  • 使用USER(),CURRENT_USER()或CURRENT_USER时;(Bug #28086)

  • 当涉及的表之一是mysql数据库中的日志表时;

  • 使用该LOAD_FILE()功能时; (Bug #39701)

  • 当一条语句引用一个或多个系统变量时。(Bug #31168)

  在早期版本中,当使用混合二进制日志记录格式时,如果按行记录一条语句,并且执行该语句的会话具有任何临时表,则所有后续语句均被视为不安全,并以基于行的格式记录,直到所有临时表该会话正在使用中的已删除。从MySQL 8.0开始,对临时表的操作不会以混合二进制日志格式记录,并且会话中临时表的存在不会影响每个语句所使用的日志模式。

  注意:如果尝试使用基于语句的日志记录执行语句,则应使用基于行的日志记录来生成警告;该警告在客户端(在的输出中SHOW WARNINGS)和mysqld错误日志中均显示,SHOW WARNINGS 每次执行这样的语句时,都会向表中添加一条警告;但是,只有为每个客户端会话生成警告的第一条语句才被写入错误日志,以防止日志泛滥。

3. 更改MySQL数据库表的日志记录格式

  MySQL可以直接(例如:使用INSERT或 DELETE)或间接地(例如使用GRANT或CREATE USER)修改数据库中授权表的内容,MySQL使用以下规则将影响数据库表的语句写入二进制日志:

  • MySQL根据binlog_format系统变量的设置,直接记录更改数据库表中数据的数据操作语句,这适用于语句如INSERT,UPDATE,DELETE,REPLACE,DO,LOAD DATA,SELECT和TRUNCATE TABLE。

  • MySQL不管binlog_format的值如何,都将间接以statements格式记录更改数据库语句,这涉及语句如 GRANT,REVOKE,SET PASSWORD RENAME USER,CREATE(所有形式的除外CREATE TABLE … SELECT),ALTER(所有形式的),和DROP(各种形式)。

  CREATE TABLE … SELECT是数据定义和数据处理的组合,该CREATE TABLE部分是利用statement格式记录,且SELECT部分根据binlog_format的值记录。

4.二进制日志事务压缩

  从MySQL 8.0.20开始,可以在MySQL服务器实例上启用二进制日志事务压缩,启用二进制日志事务压缩后,将使用zstd算法压缩事务有效负载,然后将其作为单个事件(a Transaction_payload_event)写入服务器的二进制日志文件 。压缩后的事务负载在复制流中发送到备库,其他组复制组成员或客户端(例如mysqlbinlog)时,保持压缩状态 。它们不会被接收器线程解压缩,并且仍以其压缩状态写入中继日志。因此,二进制日志事务压缩既可以节省事务的始发者,也可以节省接收者(及其备份)的存储空间,并在服务器实例之间发送事务时节省网络带宽。

  当需要检查压缩的事务有效负载中的各个事件时,将其解压缩,例如,Transaction_payload_event通过应用程序线程对进行解压缩,以便将其包含的事件应用于接收者。在恢复期间,也可以通过重做事务时使用mysqlbinlog以及SHOW BINLOG EVENTS和SHOW RELAYLOG EVENTS语句来执行解压缩。

  可以使用binlog_transaction_compression系统变量(默认值为OFF)在MySQL服务器实例上启用二进制日志事务压缩,也可以使用binlog_transaction_compression_level_zstd系统变量设置用于压缩的zstd算法的级别。此值确定压缩工作量,从1(最小工作量)到22(最大工作量),随着压缩级别的增加,压缩率也会增加,这会减少事务有效负载所需的存储空间和网络带宽,但是,数据压缩所需的工作量也增加了,占用了时间以及原始服务器上的CPU和内存资源,压缩力的增加与压缩比的增加没有线性关系。

mysql> SHOW VARIABLES LIKE 'binlog_transaction_c%';
+-------------------------------------------+-------+
| Variable_name                             | Value |
+-------------------------------------------+-------+
| binlog_transaction_compression            | OFF   |
| binlog_transaction_compression_level_zstd | 3     |
+-------------------------------------------+-------+
2 rows in set (0.00 sec)

2020年08月05日
  官文渣翻,且烂尾,将就读读!

猜你喜欢

转载自blog.csdn.net/u010257584/article/details/107681426