MySQL8 中文参考(二十)(4)https://developer.aliyun.com/article/1566110
7.4.2.8 将错误日志记录到系统日志
可以让mysqld将错误日志写入系统日志(Windows 上的事件日志,Unix 和类 Unix 系统上的syslog
)。
本节描述如何使用内置过滤器log_filter_internal
和系统日志接收器log_sink_syseventlog
配置错误日志记录,以立即生效并在后续服务器启动时生效。有关配置错误日志的一般信息,请参阅 Section 7.4.2.1, “错误日志配置”。
要启用系统日志接收器,首先加载接收器组件,然后修改log_error_services
的值:
INSTALL COMPONENT 'file://component_log_sink_syseventlog'; SET PERSIST log_error_services = 'log_filter_internal; log_sink_syseventlog';
要在服务器启动时设置log_error_services
生效,请使用 Section 7.4.2.1, “错误日志配置”中的说明。这些说明也适用于其他错误日志系统变量。
注意
对于 MySQL 8.0 配置,您必须显式启用将错误日志记录到系统日志。这与 MySQL 5.7 及更早版本不同,在 Windows 上默认启用将错误日志记录到系统日志,并且在所有平台上不需要加载组件。
将错误日志记录到系统日志可能需要额外的系统配置。请查阅您平台的系统日志文档。
在 Windows 上,写入应用程序日志中的事件日志错误消息具有以下特征:
- 标记为
Error
、Warning
和Note
的条目会被写入事件日志,但不包括来自各个存储引擎的信息声明。 - 事件日志条目的来源是
MySQL
(或MySQL-*
tag*
,如果syseventlog.tag
定义为*tag
*)。
在 Unix 和类 Unix 系统上,记录到系统日志使用syslog
。以下系统变量会影响syslog
消息:
syseventlog.facility
:syslog
消息的默认设施是daemon
。设置此变量以指定不同的设施。syseventlog.include_pid
:是否在每行syslog
输出中包含服务器进程 ID。syseventlog.tag
:此变量定义要添加到syslog
消息中服务器标识符(mysqld
)的标记。如果定义了标记,则标记将以前导连字符附加到标识符后面。
注意
在 MySQL 8.0.13 之前,请使用log_syslog_facility
、log_syslog_include_pid
和log_syslog_tag
系统变量,而不是syseventlog.*
xxx*
变量。
MySQL 使用自定义标签“系统”来表示关于非错误情况的重要系统消息,例如启动、关闭和一些重要设置更改。在不支持自定义标签的日志中,包括 Windows 上的事件日志和 Unix 及类 Unix 系统上的syslog
,系统消息被分配给信息优先级级别使用的标签。然而,即使 MySQL log_error_verbosity
设置通常排除信息级别的消息,这些消息也会被打印到日志中。
当日志接收器必须以“信息”标签而不是“系统”标签回退时,并且日志事件在 MySQL 服务器外进一步处理(例如,通过syslog
配置进行过滤或转发),这些事件可能默认由次要应用程序处理为“信息”优先级而不是“系统”优先级。
7.4.2.9 错误日志输出格式
每个错误日志输出组件都有其用于将消息写入目的地的特征输出格式,但其他因素可能影响消息的内容:
- 日志输出可用的信息。如果在执行输出组件之前执行了日志过滤组件以删除日志事件字段,则该字段不可用于写入。有关日志过滤的信息,请参阅第 7.4.2.4 节,“错误日志过滤类型”。
- 与日志输出组件相关的信息。并非每个输出组件都会写入错误事件中可用的所有字段。
- 系统变量可能会影响日志输出。请参阅影响错误日志格式的系统变量。
有关错误事件中字段的名称和描述,请参阅第 7.4.2.3 节,“错误事件字段”。对于所有日志输出,包含在错误日志消息中的线程 ID 是负责编写消息的mysqld内的线程 ID。此 ID 指示服务器的哪个部分生成了消息,并与一般查询日志和慢查询日志消息一致,这些消息包括连接线程 ID。
- log_sink_internal 输出格式
- log_sink_json 输出格式
- log_sink_syseventlog 输出格式
- 早期启动日志输出格式
- 影响错误日志格式的系统变量
log_sink_internal 输出格式
内部日志输出产生传统错误日志输出。例如:
2020-08-06T14:25:02.835618Z 0 [Note] [MY-012487] [InnoDB] DDL log recovery : begin 2020-08-06T14:25:02.936146Z 0 [Warning] [MY-010068] [Server] CA certificate /var/mysql/sslinfo/cacert.pem is self signed. 2020-08-06T14:25:02.963127Z 0 [Note] [MY-010253] [Server] IPv6 is available. 2020-08-06T14:25:03.109022Z 5 [Note] [MY-010051] [Server] Event Scheduler: scheduler thread started with id 5
传统格式消息具有以下字段:
time thread [label] [err_code] [subsystem] msg
[
和 ]
方括号字符是消息格式中的文字字符。它们不表示字段是可选的。
label
值对应于 prio
错误事件优先级字段的字符串形式。
[err_code]
和 [subsystem]
字段在 MySQL 8.0 中添加。这些字段在旧服务器生成的日志中缺失。日志解析器可以将这些字段视为仅在包含它们的新服务器生成的日志中存在的消息文本的一部分。解析器必须将 [err_code]
指示器中的 err_code
部分视为字符串值,而不是数字,因为像 MY-012487
和 MY-010051
这样的值包含非数字字符。
log_sink_json 输出格式
JSON 格式的日志接收器生成包含键值对的 JSON 对象作为消息。例如:
{ "prio": 3, "err_code": 10051, "source_line": 561, "source_file": "event_scheduler.cc", "function": "run", "msg": "Event Scheduler: scheduler thread started with id 5", "time": "2020-08-06T14:25:03.109022Z", "ts": 1596724012005, "thread": 5, "err_symbol": "ER_SCHEDULER_STARTED", "SQL_state": "HY000", "subsystem": "Server", "buffered": 1596723903109022, "label": "Note" }
显示的消息已经重新格式化以提高可读性。写入错误日志的事件每行显示一条消息。
ts
(时间戳)键在 MySQL 8.0.20 中添加,是 JSON 格式日志接收器特有的。其值是一个整数,表示自纪元('1970-01-01 00:00:00'
UTC)以来的毫秒数。
ts
和 buffered
值是 Unix 时间戳值,可以使用 FROM_UNIXTIME()
和适当的除数进行转换:
mysql> SET time_zone = '+00:00'; mysql> SELECT FROM_UNIXTIME(1596724012005/1000.0); +-------------------------------------+ | FROM_UNIXTIME(1596724012005/1000.0) | +-------------------------------------+ | 2020-08-06 14:26:52.0050 | +-------------------------------------+ mysql> SELECT FROM_UNIXTIME(1596723903109022/1000000.0); +-------------------------------------------+ | FROM_UNIXTIME(1596723903109022/1000000.0) | +-------------------------------------------+ | 2020-08-06 14:25:03.1090 | +-------------------------------------------+
log_sink_syseventlog 输出格式
系统日志接收器生成符合本地平台使用的系统日志格式的输出。
早期启动日志输出格式
服务器在启动选项被处理之前生成一些错误日志消息,因此在了解错误日志设置(如log_error_verbosity
和log_timestamps
系统变量值)以及要使用的日志组件之前。服务器处理在启动过程中生成的错误日志消息如下:
- 在 MySQL 8.0.14 之前,服务器生成具有默认时间戳、格式和详细级别的消息,并对其进行缓冲。在处理启动选项并了解错误日志配置之后,服务器会刷新缓冲的消息。由于这些早期消息使用默认日志配置,它们可能与启动选项指定的内容不同。此外,早期消息不会刷新到除默认接收器之外的日志接收器。例如,记录到 JSON 接收器不包括这些早期消息,因为它们不是 JSON 格式。
- 从 MySQL 8.0.14 开始,服务器缓冲日志事件而不是格式化的日志消息。这使得在了解设置之后可以对这些事件进行追溯应用配置设置,结果是刷新的消息使用配置的设置,而不是默认设置。此外,消息会刷新到所有配置的接收器,而不仅仅是默认接收器。
如果在日志配置未知之前发生致命错误并且服务器必须退出,则服务器使用日志默认值格式化缓冲消息,以免丢失。如果没有发生致命错误,但启动在处理启动选项之前过于缓慢,则服务器会定期使用日志默认值格式化和刷新缓冲消息,以免显得无响应。尽管这种行为类似于 8.0.14 之前的行为,即使用默认值,但在异常情况发生时不丢失消息更为可取。
影响错误日志格式的系统变量
log_timestamps
系统变量控制写入错误日志(以及一般查询日志和慢查询日志文件)中时间戳的时区。服务器在错误事件到达任何日志接收端之前应用log_timestamps
,因此它影响所有接收端的错误消息输出。
允许的log_timestamps
值为UTC
(默认)和SYSTEM
(本地系统时区)。时间戳使用 ISO 8601 / RFC 3339 格式写入:*
YYYY-MM-DD*T*
hh:mm:ss.uuuuuu*
加上一个尾部值Z
表示 Zulu 时间(UTC)或±hh:mm
(一个指示本地系统时区相对于 UTC 的调整偏移)。例如:
2020-08-07T15:02:00.832521Z (UTC) 2020-08-07T10:02:00.832521-05:00 (SYSTEM)
7.4.2.10 错误日志文件清空和重命名
如果使用FLUSH ERROR LOGS
或FLUSH LOGS
语句,或者使用mysqladmin flush-logs命令来清空错误日志,服务器将关闭并重新打开正在写入的任何错误日志文件。在清空之前,请手动重命名错误日志文件。清空日志后,将使用原始文件名打开一个新文件。例如,假设日志文件名为*
host_name*.err
,请使用以下命令重命名文件并创建一个新文件:
mv *host_name*.err *host_name*.err-old mysqladmin flush-logs error mv *host_name*.err-old *backup-directory*
在 Windows 上,请使用rename而不是mv。
如果服务器无法写入错误日志文件的位置,则清空日志操作将无法创建新的日志文件。例如,在 Linux 上,服务器可能会将错误日志写入/var/log/mysqld.log
文件,其中/var/log
目录由root
所有且不可写入mysqld。有关处理此情况的信息,请参见第 7.4.6 节“服务器日志维护”。
如果服务器没有写入命名的错误日志文件,则在清空错误日志时不会发生错误日志文件重命名。
7.4.3 通用查询日志
通用查询日志是mysqld正在执行的一般记录。当客户端连接或断开连接时,服务器会将信息写入此日志,并记录从客户端接收的每个 SQL 语句。当您怀疑客户端中存在错误并想确切知道客户端发送给mysqld的内容时,通用查询日志可能非常有用。
每当客户端连接时显示的每一行还包括using *
connection_type*
,表示建立连接所使用的协议。*connection_type
*可以是TCP/IP
(未使用 SSL 建立的 TCP/IP 连接)、SSL/TLS
(使用 SSL 建立的 TCP/IP 连接)、Socket
(Unix 套接字文件连接)、Named Pipe
(Windows 命名管道连接)或Shared Memory
(Windows 共享内存连接)。
mysqld按照接收到的顺序将语句写入查询日志,这可能与执行顺序不同。这种记录顺序与二进制日志的记录顺序相反,二进制日志中的语句是在执行后但在释放任何锁之前写入的。此外,查询日志可能包含仅选择数据的语句,而这些语句永远不会写入二进制日志。
在复制源服务器上使用基于语句的二进制日志记录时,其副本接收的语句将写入每个副本的查询日志。如果客户端使用mysqlbinlog实用程序读取事件并将其传递给服务器,则语句将写入源的查询日志。
然而,当使用基于行的二进制日志记录时,更新以行更改的形式发送,而不是 SQL 语句,因此当binlog_format
设置为ROW
时,这些语句永远不会写入查询日志。当此变量设置为MIXED
时,根据使用的语句,给定的更新也可能不会写入查询日志。有关更多信息,请参见 Section 19.2.1.1, “基于语句和基于行的复制的优缺点”。
默认情况下,通用查询日志被禁用。要明确指定初始通用查询日志状态,请使用--general_log[={0|1}]
。没有参数或参数为 1 时,--general_log
启用日志。参数为 0 时,此选项禁用日志。要指定日志文件名,请使用--general_log_file=*
file_name*
。要指定日志目的地,请使用log_output
系统变量(如第 7.4.1 节,“选择通用查询日志和慢查询日志输出目的地”中所述)。
注意
如果指定了TABLE
日志目的地,请参阅日志表和“打开文件过多”错误。
如果未为通用查询日志文件指定名称,则默认名称为*
host_name*.log
。服务器会在数据目录中创建文件,除非给定绝对路径名以指定不同的目录。
要在运行时禁用或启用通用查询日志或更改日志文件名,请使用全局general_log
和general_log_file
系统变量。将general_log
设置为 0(或OFF
)以禁用日志,设置为 1(或ON
)以启用日志。设置general_log_file
以指定日志文件的名称。如果已经打开了日志文件,则会关闭该文件并打开新文件。
当启用通用查询日志时,服务器会将输出写入由log_output
系统变量指定的任何目的地。如果启用日志,服务器会打开日志文件并将启动消息写入其中。但是,除非选择了FILE
日志目的地,否则不会进一步记录查询到文件中。如果目的地是NONE
,即使启用了通用日志,服务器也不会写入任何查询。如果日志目的地值不包含FILE
,设置日志文件名对日志记录没有影响。
服务器重启和日志刷新不会导致生成新的通用查询日志文件(尽管刷新会关闭并重新打开它)。要重命名文件并创建一个新文件,请使用以下命令:
$> mv *host_name*.log *host_name*-old.log $> mysqladmin flush-logs general $> mv *host_name*-old.log *backup-directory*
在 Windows 上,使用rename而不是mv。
您还可以通过禁用日志来在运行时重命名通用查询日志文件:
SET GLOBAL general_log = 'OFF';
禁用日志后,通过外部重命名日志文件(例如,从命令行)然后再次启用日志:
SET GLOBAL general_log = 'ON';
这种方法适用于任何平台,不需要服务器重启。
要为当前会话禁用或启用一般查询日志记录,请将会话 sql_log_off
变量设置为 ON
或 OFF
。(这假定一般查询日志本身已启用。)
写入一般查询日志的语句中的密码会被服务器重写,以避免以明文形式出现。可以通过使用 --log-raw
选项启动服务器来阻止一般查询日志的密码重写。这个选项可能对诊断目的有用,以查看服务器接收到的语句的确切文本,但出于安全原因,不建议在生产环境中使用。另请参见 Section 8.1.2.3, “Passwords and Logging”。
密码重写的一个影响是无法解析的语句(例如由于语法错误)不会被写入一般查询日志,因为无法知道它们是否不包含密码。需要记录所有语句(包括带有错误的语句)的用例应该使用 --log-raw
选项,需要注意的是这也会绕过密码重写。
只有在预期明文密码时才会进行密码重写。对于期望密码哈希值的语法的语句,不会进行重写。如果错误地为这种语法提供了明文密码,则密码将按原样记录,而不进行重写。
log_timestamps
系统变量控制着写入一般查询日志文件(以及慢查询日志文件和错误日志)中的时间戳的时区。它不影响写入日志表的一般查询日志和慢查询日志消息的时区,但是从这些表中检索的行可以通过 CONVERT_TZ()
或设置会话 time_zone
系统变量将其从本地系统时区转换为任何所需的时区。
7.4.4 二进制日志
7.4.4.1 二进制日志格式
7.4.4.2 设置二进制日志格式
7.4.4.3 混合二进制日志格式
7.4.4.4 更改 mysql 数据库表的日志格式
7.4.4.5 二进制日志事务压缩
二进制日志包含描述数据库更改的“事件”,例如表创建操作或表数据更改。它还包含可能已经进行更改的语句的事件(例如,一个DELETE
未匹配任何行),除非使用基于行的日志记录。二进制日志还包含更新数据的每个语句所花费的时间信息。二进制日志有两个重要目的:
- 对于复制,复制源服务器上的二进制日志提供了要发送到副本的数据更改记录。源服务器将其二进制日志中包含的信息发送给其副本,副本会重现这些事务以进行与源服务器上进行的相同数据更改。参见第 19.2 节,“复制实现”。
- 某些数据恢复操作需要使用二进制日志。在备份被恢复后,备份后记录的二进制日志中的事件将被重新执行。这些事件将数据库从备份点更新到最新状态。参见第 9.5 节,“时间点(增量)恢复” Recovery")。
二进制日志不用于诸如SELECT
或SHOW
等不修改数据的语句。要记录所有语句(例如,以识别问题查询),请使用一般查询日志。参见第 7.4.3 节,“一般查询日志”。
启用二进制日志记录的服务器运行性能略有下降。然而,二进制日志在启用复制和进行恢复操作方面的好处通常超过了这种轻微的性能降低。
二进制日志对意外停止是有弹性的。只有完整的事件或事务才会被记录或读取回来。
写入二进制日志的语句中的密码由服务器重写,以避免明文出现。另请参见第 8.1.2.3 节,“密码和日志记录”。
从 MySQL 8.0.14 开始,二进制日志文件和中继日志文件可以加密,有助于保护这些文件以及其中可能包含的敏感数据免受外部攻击者的滥用,也免受存储它们的操作系统用户的未经授权查看。 您可以通过将 binlog_encryption
系统变量设置为 ON
在 MySQL 服务器上启用加密。 有关更多信息,请参见 Section 19.3.2, “加密二进制日志文件和中继日志文件”。
以下讨论描述了一些影响二进制日志记录操作的服务器选项和变量。 完整列表,请参见 Section 19.1.6.4, “二进制日志记录选项和变量”。
二进制日志记录默认启用(log_bin
系统变量设置为 ON)。 例外情况是,如果您使用 mysqld 手动调用 --initialize
或 --initialize-insecure
选项初始化数据目录,则默认情况下禁用二进制日志记录,但可以通过指定 --log-bin
选项启用。
要禁用二进制日志记录,您可以在启动时指定 --skip-log-bin
或 --disable-log-bin
选项。 如果指定了其中任何一个选项,并且同时指定了 --log-bin
,则后面指定的选项优先。
--log-slave-updates
和--slave-preserve-commit-order
选项需要进行二进制日志记录。如果禁用二进制日志记录,要么省略这些选项,要么指定--log-slave-updates=OFF
和--skip-slave-preserve-commit-order
。当指定--skip-log-bin
或--disable-log-bin
时,MySQL 默认禁用这些选项。如果同时指定--log-slave-updates
或--slave-preserve-commit-order
和--skip-log-bin
或--disable-log-bin
,将发出警告或错误消息。
--log-bin[=*
base_name*]
选项用于指定二进制日志文件的基本名称。如果不提供--log-bin
选项,MySQL 将使用binlog
作为二进制日志文件的默认基本名称。为了与早期版本兼容,如果提供了--log-bin
选项但没有字符串或为空字符串,则基本名称默认为*
host_name*-bin
,使用主机机器的名称。建议您指定一个基本名称,这样如果主机名更改,您可以轻松地继续使用相同的二进制日志文件名称(参见 Section B.3.7, “Known Issues in MySQL”)。如果在日志名称中提供了扩展名(例如,--log-bin=*
base_name.extension*
),则扩展名会被静默删除并忽略。
mysqld会在二进制日志基本名称后附加一个数字扩展名以生成二进制日志文件名称。每次服务器创建新的日志文件时,该数字会增加,从而创建一个有序的文件系列。每当发生以下事件之一时,服务器都会在系列中创建一个新文件:
- 服务器启动或重新启动
- 服务器会刷新日志。
- 当��日志文件的大小达到
max_binlog_size
设置的大小。
如果使用大型事务,二进制日志文件可能会比max_binlog_size
设置的大小更大,因为事务会一次性写入文件,而不会在文件之间分割。
为了跟踪已使用的二进制日志文件,mysqld还会创建一个包含二进制日志文件名称的二进制日志索引文件。默认情况下,这个文件与二进制日志文件具有相同的基本名称,扩展名为'.index'
。您可以使用--log-bin-index[=*
file_name*]
选项更改二进制日志索引文件的名称。在mysqld运行时不应手动编辑此文件;这样做会使mysqld混淆。
术语“二进制日志文件”通常表示包含数据库事件的单个编号文件。术语“二进制日志”集体表示一组编号的二进制日志文件和索引文件。
默认的二进制日志文件和二进制日志索引文件的位置是数据目录。您可以使用--log-bin
选项来指定另一个位置,只需在基本名称前添加绝对路径名以指定不同的目录。当服务器从二进制日志索引文件中读取条目时(该文件跟踪已使用的二进制日志文件),它会检查条目是否包含相对路径。如果包含相对路径,则使用--log-bin
选项设置的绝对路径将替换路径的相对部分。在二进制日志索引文件中记录的绝对路径保持不变;在这种情况下,必须手动编辑索引文件以启用新路径或路径的使用。二进制日志文件基本名称和任何指定的路径可作为log_bin_basename
系统变量使用。
在 MySQL 5.7 中,启用二进制日志记录时必须指定服务器 ID,否则服务器将无法启动。在 MySQL 8.0 中,默认情况下将server_id
系统变量设置为 1。当启用二进制日志记录时,服务器可以使用此默认 ID 启动,但如果您不使用server_id
系统变量显式指定服务器 ID,则会发出信息消息。对于用于复制拓扑的服务器,必须为每个服务器指定唯一的非零服务器 ID。
拥有足够权限设置受限会话系统变量的客户端(参见第 7.1.9.1 节,“系统变量权限”)可以通过使用SET sql_log_bin=OFF
语句禁用自己语句的二进制日志记录。
默认情况下,服务器记录事件的长度以及事件本身,并使用这些信息来验证事件是否正确写入。您还可以通过设置binlog_checksum
系统变量来导致服务器为事件编写校验和。从二进制日志中读取时,默认情况下源使用事件长度,但可以通过启用系统变量source_verify_checksum
(从 MySQL 8.0.26 开始)或master_verify_checksum
(在 MySQL 8.0.26 之前)来使用校验和(如果可用)。副本上的复制 I/O(接收器)线程还会验证从源接收的事件。您可以通过启用系统变量replica_sql_verify_checksum
(从 MySQL 8.0.26 开始)或slave_sql_verify_checksum
(在 MySQL 8.0.26 之前)来导致复制 SQL(应用程序)线程在从中继日志读取时使用校验和(如果可用)。
记录在二进制日志中的事件的格式取决于二进制日志格式。支持三种格式类型:基于行的日志记录、基于语句的日志记录和混合基于日志记录。所使用的二进制日志格式取决于 MySQL 版本。有关日志格式的一般描述,请参见 Section 7.4.4.1, “Binary Logging Formats”。有关二进制日志格式的详细信息,请参见 MySQL Internals: The Binary Log。
服务器以与--replicate-do-db
和--replicate-ignore-db
选项相同的方式评估--binlog-do-db
和--binlog-ignore-db
选项。有关此操作的信息,请参见 Section 19.2.5.1, “Evaluation of Database-Level Replication and Binary Logging Options”。
一个复制品默认启用系统变量log_replica_updates
(从 MySQL 8.0.26 开始)或log_slave_updates
(MySQL 8.0.26 之前),这意味着复制品会将从源接收到的任何数据修改写入自己的二进制日志。必须启用二进制日志才能使此设置生效(参见第 19.1.6.3 节,“复制品服务器选项和变量”)。此设置使复制品能够作为其他复制品的源。
您可以使用RESET MASTER
语句删除所有二进制日志文件,或使用PURGE BINARY LOGS
删除其中的一部分。请参见第 15.7.8.6 节,“RESET 语句”,以及第 15.4.1.1 节,“PURGE BINARY LOGS 语句”。
如果您正在使用复制,应在确定没有复制品仍然需要使用旧二进制日志文件之前,不要删除源上的旧二进制日志文件。例如,如果您的复制品永远不会落后于三天,那么每天您可以在源上执行mysqladmin flush-logs binary,然后删除三天前的任何日志。您可以手动删除文件,但最好使用PURGE BINARY LOGS
,这也会安全地为您更新二进制日志索引文件(并且可以接受日期参数)。请参见第 15.4.1.1 节,“PURGE BINARY LOGS 语句”。
您可以使用mysqlbinlog实用程序显示二进制日志文件的内容。当您想要重新处理日志中的语句以进行恢复操作时,这可能很有用。例如,您可以按以下方式从二进制日志更新 MySQL 服务器:
$> mysqlbinlog *log_file* | mysql -h *server_name*
mysqlbinlog还可以用于显示复制品上中继日志文件的内容,因为它们使用与二进制日志文件相同的格式进行编写。有关mysqlbinlog实用程序及其使用方法的更多信息,请参见第 6.6.9 节,“mysqlbinlog — 用于处理二进制日志文件的实用���序”。有关二进制日志和恢复操作的更多信息,请参见第 9.5 节,“时间点(增量)恢复”。
二进制日志记录在语句或事务完成后立即进行,但在释放任何锁或执行任何提交之前。这确保了日志按提交顺序记录。
对非事务表的更新会立即存储在二进制日志中。
在未提交的事务中,所有更新(UPDATE
、DELETE
或 INSERT
)对更改事务表(如 InnoDB
表)的操作都会被缓存,直到服务器接收到 COMMIT
语句。此时,mysqld 在执行 COMMIT
之前将整个事务写入二进制日志。
对非事务表的修改无法回滚。如果要回滚的事务包括对非事务表的修改,则整个事务将以 ROLLBACK
语句记录,以确保这些表的修改被复制。
当处理事务的线程启动时,它会分配一个大小为 binlog_cache_size
的缓冲区来缓冲语句。如果语句大于此值,线程将打开一个临时文件来存储事务。当线程结束时,临时文件将被删除。从 MySQL 8.0.17 开始,如果服务器上启用了二进制日志加密,则临时文件将被加密。
Binlog_cache_use
状态变量显示了使用此缓冲区(可能还包括临时文件)存储语句的事务数量。Binlog_cache_disk_use
状态变量显示了实际需要使用临时文件的事务数量。这两个变量可用于调整 binlog_cache_size
的值,使其足够大,避免使用临时文件。
max_binlog_cache_size
系统变量(默认为 4GB,也是最大值)可用于限制用于缓存多语句事务的总大小。如果事务大于此字节数,它将失败并回滚。最小值为 4096。
如果您正在使用二进制日志和基于行的日志记录,CREATE ... SELECT
或INSERT ... SELECT
语句中的并发插入将转换为普通插入。这样做是为了确保您可以通过在备份操作期间应用日志来重新创建表的精确副本。如果使用基于语句的日志记录,则原始语句将写入日志。
二进制日志格式存在一些已知限制,可能会影响从备份中恢复。参见第 19.5.1 节,“复制功能和问题”。
存储程序的二进制日志记录如第 27.7 节,“存储程序二进制日志记录”所述。
请注意,由于复制功能的增强,MySQL 8.0 中的二进制日志格式与 MySQL 先前版本不同。请参见第 19.5.2 节,“MySQL 版本之间的复制兼容性”。
如果服务器无法写入二进制日志,刷新二进制日志文件,或将二进制日志同步到磁盘,复制源服务器上的二进制日志可能会变得不一致,副本可能会与源失去同步。binlog_error_action
系统变量控制在遇到此类错误时采取的操作。
- 默认设置
ABORT_SERVER
使服务器停止二进制日志记录并关闭。此时,您可以识别和纠正错误的原因。在重新启动时,恢复将如同意外服务器停止的情况一样进行(参见第 19.4.2 节,“处理副本意外停止”)。 - 设置
IGNORE_ERROR
提供与旧版本 MySQL 的向后兼容性。使用此设置,服务器将继续进行进行中的事务并记录错误,然后停止二进制日志记录,但继续执行更新。此时,您可以识别和纠正错误的原因。要恢复二进制日志记录,必须重新启用log_bin
,这需要重新启动服务器。只有在需要向后兼容性,并且二进制日志在此 MySQL 服务器实例上是非必需的情况下才使用此选项。例如,您可能仅将二进制日志用于服务器的间歇性审计或调试,并且不将其用于从服务器复制或依赖于其进行时间点还原操作。
默认情况下,二进制日志在每次写入时都会同步到磁盘(sync_binlog=1
)。如果未启用sync_binlog
,并且操作系统或机器(不仅仅是 MySQL 服务器)崩溃,那么二进制日志的最后几条语句可能会丢失。为了防止这种情况发生,启用sync_binlog
系统变量,以在每个*N
*提交组后将二进制日志同步到磁盘。参见第 7.1.8 节,“服务器系统变量”。sync_binlog
的最安全值是 1(默认值),但这也是最慢的。
在早期的 MySQL 版本中,即使将sync_binlog
设置为 1,如果发生崩溃,表内容和二进制日志内容之间仍可能存在不一致的情况。例如,如果您正在使用InnoDB
表,并且 MySQL 服务器处理一个COMMIT
语句,它会按顺序将许多准备好的事务写入二进制日志,同步二进制日志,然后将事务提交到InnoDB
。如果服务器在这两个操作之间意外退出,InnoDB
会在重新启动时回滚事务,但事务仍然存在于二进制日志中。在以前的版本中,通过在 XA 事务中启用InnoDB
支持两阶段提交来解决了这个问题。在 MySQL 8.0 中,InnoDB
对 XA 事务中的两阶段提交始终是启用的。
InnoDB
对 XA 事务中的两阶段提交支持确保了二进制日志和InnoDB
数据文件的同步。然而,MySQL 服务器还应配置为在提交事务之前将二进制日志和InnoDB
日志同步到磁盘。InnoDB
日志默认是同步的,而sync_binlog=1
确保了二进制日志的同步。隐式InnoDB
对 XA 事务中的两阶段提交支持和sync_binlog=1
的效果是,在崩溃后重新启动后,在回滚事务后,MySQL 服务器会扫描最新的二进制日志文件以收集事务*xid
*值,并计算二进制日志文件中的最后有效位置。然后,MySQL 服务器告诉InnoDB
完成已成功写入二进制日志的任何准备好的事务,并将二进制日志截断到最后的有效位置。这确保了二进制日志反映了InnoDB
表的确切数据,因此复制品保持与源的同步,因为它不会接收已回滚的语句。
如果 MySQL 服务器在崩溃恢复时发现二进制日志比应该的长度短,那么至少缺少一个成功提交的InnoDB
事务。如果sync_binlog=1
,并且磁盘/文件系统在被请求时进行了实际同步(有些不会),那么不应该发生这种情况,因此服务器会打印错误消息The binary log *
file_name* is shorter than its expected size
。在这种情况下,此二进制日志不正确,复制应该从源数据的新快照重新启动。
以下系统变量的会话值将被写入二进制日志,并在解析二进制日志时被复制实例所遵守:
sql_mode
(除了NO_DIR_IN_CREATE
模式不会被复制;参见第 19.5.1.39 节,“复制和变量”)foreign_key_checks
unique_checks
character_set_client
collation_connection
collation_database
collation_server
sql_auto_is_null