Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


17.6.5 重做日志

重做日志是一种基于磁盘的数据结构,用于崩溃恢复中修复由不完整事务写入的数据。正常运行时,重做日志将 SQL 语句或低级 API 调用结果对表数据进行编码。未能在意外关闭前完成更新数据文件的修改将在初始化和连接接受前自动重新播放。关于重做日志在崩溃恢复中的作用,请参阅第17.18.2节,“InnoDB恢复”

重做日志在磁盘上以文件形式存在。写入到重做日志文件中的数据将以影响的记录为单位进行编码,这些数据统称为重做。数据通过重做日志文件的传递由一个不断增加的LSN值表示。重做日志数据将在数据修改时追加,并且随着检查点的进度而截断最旧的数据。

关于重做日志的信息和操作,请参阅以下主题在该部分中:

配置重做日志容量

系统变量innodb_redo_log_capacity控制重做日志文件占用的磁盘空间。你可以在启动或运行时使用一个SET GLOBAL语句将其设置;例如,以下语句将重做日志容量设置为8GB:

SET GLOBAL innodb_redo_log_capacity = 8589934592;

在运行时设置配置更改将立即生效,但可能需要一些时间才能完全实现。如果重做日志文件占用的空间少于指定值,则脏页从缓冲池中被flush到表空间数据文件中更不积极,最后增加了磁盘空间占用的重做日志文件。如果重做日志文件占用的空间多于指定值,则脏页被flush得更积极,最后减少了磁盘空间占用的重做日志文件。

如果未定义innodb_redo_log_capacity,且未定义innodb_log_file_size或innodb_log_files_in_group,则将使用默认的innodb_redo_log_capacity值。

如果未定义innodb_redo_log_capacity,并且定义了innodb_log_file_size和/或innodb_log_files_in_group,那么InnoDB redo日志的容量将被计算为(innodb_log_files_in_group * innodb_log_file_size)。这项计算不会修改未使用的innodb_redo_log_capacity设置的值。

服务器状态变量Innodb_redo_log_capacity_resized表示所有redo日志文件的总容量。

redo日志文件位于数据目录中的#innodb_redo目录,除非通过innodb_log_group_home_dir变量指定了不同的目录。如果定义了innodb_log_group_home_dir,那么redo日志文件位于该目录中的#innodb_redo目录。 redo日志文件有两种类型:普通和备用。普通redo日志文件是正在使用的文件,而备用redo日志文件是等待使用的文件。InnoDB尝试维护总共32个redo日志文件,每个文件大小为1/32 * innodb_redo_log_capacity;然而,在修改innodb_redo_log_capacity设置后,文件大小可能会在一段时间内不同。

redo日志文件使用#ib_redoN命名约定,其中N是redo日志文件的编号。备用redo日志文件以_tmp后缀标识。以下示例显示了在#innodb_redo目录中的redo日志文件,其中有21个活动redo日志文件和11个备用redo日志文件,按顺序编号。

'#ib_redo582'  '#ib_redo590'  '#ib_redo598'      '#ib_redo606_tmp'
'#ib_redo583'  '#ib_redo591'  '#ib_redo599'      '#ib_redo607_tmp'
'#ib_redo584'  '#ib_redo592'  '#ib_redo600'      '#ib_redo608_tmp'
'#ib_redo585'  '#ib_redo593'  '#ib_redo601'      '#ib_redo609_tmp'
'#ib_redo586'  '#ib_redo594'  '#ib_redo602'      '#ib_redo610_tmp'
'#ib_redo587'  '#ib_redo595'  '#ib_redo603_tmp'  '#ib_redo611_tmp'
'#ib_redo588'  '#ib_redo596'  '#ib_redo604_tmp'  '#ib_redo612_tmp'
'#ib_redo589'  '#ib_redo597'  '#ib_redo605_tmp'  '#ib_redo613_tmp'

每个普通redo日志文件都与特定的LSN值范围相关联;例如,以下查询显示了前一个示例中列出的活动redo日志文件的START_END_LSN值:

mysql> SELECT FILE_NAME, START_LSN, END_LSN FROM performance_schema.innodb_redo_log_files;
+----------------------------+--------------+--------------+
| FILE_NAME                  | START_LSN    | END_LSN      |
+----------------------------+--------------+--------------+
| ./#innodb_redo/#ib_redo582 | 117654982144 | 117658256896 |
| ./#innodb_redo/#ib_redo583 | 117658256896 | 117661531648 |
| ./#innodb_redo/#ib_redo584 | 117661531648 | 117664806400 |
| ./#innodb_redo/#ib_redo585 | 117664806400 | 117668081152 |
| ./#innodb_redo/#ib_redo586 | 117668081152 | 117671355904 |
| ./#innodb_redo/#ib_redo587 | 117671355904 | 117674630656 |
| ./#innodb_redo/#ib_redo588 | 117674630656 | 117677905408 |
| ./#innodb_redo/#ib_redo589 | 117677905408 | 117681180160 |
| ./#innodb_redo/#ib_redo590 | 117681180160 | 117684454912 |
| ./#innodb_redo/#ib_redo591 | 117684454912 | 117687729664 |
| ./#innodb_redo/#ib_redo592 | 117687729664 | 117691004416 |
| ./#innodb_redo/#ib_redo593 | 117691004416 | 117694279168 |
| ./#innodb_redo/#ib_redo594 | 117694279168 | 117697553920 |
| ./#innodb_redo/#ib_redo595 | 117697553920 | 117700828672 |
| ./#innodb_redo/#ib_redo596 | 117700828672 | 117704103424 |
| ./#innodb_redo/#ib_redo597 | 117704103424 | 117707378176 |
| ./#innodb_redo/#ib_redo598 | 117707378176 | 117710652928 |
| ./#innodb_redo/#ib_redo599 | 117710652928 | 117713927680 |
| ./#innodb_redo/#ib_redo600 | 117713927680 | 117717202432 |
| ./#innodb_redo/#ib_redo601 | 117717202432 | 117720477184 |
| ./#innodb_redo/#ib_redo602 | 117720477184 | 117723751936 |
+----------------------------+--------------+--------------+

在做checkpoint时,InnoDB将checkpoint LSN存储在包含该LSN的文件头中。在恢复过程中,将检查所有redo日志文件,并从最新的checkpoint LSN开始恢复。

为监控redo日志和redo日志容量resize操作提供了多个状态变量;例如,您可以查询Innodb_redo_log_resize_status以查看resize操作的状态:

mysql> SHOW STATUS LIKE 'Innodb_redo_log_resize_status';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_redo_log_resize_status | OK    |
+-------------------------------+-------+

状态变量Innodb_redo_log_capacity_resized显示当前redo日志容量限制:

mysql> SHOW STATUS LIKE 'Innodb_redo_log_capacity_resized';
 +----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| Innodb_redo_log_capacity_resized | 104857600 |
+----------------------------------+-----------+

其他适用的状态变量包括:

请查看状态变量描述以获取更多信息。

您可以通过查询innodb_redo_log_files性能_schema表来查看活动重做日志文件的信息。以下查询从表中的所有列中检索数据:

SELECT FILE_ID, START_LSN, END_LSN, SIZE_IN_BYTES, IS_FULL, CONSUMER_LEVEL 
FROM performance_schema.innodb_redo_log_files;

自动重做日志容量配置

innodb_dedicated_server启用时,InnoDB将自动配置某些InnoDB参数,包括重做日志容量。自动配置旨在为专门用于 MySQL 的服务器实例提供服务,其中 MySQL 服务器可以使用所有可用的系统资源。更多信息,请见第17.8.12节,“Enabling Automatic Configuration for a Dedicated MySQL Server”

重做日志 Archiving

备份工具可能会在备份操作进行时无法跟上重做日志生成的速度,从而导致重做日志记录被覆盖。这种问题通常发生在备份操作期间 MySQL 服务器活动较高,且重做日志文件存储媒体的速度比备份存储媒体快的情况下。重做日志 Archiving 功能通过将重做日志记录顺序写入到存档文件中来解决这个问题。备份工具可以从存档文件中复制重做日志记录,以避免数据丢失。

如果在服务器上配置了重做日志 Archiving,MySQL Enterprise Backup,可与MySQL Enterprise Edition一起使用,该备份工具将在备份 MySQL 服务器时使用重做日志 Archiving 功能。

启用服务器的redo日志归档需要设置innodb_redo_log_archive_dirs系统变量的值。该值指定为带标签的redo日志归档目录列表,使用分号 (;) 分隔。例如:

mysql> SET GLOBAL innodb_redo_log_archive_dirs='label1:directory_path1[;label2:directory_path2;…]';

标签(label)是归档目录的任意标识符,可以是任何字符串,除了冒号 (:) 之外。空标签也允许,但是仍然需要冒号 (:)。必须指定目录路径。redo日志归档文件所在目录必须存在,当启用redo日志归档时,如果不存在将返回错误。目录路径可以包含冒号 (:),但是分号 (;) 不允许。

innodb_redo_log_archive_dirs变量必须在启用redo日志归档前配置。默认值为NULL

Notes

您指定的归档目录必须满足以下要求。(这些要求将在启用redo日志归档时执行):

  • 目录必须存在。目录不会被redo日志归档进程创建。如果不存在,会返回以下错误:

    ERROR 3844 (HY000): Redo log archive directory 'directory_path1' does not exist or is not a directory

  • 目录不能是世界可访问的。这样可以防止redo日志数据被未经授权的系统用户暴露。否则,以下错误将返回:

    ERROR 3846 (HY000): redo日志归档目录'directory_path1'对所有操作系统用户可访问

  • 目录不能是由datadirinnodb_data_home_dirinnodb_directoriesinnodb_log_group_home_dirinnodb_temp_tablespaces_dirinnodb_tmpdirinnodb_undo_directorysecure_file_priv定义的目录,也不能是这些目录的父目录或子目录。否则,将返回类似以下错误:

    ERROR 3845 (HY000): redo日志归档目录'directory_path1'在、下或超出服务器目录'datadir'-'/path/to/data_directory'

当支持redo日志归档的备份工具启动备份时,该备份工具将通过调用innodb_redo_log_archive_start()函数激活redo日志归档。

如果您不使用支持redo日志归档的备份工具,可以手动激活redo日志归档,如下所示:

mysql> SELECT innodb_redo_log_archive_start('label', 'subdir');
+------------------------------------------+
| innodb_redo_log_archive_start('label') |
+------------------------------------------+
| 0                                        |
+------------------------------------------+

mysql> DO innodb_redo_log_archive_start('label', 'subdir');
Query OK, 0 rows affected (0.09 sec)
Note

激活redo日志归档的MySQL会话(使用innodb_redo_log_archive_start())必须保持打开状态直到归档完成。同样,激活redo日志归档的会话也必须使用innodb_redo_log_archive_stop()停止redo日志归档。如果会话在explicitly deactivating redo log archiving之前终止,服务器将隐式地停止redo日志归档并删除redo日志归档文件。

其中label是由innodb_redo_log_archive_dirs定义的标签;subdir是可选参数,用于指定由label标识的目录中的子目录来保存归档文件;它必须是一个简单的目录名称(不允许斜杠(/)、反斜杠(\)或冒号(:))。subdir可以为空、null或省略。

只有拥有INNODB_REDO_LOG_ARCHIVE特权的用户才能通过调用innodb_redo_log_archive_start()激活redo日志归档或使用innodb_redo_log_archive_stop()停止它。启动备份工具或手动激活和停止redo日志归档的MySQL用户必须拥有这个特权。

redo日志归档文件路径为目录标识/[子目录/]archive.serverUUID.000001.log,其中目录标识是通过label参数为innodb_redo_log_archive_start()指定的归档目录。子目录是用于innodb_redo_log_archive_start()的可选参数。

例如,redo日志归档文件的完整路径和名称将类似于以下所示:

/directory_path/subdirectory/archive.e71a47dc-61f8-11e9-a3cb-080027154b4d.000001.log

备份工具完成复制InnoDB数据文件后,将调用innodb_redo_log_archive_stop()函数来停用redo日志归档。

如果您不使用支持redo日志归档的备份工具,可以手动停用redo日志归档,如下所示:

mysql> SELECT innodb_redo_log_archive_stop();
+--------------------------------+
| innodb_redo_log_archive_stop() |
+--------------------------------+
| 0                              |
+--------------------------------+

或:

mysql> DO innodb_redo_log_archive_stop();
Query OK, 0 rows affected (0.01 sec)

stop函数完成成功后,备份工具将从归档文件中查找相关的redo日志数据,并将其复制到备份中。

备份工具完成复制redo日志数据后,不再需要redo日志归档文件,就删除该文件。

在正常情况下,删除归档文件是备份工具的责任。但是,如果redo日志归档操作突然退出前innodb_redo_log_archive_stop()函数未被调用,MySQL服务器将删除文件。

启用redo日志归档通常会由于额外写入活动而产生 minor性能成本。

在 Unix 和 Unix 类似操作系统上,性能影响通常较小,假设没有持续高的更新率。在 Windows 上,性能影响通常较高,假设相同。

如果存在持续高的更新率,并且重做日志归档文件位于同一存储媒体上,则性能影响可能会更大,因为写入活动被加剧。

如果存在持续高的更新率,并且重做日志归档文件位于比重做日志文件慢的存储媒体上,性能将受到任意影响。

将数据写入重做日志归档文件不会阻碍正常的事务日志记录,除非重做日志归档文件存储媒体的速度远低于重做日志文件存储媒体,并且存在大量已持久化的重做日志块等待被写入重做日志归档文件。在这种情况下,事务日志记录率将降低到可以由较慢的存储媒体管理的水平。

禁用重做日志

您可以使用ALTER INSTANCE DISABLE INNODB REDO_LOG语句禁用重做日志。这一功能旨在将数据加载到新 MySQL 实例中。禁用重做日志可以加速数据加载,避免重做日志写入和双写缓冲。

Warning

这项功能仅适用于将数据加载到新 MySQL 实例中。不要在生产系统上禁用重做日志。在禁用重做日志时,可以关闭并重新启动服务器,但突然的服务器停机可能会导致数据丢失和实例损坏。

在redo日志禁用时,尝试重新启动服务器可能会被拒绝,并显示以下错误信息:

[ERROR] [MY-013598] [InnoDB] Server was killed when Innodb Redo 
logging was disabled. Data files could be corrupt. You can try 
to restart the database with innodb_force_recovery=6

在这种情况下,请初始化一个新的MySQL实例,然后重新开始数据加载过程。

INNODB_REDO_LOG_ENABLE特权是启用和禁用redo日志所需的权限。

Innodb_redo_log_enabled状态变量允许监控redo日志状态。

克隆操作和redo日志归档不允许在redo日志禁用时执行,反之亦然。

ALTER INSTANCE [ENABLE|DISABLE] INNODB REDO_LOG操作需要独占备份元数据锁定,这将防止其他ALTER INSTANCE操作同时执行。其他ALTER INSTANCE操作必须等待锁定被释放后才能执行。

以下过程演示了如何在加载数据到新的MySQL实例时禁用redo日志。

  1. 在新的MySQL实例上,授予负责禁用redo日志的用户账户INNODB_REDO_LOG_ENABLE特权。

    mysql> GRANT INNODB_REDO_LOG_ENABLE ON *.* to 'data_load_admin';
  2. 作为data_load_admin用户,禁用redo日志:

    mysql> ALTER INSTANCE DISABLE INNODB REDO_LOG;
  3. 检查Innodb_redo_log_enabled状态变量,以确保redo日志已禁用。

    mysql> SHOW GLOBAL STATUS LIKE 'Innodb_redo_log_enabled';
    +-------------------------+-------+
    | Variable_name           | Value |
    +-------------------------+-------+
    | Innodb_redo_log_enabled | OFF   |
    +-------------------------+-------+
  4. 运行数据加载操作。

  5. 作为data_load_admin用户,在数据加载操作完成后启用redo日志:

    mysql> ALTER INSTANCE ENABLE INNODB REDO_LOG;
  6. 检查Innodb_redo_log_enabled状态变量,以确保redo日志已启用。

    mysql> SHOW GLOBAL STATUS LIKE 'Innodb_redo_log_enabled';
    +-------------------------+-------+
    | Variable_name           | Value |
    +-------------------------+-------+
    | Innodb_redo_log_enabled | ON    |
    +-------------------------+-------+