目录
[一. 二进制日志](#一. 二进制日志)
[1.2 作用](#1.2 作用)
[1.3 配置](#1.3 配置)
[1.4. 磁盘文件](#1.4. 磁盘文件)
[1.5 过期时间------binlog_expire_logs_seconds](#1.5 过期时间——binlog_expire_logs_seconds)
[1.6 日志格式------binlog_format](#1.6 日志格式——binlog_format)
[1.7 刷盘策略------sync_binlog](#1.7 刷盘策略——sync_binlog)
[2.2 常用选项](#2.2 常用选项)
[2.3 binlog内容的格式](#2.3 binlog内容的格式)
[2.4 数据准备](#2.4 数据准备)
[2.5 查看binlog](#2.5 查看binlog)
[2.6 简单数据恢复](#2.6 简单数据恢复)
[2.7 远程备份binlog日志(了解)](#2.7 远程备份binlog日志(了解))
- 本专题目标
了解MySQL包含的日志类型
掌握二进制日志的作用
掌握二进制日志的相关配置,包括:
- 输出位置
- 过期时间
- 日志格式
- 刷盘策略
掌握二进制日志在磁盘上的命名规则
掌握通过SQL语句刷新和删除二进制日志的方法
掌握通过mysqlbinlog工具解析并查看二进制日志
掌握二进制日志内容的格式
掌握如何通过二进制日志恢复数据
了解数据库备份的作用
了解数据库备份的分类以及特点
掌握制定备份策略时的注意事项
掌握如何制定一份适合业务系统的备份策略
掌握mysqldump工具的应用场景
掌握mysqldump工具的使用方法和注意事项
掌握如何通过mysqldump工具进行数据库备份
掌握如何通过mysqldump工具进行数据库恢复
掌握在生产环境通过mysqldump工具进行数据库备份与恢复的完整流程
掌握通过SQL语句进行数据导入导出的方法
掌握通过使用mysqlimport工具将数据导入数据库
掌握物理备份工具Xtrabackup的使用场景
掌握物理备份工具Xtrabackup的下载和安装
掌握通过Xtrabackup进行全量备份与数据恢复
掌握通过Xtrabackup进行增量备份与数据恢复
- 本专题可以解决的问题(面试题)
-
知道MySQL有哪些日志吗?
-
介绍一下MySQL日志的作用是什么?
-
二进制日志的作用是什么?
-
如何开启二进制日志?
-
二进制日志常见的配置选项有哪些?
-
二进制日志的刷盘策略有几种?说一下它们的区别?
-
如何查看二进制日志?
-
了解数据库备份吗?
-
数据库备份的分类有哪些?
-
什么是逻辑备份和物理备份?
-
什么是冷备、热备和温备?
-
什么是全量备份和增量备份?
-
进行数据库备份时应注意什么?
-
mysqldump用过吗?
-
介绍一下mysqldump的应用场景和使用方法?
-
使用mysqldump进行数据备份时会出现数据一致问题吗?如何解决?
-
如果让你执行数据库备份,说一下从开始准备到备份结束的完整流程或者进行哪些操作?
-
MySQL中如何进行备份数据导入?
-
还了解关于MySQL的其他备份方式吗?
-
Xtrabackup工具用过吗?介绍下它的特点?
-
如何通过Xtrabackup进行全量或增量备份和数据恢复?
3.MySQL日志有哪些?
MySQL Server有以下几种日志,可以记录MySQL服务器正在发生的活动
日志类型 | 日志信息 |
---|---|
重做日志(Redo log) | 用于事务的提交和崩溃时恢复数据 |
回滚日志(Undo log) | 用于事务回滚,回滚日志是事务回滚的依据 |
错误日志 (Error log) | mysqld 在启动、运行或停止时遇到的问题 |
一般查询日志 (General query log) | 已建立的客户端连接和从客户端接收到的语句 |
慢查询日志 (Slow query log) | 执行时间超过 long_query_time 指定秒数的查询 |
二进制日志 (Binary log) | 更改数据的语句(也用于主从复制) |
中继⽇志(Relaylog) | 从源服务器接收到的数据更改 |
- 重做日志,回滚日志可以参考存储引擎专题中的相关内容
- 错误日志,一般查询日志,慢查询日志的介绍可以参考服务器配置与管理专题中的日志内容
一. 二进制日志
1.1.介绍
二进制日志(Binary Log,简称 binlog)是 MySQL 数据库中最为关键 的日志之一。它以离散的"事件" 形式,精准记录 所有对数据库结构或数据进行修改的操作,包括数据定义语言 (DDL) 语句(例如 CREATE
, ALTER
, DROP
)和数据操作语言 (DML) 语句(例如 INSERT
, UPDATE
, DELETE
)。典型的记录内容包括但不限于表的创建、修改以及表数据的变更历史。
需要明确的是,二进制日志通常不会记录不修改数据的操作,如 SELECT 查询或 SHOW 命令。
除了记录操作本身,二进制日志还包含了重要的元数据 ,例如每个修改语句执行时消耗的时间信息(当 binlog_rows_query_log_events
开启时,甚至可能包含原始 SQL 语句)。
启用二进制日志是 MySQL 实现数据复制(Replication)和基于时间点恢复(Point-in-Time Recovery, PITR)两大核心功能的基石。 它允许将一个服务器(主库)上的变更同步到一个或多个其他服务器(从库),也使得数据库能够恢复到任意一个包含在 binlog 中的历史状态(配合全量备份)。
启用二进制日志功能会引入额外的磁盘 I/O 操作,因此可能带来轻微的性能开销。管理员需要权衡其带来的数据安全性与复制能力与性能影响。
二进制日志文件在以下情况下会自动切换,生成新的日志文件序列:
-
MySQL 服务器重启时。
-
用户显式执行
FLUSH LOGS
命令时。 -
当前日志文件大小达到配置参数
max_binlog_size
指定的阈值时。
1.2 作用
- **主从节点数据复制:**从节点服务器读取主节点服务器上的二进制日志文件,并根据二进制日志中记录的事件在从节点上执行相同的操作,保证主从节点服务器上数据一致,实现数据复制功能,并于数据复制。
- **数据恢复:**重新执行记录在二进制日志中的事件,可以完成任一事务之前的数据恢复。
1.3 配置
二进制日志相关系统变量
默认binlog自动开启,可以查看相看系统变量
sql
show variables like '%log_bin%'; #查看包含log_bin的配置

指定二进制日志的路径和文件名
选项 --log-bin[=base_name] 用于指定二进制日志文件的基本名称,如果不指定 --log-bin 选项,默认基本名称为 binlog ,建议为二进制日志指定一个基本名;
二进制日志文件和索引文件的默认保存位置是数据目录。

可以通过配置选项文件对默认值进行配置,使用 --log-bin[=file_name] 选项指定自定义路径,file_name 格式 = 绝对路径+基本名。--log-bin 对应的系统变量是 log_bin_basename。如果指定了自定义路径,那么需要为自定义目录设置适当权限
sql
vim /etc/mysql/my.cnf #编辑选项文件
打开这个文件

我们在[mysqld]节点下面添加下面这个即可
bash
# MySQL 服务节点
[mysqld]
# 配置自定义的二进制日志的基本文件名,可以是绝对路径(生产环境),也可以是相对路径(数据目录下)
log_bin=/var/lib/mysql/binlog
保存退出之后,我们执行下面这个
bash
systemctl restart mysql
重启之后,我们还得检查一下有没有在运行
bash
systemctl status mysql
然后我们重新进去看看

我们也可以回到数据目录下面看看
我们发现多了一个binlog.000014,这是因为修改配置文件之后重启mysql服务,生成了一个新的二进制日志文件
关闭二进制日志
- 永久关闭
我们还是可以 通过配置文件
sql
vim /etc/mysql/my.cnf #编辑选项文件
然后在[mysqld]节点下面添加下面两个中任意一个即可关闭二进制日志文件 。
bash
skip-log-bin
# 或,任选其一
disable-log-bin
注意:禁用二进制日志,skip-log-bin或disable-log-bin 要配置在log_bin的后面
- 临时关闭二进制日志
bash
-- 关闭会话级别是否开启二进制日志
set session sql_log_bin = 0;
show variables like '%log_bin%';

只能关闭会话级别,不能关闭全局的二进制日志,如果关闭全局二进制日志要通过选项文件设置
1.4. 磁盘文件
文件名规则
MySQL 二进制日志文件的命名遵循 <basename>.<sequence_number>
的格式:
-
<basename>
:这是二进制日志文件的基础名称,由配置文件中的log_bin_basename
参数(或在旧版本中是log_bin
参数)指定。如果未显式配置,通常默认为主机名后跟-bin
(例如myserver-bin
)。 -
<sequence_number>
:这是一个由 MySQL 自动维护并严格递增的数字序列 (通常以6
位数字表示,如000001
,000002
),作为文件的扩展名。这个序列号保证了日志文件在时间维度上的严格顺序性,这对于日志的正确解析、数据复制和基于时间点的恢复至关重要。
新的二进制日志文件创建时机
MySQL 服务器会在以下任一情况发生时,自动创建一个新的二进制日志文件(序列号递增):
-
服务器启动或重启: 每当 MySQL 服务启动(包括首次启动)或重新启动时,都会创建一个新的日志文件,序列号增加。
-
日志刷新命令执行: 当用户显式执行
FLUSH BINARY LOGS
或FLUSH LOGS
命令时,会立即关闭当前日志文件并创建一个新文件。 -
当前日志文件达到最大尺寸限制: 当正在写入 的二进制日志文件的大小达到
max_binlog_size
系统变量所定义的阈值时,服务器会自动切换到新的日志文件。需要注意:-
max_binlog_size
定义了单个二进制日志文件的最大允许字节数。 -
其最小值 为
4096
字节(4KB)。 -
其最大值 和默认值 均为
1GB
(1073741824 字节)。 -
重要说明: 如果一个事务的写入量非常大,以至于其单个语句或事件本身就需要超过
max_binlog_size
的空间,MySQL 为了保证事务的原子性 ,会允许该事务完整地 写入当前日志文件,即使这会导致**实际二进制日志文件大小暂时超过max_binlog_size
。**只有在该事务提交完成后,才会在下一次写入时创建新的日志文件。
-
多说无益,我们来见一见。
服务器启动或重启时会创建一个新的二进制日志文件
每当 MySQL 服务启动(包括首次启动)或重新启动时,都会创建一个新的日志文件,序列号增加。这个情况,我们在上面这个小节就已经验证过了。

日志刷新命令执行时会创建一个新的二进制日志文件
我们看看

刷新二进制日志的命令如下
bash
flush binary logs;


删除二进制日志文件
可以使用RESET MASTER 语句删除所有二进制日志文件,或者使用 PURGE binary LOGS 删除一部分二进制日志文件,具体演示:
bash
# 删除指定日志文件之前的所有日志文件并更新索引
PURGE BINARY LOGS TO 'binlog.000010';
# 删除指定时间之前的所有日志文件并更新索引
PURGE BINARY LOGS BEFORE '2024-10-02 22:56:26'
# 重置二进⾏日志文件和索引文件为初始状态
RESET MASTER;
我们来看看
删除指定日志文件之前的所有日志文件并更新索引
删除之前

bash
# 删除指定日志文件之前的所有日志文件并更新索引
PURGE BINARY LOGS TO 'binlog.000014';

删除之后

重置二进制日志
执行前

bash
# 重置二进⾏日志文件和索引文件为初始状态
RESET MASTER;


执行之后我们发现二进制日志从1重新开始了
1.5 过期时间------binlog_expire_logs_seconds
在选项文件中配置**`binlog_expire_logs_seconds`**可以设置二进制日志的过期时间,单位为秒,默认2592000秒,即30天。二进制日志文件过期后,会自动删除。
bash
vim /etc/mysql/my.cnf # 编辑选项文件
我们在配置文件添加下这个
bash
# MySQL 服务节点
[mysqld]
# 配置自定义的二进制日志的基本文件名,可以是绝对路径(生产环境),也可以是相对路径(数据目录下)
log_bin=/var/lib/mysql/binlog
# 指定二进制日志的过期时间
binlog_expire_logs_seconds=2592000
保存退出之后,需要重启mysql服务
bash
systemctl restart mysql
systemctl status mysql

这个时候我们重新登陆mysql去查看系统变量
bash
show variables like '%bin%';

1.6 日志格式------binlog_format
记录二进制日志时使用的格式有以下三种:
格式 | 说明 |
---|---|
STATEMENT | 基于 SQL 语句记录日志 |
ROW | 基于表中受影响的行记录日志 |
MIXED | 基于语句格式与行格式的混合模式记录日志 |
MySQL 提供了三种不同的二进制日志格式,用于记录数据库的变更。格式的选择直接影响数据复制(Replication)的行为、安全性、性能以及日志文件的大小。
可以通过设置系统变量binlog_format (例如 SET GLOBAL binlog_format = 'ROW'
; 或在启动时使用 --binlog-format=xxx
选项) 来指定格式。
1.基于语句的日志格式 (Statement-Based Logging, SBL)
-
工作原理: 这是 MySQL 最初 实现复制时采用的格式。在这种格式下,二进制日志记录的是实际执行的、修改数据的 SQL 语句本身(例如
UPDATE users SET balance = balance - 100 WHERE id = 5;
)。 -
启用方式: 设置binlog_format
= 'STATEMENT'
。 -
优点:
-
生成的日志文件通常较小,因为只记录语句文本。
-
便于人工阅读和理解日志内容。
-
某些模式的数据修改(如影响大量行的
UPDATE
或DELETE
)记录效率可能更高。
-
-
缺点与风险:
-
非确定性语句风险: 这是最主要的问题。如果 SQL 语句的执行结果依赖于上下文环境(如当前时间
NOW()
、随机数RAND()
、会话变量@@session_var
、非确定性函数UUID()
、USER()
、LOAD_FILE()
等),或者依赖于表中特定的数据顺序(例如使用了LIMIT
但没有ORDER BY
),在主库上执行的结果可能与在从库上重放时产生的结果不一致 ,导致主从数据差异。 -
某些特殊操作(如使用
LOAD DATA INFILE
)需要额外的日志文件支持。
-
2.基于行的日志格式 (Row-Based Logging, RBL) - (默认)
-
工作原理: 在这种格式下,二进制日志记录的是表中哪些数据行被修改了,以及这些行修改前(可选)和修改后的具体数据值 。它记录的是行级别的变更事件,而不是原始的 SQL 语句。
-
启用方式: 设置 binlog_format
= 'ROW'
。这是 MySQL 5.7.7 及以后版本的默认日志格式。 -
优点:
-
最高的数据一致性保证: 这是其成为默认格式的核心原因。由于记录的是行的实际变更结果,重放时不受上下文环境或非确定性函数的影响,能够最可靠地保证主从数据库的数据完全一致 。因为记录的是真实的值,在数据同步中保证了数据的一致性。
-
安全地复制所有类型的语句(包括非确定性语句和
LOAD DATA INFILE
)。
-
-
缺点:
-
生成的日志文件通常较大 ,尤其是当一条语句修改了大量行时(例如
UPDATE large_table SET column = 1;
),因为需要为每一行变更记录数据。 -
日志内容不易直接阅读(通常需要借助
mysqlbinlog
工具配合-v
或--verbose
选项解析)。 -
某些大量行更新的语句,其日志量可能显著高于 STATEMENT 格式。
-
3.混合日志记录格式 (Mixed Logging, MIXED)
-
工作原理: 这种格式旨在结合 SBL 和 RBL 的优点。默认情况下,它使用基于语句的格式 (SBL) 来记录变更。 但是,MySQL 服务器会智能地判断 当前执行的语句是否安全 (即是否可能产生非确定性的结果或在从库上导致不一致)。如果 MySQL 检测到潜在的风险 (例如语句中使用了
UUID()
,RAND()
,USER()
,LOAD_FILE()
等非确定性函数,或者使用了INSERT ... SELECT
且涉及不确定的ORDER BY
/LIMIT
),它会自动且透明地将该特定语句切换到基于行的格式 (RBL) 进行记录。 -
启用方式: 设置 binlog_format
= 'MIXED'
。 -
目标: 在保证绝大多数安全语句能利用 SBL 格式(日志小、效率可能高)的同时,自动规避 SBL 固有的数据一致性风险。它试图在日志大小/性能和安全性之间取得一个平衡。
-
注意: 虽然 MIXED 格式减少了完全使用 RBL 的日志大小,但日志大小仍然可能波动,因为它包含两种格式的记录。管理员仍需监控日志增长。
设置二进制日志格式
bash--binlog-format=[STATEMENT|ROW|MIXED]
在生产环境中我们建议使用ROW格式,因为一般我们需要binlog来做更多的操作,比如数据同步和日志解析;Mixed混合模式日志处理有些困难,很多同步工具无法使用
配置日志格式
我们还是去
bash
vim /etc/mysql/my.cnf #编辑选项文件
bash
# MySQL 服务节点
[mysqld]
# 配置自定义的二进制日志的基本文件名,可以是绝对路径(生产环境),也可以是相对路径(数据目录下)
log_bin=/var/lib/mysql/binlog
# 指定二进制日志的过期时间
binlog_expire_logs_seconds=2592000
# 指定二进制日志格式为ROW
binlog_format=ROW

保存退出之后我们还需要重启mysql
bash
systemctl restart mysql
systemctl status mysql

这个时候我们可以重新登陆mysql去查看系统变量
bash
show variables like '%bin%';

1.7 刷盘策略------sync_binlog
首先看一下MySQL binlog缓存、操作系统缓存和磁盘中二进制日志文件的关系,如图所示:

MySQL二进制日志的刷盘过程
当执行 INSERT/UPDATE/DELETE 等 DML 语句或 CREATE/ALTER 等 DDL 语句时,MySQL 会生成对应的二进制日志事件(以离散的"事件"形式记录变更逻辑及数据差异)。
这些事件首先写入线程私有的 binlog 内存缓存区(每个客户端线程独立分配,大小由 binlog_cache_size 控制),以此缓冲写入压力、提升并发性能;
当事务提交(COMMIT)时,缓存中的事件通过 write() 系统调用批量写入操作系统的 Page Cache(内核态内存缓冲区),此时数据尚未持久化,存在操作系统崩溃丢失的风险;
最终,由 sync_binlog 参数控制刷盘机制,将 Page Cache 中的数据强制写入磁盘上的 binlog 文件(如 binlog.000002),完成持久化。
sync_binlog系统变量
sync_binlog是一个至关重要的 MySQL 系统变量,它直接控制着二进制日志 (binlog) 从 MySQL Server 的内部缓存 (binlog cache) 持久化到磁盘文件的时机和频率 。这个设置是性能与数据安全/一致性之间权衡的关键点,尤其是在发生操作系统崩溃或 MySQL 进程异常终止 (crash) 时,它决定了可能丢失的事务数量。
配置选项与影响
sync_binlog可以设置为以下值,每种设置对应不同的行为、风险和性能表现:
-
sync_binlog**
= 0
(操作系统控制)**-
行为: MySQL 不主动调用
fsync()
系统调用 来强制将 binlog 缓存写入磁盘。何时将缓存数据真正写入物理磁盘完全由操作系统的 I/O 调度策略和文件系统自身的刷新机制决定(通常依赖于write()
调用和后台刷盘线程)。 -
当 sync_binlog**= 0时,MySQL先将产生的二进制日志写入操作系统的缓存,什么时候刷入磁盘完全由操作系统决定。**
-
优点: 性能最佳 。因为避免了频繁的
fsync()
调用(这是一个相对昂贵的阻塞操作),事务提交延迟最低,吞吐量最高。 -
风险: 数据丢失风险最大 。如果操作系统或 MySQL 服务器进程崩溃,所有尚未被操作系统刷新到磁盘的 binlog 事件(即仍在 binlog cache 或操作系统 Page Cache 中的事件)都会永久丢失 。这意味着即使事务在 MySQL 层面已经提交(
COMMIT
),如果对应的 binlog 事件丢失,这些提交的事务也无法被复制到从库或用于基于时间点的恢复 (PITR)。这可能导致主库和从库之间出现严重的数据不一致。
-
-
sync_binlog**
= 1
(每次提交同步)**-
行为: 每次事务成功提交 (
COMMIT
) 时 ,MySQL 在返回成功给客户端之前,会先调用fsync()
确保该事务产生的所有 binlog 事件都被物理写入并持久化到磁盘。 -
当sync_binlog = 1,每次事务成功提交 (COMMIT) 时,MySQL先将产生的二进制日志写入操作系统的缓存,然后里面刷新到磁盘里面。
-
优点: 数据安全性最高 。即使操作系统或 MySQL 进程崩溃,只要事务提交成功,其对应的 binlog 事件就一定已写入磁盘。这为数据复制和 PITR 提供了最坚实的保障,最大程度地保证了主库与从库的数据一致性以及崩溃恢复后的数据完整性 。这也是实现 "双一模式" (
innodb_flush_log_at_trx_commit=1
+sync_binlog=1
) 的关键组成部分,是金融级应用或对数据一致性要求极高的场景的标配。 -
缺点: 性能开销最大 。频繁的
fsync()
调用(每个事务一次)会显著增加 I/O 负载和事务提交延迟,从而降低系统的整体吞吐量。在高并发写入场景下,性能影响尤为明显。
-
-
sync_binlog**
= N
(N > 1
,N次提交同步)**-
行为: MySQL 会在每成功提交
N
个事务后 ,调用一次fsync()
将累积的 binlog 事件批量刷新到磁盘。N
是一个正整数 ,其有效范围通常是1
到4294967295
。 -
当sync_binlog = N,每成功提交 N 个事务后,MySQL先将产生的二进制日志写入操作系统的缓存,然后里面刷新到磁盘里面。
-
优点: 在安全性和性能之间取得折衷 。相比
sync_binlog=1
,显著减少了fsync()
的调用次数,降低了 I/O 压力,提高了系统吞吐量和事务处理能力。 -
风险: 牺牲了一定的数据安全性 。如果 MySQL 在成功提交了
M
(M < N
) 个事务但尚未达到N
次提交阈值(即尚未调用fsync
)时发生崩溃,那么最后这M
个已提交事务对应的 binlog 事件将会丢失 。这同样会导致主从数据不一致和 PITR 无法恢复这些事务。风险程度取决于N
的大小和崩溃发生的时机。 -
配置建议: 这个值
N
没有放之四海而皆准的最佳设置 。它必须根据具体的业务场景、硬件性能(特别是磁盘 IOPS)、可容忍的数据丢失量(RPO - Recovery Point Objective)进行仔细的评估和充分的性能测试 。需要权衡提高性能的收益与潜在丢失最多N-1
个事务的风险。
-
生产环境推荐
-
对数据一致性要求极高的场景 (如金融交易、核心业务系统): 强烈推荐设置 sync_binlog = 1。 这是保障数据安全性和主从一致性的黄金标准,配合
innodb_flush_log_at_trx_commit=1
构成"双一模式"。虽然会带来性能损耗,但这是为数据安全付出的必要代价。应优先考虑通过优化硬件(如使用带电池保护写缓存的 RAID 控制器、NVMe SSD)或调整其他参数来缓解性能压力。 -
对数据一致性要求稍低,或性能压力极大的场景: 可以考虑设置
sync_binlog = N
(N > 1
)。但务必:-
明确评估并接受最多丢失
N-1
个事务的风险(RPO)。 -
经过严格的性能测试和稳定性测试 ,找到一个既能有效提升性能,又能将数据丢失风险控制在可接受范围内的
N
值(例如 100, 1000)。切勿随意设置过大的N
值。
-
-
sync_binlog = 0
: 通常不推荐在生产环境使用,除非是纯日志类、可容忍较大数据丢失的非关键业务,且对性能有极端要求。使用时必须充分意识到其高风险。
我们可以去看看我们当前的刷盘策略
bash
show variables like '%bin%';

1.8.常用操作
sql
-- 查看binlog是否开启
show variables like '%log_bin%';
select @@log_bin;

sql
-- 查看binlog的路径
select @@log_bin_basename;

sql
-- 查看binlog的格式
select @@binlog_format;

sql
-- 查看刷盘策略
select @@sync_binlog;

sql
-- 刷新所有日志
flush logs;
-- 刷新二进制日志
flush binary logs;
sql
-- 查看当前服务器使用的binlog文件及大小
show binary logs;

sql
-- 查看最新的binlog文件名和position
show master status;

sql
-- 查看binlog中的事件
show binlog events [IN 'log_name'] [FROM pos] [LIMIT row_count];
show binlog events in 'binlog.000051' from 676 limit 3;

sql
-- 重置二进制日志文件和索引文件为初始状态
reset master;
-- 删除指定日志文件之前的所有日志文件并更新索引
purge binary logs to 'binlog.000010';
-- 删除指定时间之前的所有日志文件并更新索引
purge binary logs before '2024-05-02 22:56:26'
sql
-- 查看服务器ID
select @@server_id;

二.mysqlbinlog工具
2.1.作用
这个mysqlbinlog是跟着mysql一起安装到我们的系统里面的
用来解析二进制日志的实用工具,可以通过 ls /usr/bin/mysql* 查看

2.2 常用选项
mysqlbinlog 有如下常用选项,可以在命令行中指定,也可以在选项文件中通过 [mysqlbinlog] 和 [client] 组进行指定
选项 | 说明 |
---|---|
--base64-output |
--base64-output=value 将 BINLOG 中的事件用 base-64 进行编码(value 的取值需特殊说明)。 |
--database |
只查看指定数据库的日志。 |
--no-defaults |
不读取选项文件。所有的客户端程序在启动时都会先去选项文件里面读取[client]节点,并加载节点下的配置。如果读取二进制日志时如果字符编码集是utf8mb4就有可能产生乱码。如果说我们不希望mysqlbinlog启动时读取这个配置,我们就可以使用这个 |
--offset, -o |
--offset=N, -o N 跳过日志中的前 N 条记录。 |
--raw |
以原始二进制格式写入事件(默认是文本格式)。 |
--read-from-remote-server, -R |
--read-from-remote-server=file_name, -R 读取远程 MySQL 服务器的二进制日志,要求远程服务器正在运行。 |
--require-row-format |
基于行格式的二进制日志记录格式。 |
--result-file, -r |
--result-file=name, -r name 指定输出的目标文件。 |
--server-id |
仅显示指定服务器 ID 创建的事件。 |
--skip-gtids |
输出转储文件时不包含二进制日志文件中的 GTID。 |
--start-datetime |
--start-datetime=datetime 从等于或晚于 datetime 的第一个事件开始读取日志(支持 DATETIME 和 TIMESTAMP 类型)。 |
--stop-datetime |
--stop-datetime=datetime 在等于或晚于 datetime 的第一个事件处停止(支持 DATETIME 和 TIMESTAMP 类型)。 |
--start-position, -j |
--start-position=N, -j N 开始读取日志的位置(position 等于或大于 N 后的事件)。 |
--stop-position |
--stop-position=N 在日志位置 N 处停止解码。 |
--stop-never |
保持与服务器的连接。 |
--verbose, -v |
重新构建行事件并显示为已注释的 SQL 语句,并在适用时显示表分区信息。 |

--base64-output= value ,value允许的值:
- (默认 AUTO ) AUTO ("automatic")或 UNSPEC ("unspecified")在必要时自动显示BINLOG语句。如果使用mysqlbinlog重新执行二进制日志文件内容,那么使用 AUTO 选项是唯一安全的行为,其他选项值仅用于调试或测试,如果 --based4-output 没有指定,那么默认值是 AUTO
- NEVER 不显示BINLOG语句。
- DECODE-ROWS 不显示加密内容,可以配合mysqlbinlog的 --verbose 选项以注释的形式只显示事件的SQL语句。帮我润色一下
2.3 binlog内容的格式
mysqlbinlog 可以使用以下语法
mysqlbinlog [options] log_file ...
例如要显示名为 binlog.000010 二进制日志文件的内容,可以使用以下命令:

mysqlbinlog --no-defaults /var/lib/mysql/binlog.000002

- position: # at 4 每条日志都以 # at 开始,后面的数字表示该条日志记录的事件在文件中的偏移量,当前示例表示该事件从日志文件的第4个字节开始
- timestamp: 事件发生的时间戳,即第二行开头记录的
- server id: 服务器标识(1)
- end_log_pos: 下一个事件在文件中的偏移量(当前事件结束偏移+1)
- Type: 事件类型
- thread_id: 执行事件的线程Id
- exec_time: 事件执行花费的时间(0.00 表示10毫秒以内)
- error_code: 错误码(0 表示没有错误)

2.4 数据准备
首先我们先重置一下二进制日志
sql
reset master;


然后我们选择db2数据库,执行下面这些语句
sql
-- 建库
drop database if exists testdb;
create database testdb character set utf8mb4 collate utf8mb4_0900_ai_ci;
use testdb;
-- 建表
create table t1 (
id bigint not null,
name varchar(20) not null
);
-- 写入
insert into t1 (id, name) values (101, 'user101');
insert into t1 (id, name) values (102, 'user102');
insert into t1 (id, name) values (103, 'user103');
insert into t1 (id, name) values (104, 'user104');
insert into t1 (id, name) values (105, 'user105');
insert into t1 (id, name) values (106, 'user106');
-- 更新
update t1 set name = 'biti01' where id = 101;
update t1 set name = 'biti02' where id = 102;
update t1 set name = 'biti03' where id = 103;
-- 删除
delete from t1 where id = 104;
delete from t1 where id = 105;
delete from t1 where id = 106;
2.5 查看binlog
查看指定数据库的日志
bash
# 查看数据库testdb的日志
mysqlbinlog --no-defaults --database=test_db /var/lib/mysql/binlog.000001 | less

以上的日志内容是加密的,可以通过加入 --base64-output=decode-rows 不显示加密内容,配合 -v 选项,显示事件的SQL语句
bash
# 不显示加密内容,显示事件的SQL语句
mysqlbinlog --no-defaults --database=testdb --base64-output=decode-rows -v /var/lib/mysql/binlog.000001 | less
我们很容易就能看到下面这些



insert记录中表示为第几列设置什么值

update where条件中记录了所有列的条件值,再记录为每个列设置的值。

delete是和update一样的
1. 按时间范围查询日志
查看指定时间之后的日志
mysqlbinlog --no-defaults \
--database=testdb \
--base64-output=decode-rows \
-v \
--start-datetime='2024-10-21 16:38:33' \
/var/lib/mysql/binlog.000001 | less
-
功能 :读取
binlog.000001
中 2024-10-21 16:38:33 之后 的所有日志。 -
关键参数:
-
--database=testdb
:仅解析testdb
数据库的日志。 -
--base64-output=decode-rows
:解码行格式事件(如INSERT/UPDATE/DELETE
)。 -
-v
:显示注释 SQL(可升级为-vv
显示更详细数据)。 -
--start-datetime
:起始时间(支持DATETIME
或TIMESTAMP
格式)。
-
(2) 查看指定时间区间内的日志
mysqlbinlog --no-defaults \
--database=testdb \
--base64-output=decode-rows \
-v \
--start-datetime='2024-10-21 16:38:33' \
--stop-datetime='2024-10-21 19:38:33' \
/var/lib/mysql/binlog.000001 | less
-
功能 :读取
binlog.000001
中 2024-10-21 16:38:33 到 19:38:33 之间的日志。 -
关键参数:
--stop-datetime
:结束时间(与--start-datetime
配合使用)。
2. 按位置范围查询日志
(1) 从指定位置读取到文件末尾
mysqlbinlog --no-defaults \
--database=testdb \
--base64-output=decode-rows \
-v \
--start-position=3793 \
/var/lib/mysql/binlog.000001 | less
-
功能 :从
binlog.000001
的 偏移量 3793 开始读取日志,直到文件结尾。 -
关键参数:
--start-position
:起始偏移量(通过SHOW BINLOG EVENTS
获取)。
我就从下面这里开始读取

bash
mysqlbinlog --no-defaults \
--database=testdb \
--base64-output=decode-rows \
-v \
--start-position=3476 \
/var/lib/mysql/binlog.000001 | less
其实是一样的。
(2) 读取指定位置区间内的日志
mysqlbinlog --no-defaults \
--database=testdb \
--base64-output=decode-rows \
-v \
--start-position=3793 \
--stop-position=4690 \
/var/lib/mysql/binlog.000001 | less
-
功能 :读取
binlog.000001
中 偏移量 3793 到 4690 的日志。 -
关键参数:
--stop-position
:结束偏移量(需小于文件总大小)。
这些我就不演示了
2.6 简单数据恢复
删除testdb
bash
-- 删除数据库
drop database testdb;

我们现在去看看二进制日志文件里面对应的
bash
mysqlbinlog --no-defaults --database=testdb --base64-output=decode-rows -v /var/lib/mysql/binlog.000001 | less

当前删除数据库的事件和偏移量
我们要恢复的话,就是要执行偏移量为4544之前的日志重新执行一遍即可。
确定从哪里开始
我们找到最初的那条SQL语句drop database if exists testdb;对应的事件就好了

到哪里结束
我们这里去寻找最后一条SQL语句delete from t1 where id = 106;对应的事件就好了,也即是下面的4384

重新执行指定区间内容的日志操作
bash
# 方法一:找到恢复的起始位置,直接通过二进制日志进行恢复
mysqlbinlog --no-defaults --skip-gtids=true --start-position=234 --stop-position=4384 /var/lib/mysql/binlog.000001 | mysql -uroot -p123456 -h127.0.0.1 -P3306
执行前


执行后


这是因为还有一个commit没有执行

我们看到commit上面是删除这个106号的信息的,但是我们只是恢复到4384,这个时候并没有给我们commit。所以我们必须要加上这个4436这个commit。要不然我们的4384里面的删除操作就不生效。
事务的commit是另外一个事件,把这个一定要加上,要不然最后一次修改操作不生效。
所以终点不是最后一条SQL语句对应的偏移量4384,而应该是 最后一条SQL语句之后的commit对应的偏移量4436。
将指定区间内容导出为.sql文件,然后再通过source文件来
bash
# 方法二:导出二进制日志到.sql文件
mysqlbinlog \
--no-defaults \
--skip-gtids \
--start-position=234 \
--stop-position=4436 \
/var/lib/mysql/binlog.000001 \
> testdb.sql

导出SQL之后我们必须去查看最后一个修改操作是否是commit!!!
我们可以进去看看
我们划到最后面

这个时候我们需要将其修改为commit

bash
# 在MySQL客户端导入.sql文件
source /root/testdb.sql


检查文件权限:
使用命令
ls -l /var/lib/mysql/testdb.sql
查看文件权限。确保运行操作的用户(或所属用户组)拥有该文件的读取权限。
如需修改权限,可使用
chmod
命令。例如:
chmod 644 /var/lib/mysql/testdb.sql
(这将设置所有者拥有读写权限,所属组和其他用户拥有读取权限)。
检查目录权限:
使用命令
ls -ld /var/lib/mysql
查看目录权限。确保相关用户(或所属用户组)拥有该目录的执行权限(即进入目录的权限)。
如需修改权限,可使用
chmod
命令。例如:
chmod 755 /var/lib/mysql
(这将设置所有者拥有读、写、执行权限,所属组和其他用户拥有读、执行权限)。
2.7 远程备份binlog日志(了解)
- 应用场景:本地磁盘的二进制日志有丢失的风险,在生产环境中通过把生成的binlog日志压缩后传输到远程服务器。
- 功能描述:MySQL5.6开始mysqlbinlog支持将远程服务器上的binlog实时复制到本地服务器上,比如在备份机上运行mysqlbinlog复制主库的日志
- 实现机制:通过MySQL Replication API实时获取二进制事件。远程服务器相当于主服务器,备份服务器相当于MySQL从服务器

示例:
在主服务器上创建账号
sql
-- 创建一个用于复制日志的用户
CREATE USER 'binlogrep'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 为用户赋予复制权限
GRANT REPLICATION SLAVE ON *.* TO 'binlogrep'@'%';
-- 刷新权限
FLUSH PRIVILEGES;
-- 测试登录
mysql -ubinlogrep -p123456


从服务器运行备份
bash
# 测试登录
mysql -ubinlogrep --host=117.72.80.239 -P3306 -p123456

bash
mysqlbinlog --read-from-remote-server --raw --host=117.72.80.239 --port=3306 --user=binlogrep --password=123456 --stop-never /var/lib/mysql/binlog.000001 --result-file=D:/Logs/bak-
|----------------------------------|---------------------------------------|
| --read-from-remote-server
| 从远程 MySQL 服务器读取二进制日志。 |
| --raw
| 输出原始二进制日志文件(而非文本格式)。 |
| --host=192.168.100.231
| 远程 MySQL 服务器地址。 |
| --port=3306
| 远程 MySQL 服务端口。 |
| --user=binlogrep
| 用于连接的用户名(需具备 REPLICATION SLAVE
权限)。 |
| --password=123456
| 用户密码。 |
| --stop-never
| 持续监听日志,不主动断开连接(适用于实时备份)。 |
| --result-file=/log/1373306/bak
| 指定本地保存文件路径(注意:需确保目录存在)。 |
这种方式指定本地备份日志文件,可以为日志文件前加前缀,如果只指定备份目录一定以 / 结尾,比如 result-file=/log/1373306/ 此时备份的日志文件使用主服务器的文件名
执行之前

执行之后

如果说我们在远程机器上刷新了二进制日志文件


我们在本地也是能看到的,前提是我们加上了--stop-never选项

总的来说我们可以像下面这个

