MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

MariaDB binlog在数据恢复中的应用

2024-05-253.6k 阅读

MariaDB binlog 基础概述

MariaDB binlog 是什么

在 MariaDB 数据库中,二进制日志(Binlog,Binary Log 的简称)是一个非常关键的组件。它记录了数据库所有改变数据的操作,包括 INSERTUPDATEDELETE 等语句,以及数据库结构更改操作,如 CREATEALTERDROP 等。与 InnoDB 存储引擎的重做日志(redo log)不同,binlog 是逻辑日志,记录的是数据库操作的逻辑形式,而重做日志是物理日志,记录的是数据库物理层面的修改。

binlog 的主要作用在于数据备份、恢复以及主从复制。当数据库出现故障或者数据丢失时,我们可以利用 binlog 中的记录将数据库恢复到故障前的某个时间点。在主从复制架构中,主库将 binlog 发送给从库,从库通过重放 binlog 来保持与主库的数据一致性。

binlog 的写入模式

MariaDB 有三种 binlog 的写入模式,通过参数 sync_binlog 来控制,该参数可以设置为 0、1 或 N(N 为正整数)。

  1. sync_binlog = 0:表示 MariaDB 不会主动将 binlog 刷写到磁盘,而是交给操作系统去决定何时将缓存数据刷盘。这种模式下写入性能最高,但如果操作系统或服务器崩溃,可能会丢失部分 binlog 记录。
  2. sync_binlog = 1:表示每次事务提交时,MariaDB 都会将 binlog 刷写到磁盘。这确保了事务的持久性,即一旦事务提交,其对应的 binlog 记录就已经安全存储在磁盘上。这种模式下数据安全性最高,但由于每次都要进行磁盘 I/O 操作,性能相对较低。
  3. sync_binlog = N:表示每 N 次事务提交后,MariaDB 将 binlog 刷写到磁盘。这种模式是在性能和数据安全性之间的一种平衡,N 的值需要根据实际业务场景和硬件性能来调整。例如,设置 sync_binlog = 10,意味着每 10 次事务提交后,才进行一次 binlog 的刷盘操作。如果在这 10 次事务提交过程中系统崩溃,那么可能会丢失这 10 次事务的 binlog 记录。

binlog 文件结构

binlog 文件由一系列的日志事件(Log Event)组成,每个日志事件记录了一个数据库操作。日志事件有不同的类型,例如 Query_log_event 用于记录 SQL 查询语句,Row_log_event 用于记录行级别的数据修改(在基于行的复制模式下)。

每个 binlog 文件都有一个文件名,格式为 hostname - binlog - index,例如 mariadb - bin.000001。其中,index 是一个自增长的数字,从 000001 开始。当当前 binlog 文件达到一定大小(由参数 max_binlog_size 控制,默认值通常为 1073741824 字节,即 1GB)或者执行 FLUSH LOGS 语句时,MariaDB 会创建一个新的 binlog 文件,并将索引值加 1。

除了 binlog 文件本身,MariaDB 还维护一个名为 master.info 的文件(在主库上),记录了当前正在使用的 binlog 文件以及文件中的偏移量等信息。在从库上,有 relay - log.info 文件,用于记录从库复制过程中相关的中继日志信息。

MariaDB binlog 在数据恢复中的原理

基于时间点恢复(Point - in - Time Recovery, PITR)

基于时间点恢复是 MariaDB 使用 binlog 进行数据恢复的一种重要方式。其原理是通过备份数据(通常是全量备份)和 binlog 记录,将数据库恢复到某个特定的时间点。

假设我们有一个在 T0 时刻的全量备份,以及从 T0T1 时刻产生的 binlog 记录。当数据库在 T1 之后出现故障需要恢复时,我们可以首先将全量备份恢复到数据库。然后,通过重放 T0T1 之间的 binlog 记录,将数据库逐步恢复到 T1 时刻的状态。

具体实现过程如下:

  1. 恢复全量备份:使用备份工具(如 mariabackup 等)将全量备份的数据文件恢复到数据库的数据目录。这一步会将数据库恢复到备份时刻的状态。
  2. 重放 binlog:根据备份记录中记录的 binlog 位置信息,从备份时刻对应的 binlog 文件和偏移量开始,依次重放后续的 binlog 文件中的日志事件,直到达到目标恢复时间点或者最新的 binlog 记录。

基于位置恢复(Recovery Based on Position)

除了基于时间点恢复,还可以基于 binlog 中的位置信息进行恢复。在 MariaDB 的主从复制过程中,主库会记录每个事务在 binlog 中的位置(通常用文件名和偏移量表示)。当从库出现故障需要恢复时,可以根据主库提供的 binlog 位置信息,从该位置开始重放 binlog,从而恢复到与主库一致的状态。

例如,主库向从库发送 binlog 记录时,会告知从库当前 binlog 文件的名称(如 mariadb - bin.000005)以及事务在该文件中的偏移量(如 123456)。从库在故障恢复后,可以利用这些位置信息,找到对应的 binlog 文件并从指定偏移量开始重放 binlog,以实现数据恢复和与主库的同步。

这种基于位置恢复的方式在主从复制架构的维护和故障处理中非常有用,能够快速准确地恢复从库的数据,减少数据不一致的风险。

启用和配置 MariaDB binlog

启用 binlog

在 MariaDB 中,启用 binlog 非常简单,只需要在配置文件(通常是 /etc/mysql/my.cnf/etc/mariadb.cnf)中添加或修改以下配置项:

[mysqld]
log - bin = /var/log/mysql/mariadb - bin

上述配置中,log - bin 参数指定了 binlog 文件的存储路径和文件名前缀。/var/log/mysql/mariadb - bin 表示 binlog 文件将存储在 /var/log/mysql 目录下,文件名为 mariadb - bin.000001mariadb - bin.000002 等依次递增。

配置完成后,重启 MariaDB 服务使配置生效:

sudo systemctl restart mariadb

配置 binlog 相关参数

  1. max_binlog_size:该参数用于设置单个 binlog 文件的最大大小,默认值为 1073741824 字节(1GB)。如果希望修改该值,可以在配置文件中添加:
[mysqld]
max_binlog_size = 536870912 # 设置为 512MB
  1. sync_binlog:如前文所述,该参数控制 binlog 的写入模式。如果希望设置为每次事务提交都刷盘,可以在配置文件中添加:
[mysqld]
sync_binlog = 1
  1. binlog_format:该参数用于设置 binlog 的格式,有三种取值:STATEMENTROWMIXED
    • STATEMENT:基于语句的格式,binlog 记录的是执行的 SQL 语句。这种格式优点是日志量小,但在某些情况下(如使用函数 NOW() 等)可能导致主从复制数据不一致。
    • ROW:基于行的格式,binlog 记录的是每一行数据的修改。这种格式优点是数据一致性好,但日志量较大。
    • MIXED:混合模式,MariaDB 会根据 SQL 语句的情况自动选择使用 STATEMENTROW 格式记录 binlog。 例如,要设置为基于行的格式,可以在配置文件中添加:
[mysqld]
binlog_format = ROW
  1. expire_logs_days:该参数用于设置 binlog 文件的过期天数,超过指定天数的 binlog 文件会被自动删除。例如,设置为 7 天:
[mysqld]
expire_logs_days = 7

查看和管理 MariaDB binlog

查看 binlog 状态

可以使用 SHOW BINARY LOGS 语句来查看当前数据库的 binlog 文件列表:

SHOW BINARY LOGS;

该语句会返回一个结果集,包含 binlog 文件的名称和文件大小等信息,例如:

+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mariadb - bin.000001 | 1073741824 |
| mariadb - bin.000002 | 536870912  |
+------------------+-----------+

使用 SHOW MASTER STATUS 语句可以查看当前正在使用的 binlog 文件以及文件中的偏移量:

SHOW MASTER STATUS;

返回结果类似:

+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mariadb - bin.000002 | 123456   |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

清理 binlog

  1. 手动清理:可以使用 PURGE BINARY LOGS 语句手动清理 binlog 文件。例如,要删除所有早于 mariadb - bin.000003 的 binlog 文件,可以执行:
PURGE BINARY LOGS TO'mariadb - bin.000003';
  1. 自动清理:如前文所述,通过设置 expire_logs_days 参数,MariaDB 会自动删除过期的 binlog 文件。系统会定期检查 binlog 文件的创建时间,超过 expire_logs_days 天数的文件会被删除。

备份 binlog

为了确保在数据恢复过程中有完整的 binlog 记录可用,需要对 binlog 进行备份。一种常见的方法是使用 mysqlbinlog 工具将 binlog 文件导出为文本格式进行备份。例如,要备份 mariadb - bin.000001 文件,可以执行:

mysqlbinlog /var/log/mysql/mariadb - bin.000001 > /backup/mariadb - bin.000001.sql

上述命令将 mariadb - bin.000001 文件内容导出为 sql 格式,并保存到 /backup 目录下。在恢复数据时,可以使用 mysql 命令来执行这个备份的 sql 文件,重放 binlog 记录。

MariaDB binlog 数据恢复实战

准备测试环境

  1. 安装 MariaDB:在 Linux 系统上,可以使用包管理器安装 MariaDB,例如在 CentOS 上:
sudo yum install mariadb - server mariadb - client
sudo systemctl start mariadb
sudo systemctl enable mariadb
  1. 创建测试数据库和表:登录到 MariaDB 数据库:
mysql - u root - p

然后创建一个测试数据库和表,并插入一些数据:

CREATE DATABASE test_db;
USE test_db;
CREATE TABLE test_table (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50));
INSERT INTO test_table (name) VALUES ('Alice'), ('Bob'), ('Charlie');

进行全量备份

使用 mariabackup 工具进行全量备份。首先确保 mariabackup 工具已安装,在 MariaDB 官方仓库中有提供。

mariabackup --backup --target - dir=/backup/full_backup

上述命令会将数据库的数据文件备份到 /backup/full_backup 目录下。备份完成后,可以看到备份目录中包含数据文件、日志文件以及备份元数据文件等。

模拟数据丢失

假设在备份后,我们不小心删除了 test_table 表:

USE test_db;
DROP TABLE test_table;

基于 binlog 恢复数据

  1. 恢复全量备份:首先将全量备份恢复到数据库:
mariabackup --prepare --target - dir=/backup/full_backup
mariabackup --copy - back --target - dir=/backup/full_backup
sudo chown - R mysql:mysql /var/lib/mysql
sudo systemctl restart mariadb
  1. 重放 binlog:找到备份时记录的 binlog 位置信息(通常在备份元数据文件中),假设备份时的 binlog 文件为 mariadb - bin.000001,偏移量为 123456。然后使用 mysqlbinlog 工具和 mysql 命令重放 binlog:
mysqlbinlog --start - position=123456 /var/log/mysql/mariadb - bin.000001 | mysql - u root - p

上述命令会从指定的 binlog 位置开始重放 binlog 记录,直到文件末尾。执行完成后,登录到 MariaDB 数据库检查,会发现 test_table 表以及数据已经恢复。

恢复到指定时间点

假设我们希望恢复到删除表操作之前的某个时间点,例如 2023 - 10 - 01 12:00:00

  1. 获取 binlog 记录时间:可以使用 mysqlbinlog 工具查看 binlog 记录中的时间信息。例如:
mysqlbinlog --verbose /var/log/mysql/mariadb - bin.000001 | grep '2023 - 10 - 01 12:00:00'

通过查看详细的 binlog 记录,找到在该时间点之前的 binlog 位置信息,假设为 mariabackup - bin.000001 文件的偏移量 234567。 2. 恢复全量备份和重放 binlog:与前面恢复数据的步骤类似,先恢复全量备份:

mariabackup --prepare --target - dir=/backup/full_backup
mariabackup --copy - back --target - dir=/backup/full_backup
sudo chown - R mysql:mysql /var/lib/mysql
sudo systemctl restart mariadb

然后重放 binlog 到指定位置:

mysqlbinlog --stop - position=234567 /var/log/mysql/mariabackup - bin.000001 | mysql - u root - p

这样就可以将数据库恢复到 2023 - 10 - 01 12:00:00 这个时间点的状态,test_table 表以及数据会被恢复,而删除表的操作不会被重放。

数据恢复过程中的常见问题及解决方法

binlog 损坏

  1. 原因:硬件故障、软件错误或者异常断电等情况可能导致 binlog 文件损坏。
  2. 解决方法:如果 binlog 文件损坏,可以尝试使用 mysqlbinlog 工具的 --no - default - values 选项来尝试解析损坏的 binlog 文件。例如:
mysqlbinlog --no - default - values /var/log/mysql/mariadb - bin.000001 > repaired_binlog.sql

然后检查 repaired_binlog.sql 文件,手动修复其中错误的记录(如果可能的话)。另外,如果有 binlog 备份,可以使用备份的 binlog 文件进行恢复。

恢复数据不一致

  1. 原因:binlog 格式设置不当(如在 STATEMENT 格式下使用了某些不确定的函数)、主从复制延迟导致 binlog 重放顺序错误等都可能导致恢复数据不一致。
  2. 解决方法:确保在主从复制环境中,主库和从库的 binlog_format 设置一致,并且尽量使用 ROW 格式以保证数据一致性。在恢复数据时,仔细检查 binlog 记录的顺序和内容,确保重放过程正确。如果发现数据不一致,可以尝试从备份点重新恢复,并仔细分析重放过程中的错误信息。

重放 binlog 报错

  1. 原因:重放 binlog 报错可能是由于数据库版本差异、语法错误或者数据结构不一致等原因导致。例如,在高版本数据库上生成的 binlog 记录,在低版本数据库上重放可能会因为语法不兼容而报错。
  2. 解决方法:首先检查报错信息,确定错误原因。如果是数据库版本差异问题,可以尝试在相同版本的数据库环境中进行恢复。如果是语法错误,可以手动修改 binlog 记录中的 SQL 语句(在备份的 binlog 文件中),然后重新重放。对于数据结构不一致问题,需要根据实际情况调整数据库结构,使其与 binlog 记录中的操作相匹配后再进行重放。

通过深入理解 MariaDB binlog 的原理、正确配置和管理 binlog,以及熟练掌握基于 binlog 的数据恢复方法,我们能够在面对数据库故障和数据丢失等问题时,有效地恢复数据,保障数据库的可用性和数据完整性。在实际应用中,还需要结合具体的业务场景和需求,制定合理的备份和恢复策略,以应对各种可能出现的数据风险。同时,不断关注 MariaDB 的更新和改进,及时调整和优化 binlog 相关的配置和操作,以适应数据库环境的变化。