• 深入理解MySQL binlog

深入理解MySQL binlog

2025-05-06 01:00:05 栏目:宝塔面板 141 阅读

binlog 是 MySQL 最为重要的日志文件,MySQL 数据的备份恢复、主从复制都依赖 binlog,相比于其他日志文件,binlog 可以说是刚需了。

binlog 常见命令

为了对 binlog 有一个直观的认知,我们先来看几个命令。

首先,默认情况下 binlog 并不会开启,我们可以通过下面的 show variabkes like‘log_bin’命令查看 binlog 的开启状态:

MySQL> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | OFF   |
+---------------+-------+

如果你需要开启 binlog,可以在 my.ini 配置文件中可以加入下面的配置来开启:

log_bin=/home/MySQL/bin-log.log

开启 binlog 以后,我们就可以看看 binlog 的内容了。由于 binlog 本身是二进制文件,我们不能直接打开查看,但我们只关心 binlog 内容的意义而不是内容本身,因此我们可以用 MySQL 提供的如下命令来查看 binlog 内容:

show binlog events;

在 MySQL 中,输入上述命令后,我们能看到如下所示的返回结果:

MySQL> show binlog events;
+----------------+------+-------------+-----------+-------------+---------------
| Log_name       | Pos  | Event_type  | Server_id | End_log_pos | Info
+----------------+------+-------------+-----------+-------------+---------------
| bin-log.000001 |    4 | Format_desc |         1 |         107 | Server ver: 5.7.29-log, Binlog ver: 4                         |
| bin-log.000001 |  99 | Query       |         1 |         175 | BEGIN
                                                |
| bin-log.000001 |  166 | Intvar      |         1 |         203 | INSERT_ID=9
                                                |
| bin-log.000001 |  200 | Query       |         1 |         315 |insert into user (age,name) values(1,"test") |
| bin-log.000001 |  331 | Xid         |         1 |         342 | COMMIT /* xid=22 */                                           |
+----------------+------+-------------+-----------+-------------+---------------

在这个返回的结果中,最重要的是 Event_type 和 Info 这两个字段,其余字段不影响我们学习理解 binlog,就不赘述了。其中,Info 是命令的具体内容,可以看到 Info 里面是具体执行的 SQL 语句。而 Event_type 是事件类型,它的作用是记录我们对 MySQL 所有变更操作的类型。

目前 MySQL 有 30 多种事件类型,归类了你对 MySQL 的所有变更操作。这些操作日志的内容共同组成了我们的 binlog,其中 Event_type 是 binlog 日志中的一个字段,因此认识 Event_type 对理解 binlog 的内容非常重要,我们后面会挑选几个 Event_type 类型介绍。

通过上面的返回的结果,我们可以看到,每个指令、每个动作都是一行记录,而在 binlog 里每一行被称作一个事件。也就是说 binlog 是由一个又一个事件组成的。

binlog 文件格式

在讲解 binlog 事件之前,我们先看看 binlog 的文件格式分类。binlog 有 3 种格式类型,分别是 STATEMENT、ROW、MIXED:

  • STATEMENT

STATEMENT 是 binlog 的默认格式,我们后面对 binlog 的分析也是基于 STATEMENT 格式进行的。这个格式下,每一条修改数据的 sql 都会被记录到 binlog 中,slave 端再根据 sql 语句重现。

但 STATEMENT 的缺点也很明显,比如你用了 uuid 或者 now 这些函数,你在主库上执行的结果并不是你在从库执行的结果,这种随时在变的函数会导致复制的数据不一致。

  • ROW

在 ROW 模式下,我们只需要知道行数据最终被修改成什么样了,不会出现 STATEMENT 下动态函数的问题。但 ROW 的缺点是每行数据的变化结果都会被记录,比如执行批量 update 语句,更新多少行数据就会产生多少条记录,使 binlog 文件过大,而在 STATEMENT 格式下只会记录一个 update 语句而已。

  • MIXED

MIXED 包含了 STATEMENT 和 ROW 模式,它会根据不同的情况自动使用 ROW 模式和 STATEMENT 模式,MIXED 除了包含 STATEMENT 和 ROW 特性之外,还有一些针对自身优化的特性,比如压缩方式和一些特殊标记等等。

binlog 事件

在前面我们说了,binlog 由若干个事件组成,其中开头的第一个事件叫 Format_description,中文翻译为格式描述事件,文件结尾的最后一个事件叫做 rotate,中文翻译为日志轮换事件。其中 Format_description 包含了 binlog 的服务器信息、文件状态的关键信息等。

如果 MySQL 服务关闭或者重启,那么 MySQL 进程会自动创建一个新的 binlog,同时写入一个新的 Format_description。简单来说 Format_description 就是一个文件头。rotate 则包含下一个 binlog 的文件信息,它由 MySQL 写完 binlog 后添加到 binlog 的末尾,注意 rotate 只有当 binlog 写完才会有,binlog 没有写完的情况下是没有 rotate 的。

binlog 的基础结构如下,中间黄色部分就是我们执行的每一个事件。除了 select,剩下所有操作基本都会被记录,binlog 不记录 select 是因为 select 不会产生变更。

图片

binlog 对所有产生变化的操作做了分类,我们挑几类常见的介绍一下:

  • QUERY

这是最常见的类型,执行更新语句时会生成此事件,包括:create,insert,update,delete 等等。比如我们手动执行一个插入语句,然后再使用上面提到的 show binlog events 看一下下面的 binlog 文件内容:

insert into test values(1,'yafeng');
| bin-log.000001 | 412 | Query       |         1 |         536 | insert into test values(1,'yafeng');                                                      |
| bin-log.000001 | 520 | Xid         |         1 |         563 | COMMIT /* xid=30 */

和前面的日志内容相比,我们可以看到,经过 insert 操作,binlog 文件中多了一个 Query 类型的记录。

  • XID

事务提交时产生的事件,上面 insert 语句就是一个事务,因此除了 QUERY 记录还产生了一条 XID 记录。

  • FORMAT_DESCRIPTION

我们在前面提到了 FORMAT_DESCRIPTION,它是 binlog 的文件头记录。

  • ROTATE

当 binlog 写完后会另启一个新 binlog 来记录日志,旧的 binlog 文件末尾会追加这个事件,什么情况下 binlog 会写完呢?有 3 种情况,一个是手动执行 flush logs 命令,第二是重启 MySQL,第三是 binlog 文件大于 max_binlog_size 参数配置的大小。

  • INTVAR

SQL 中使用了 AUTO_INCREMENT 的字段,就会产生这个事件。

  • STOP

当 MySQL 停止时会生成此事件,是的,你没听错,连 MySQL 的停止也会被记录到 binlog。

  • RAND

SQL 中包含随机数函数的语句将产生 RAND 事件。

以上几个事件是 STATEMENT 格式下常见的几个,还有一些事件工作在 ROW 和 MIXED 格式下。binlog 在记录每个事件的时候也使用了 header 和 body 的格式,即 header 存储元数据,body 存储具体执行的语句。当然这并不是很重要,因为计算机领域中从网络协议到虚拟机到操作系统几乎都采用了类似的设计。下面我们来介绍 binlog 的变种文件 relay log。

relay log

relay log 中文名是中继日志,在主从复制的时候会辅助 binlog 完成复制任务。relay log 有着和 binlog 类似的格式和结构,可以看作是 binlog 的亲兄弟。唯一不同的地方是 relay log 多了 master.info 和 relay-log.info 两个文件。

master.info 和 relay-log.info 的文件内容非常小,一般以 info 为后缀结尾的文件都不大,里面记录了文件的指针。其中 master.info 记录 I/O 线程读取 binlog 的实时位置指针,relay-log.info 记录了 SQL 线程读取 relay log 的实时文件指针。 I/O 线程和 SQL 线程可以看作是在从库上工作的两个流水线工人,I/O 线程负责原材料的运输,写入本地的 relay log 中,SQL 线程负责从 relay log 获取原材料并加工。

现在我们再来回顾一下主从复制的流程,实际上这个流程有很多隐藏细节,既然我们今天提到了 master.info 和 relay-log.info,我们就来深入讲一下这个流程:

  1. 首先主库收到客户端请求语句,在语句结束之前向 binlog 写入事件。
  2. 之后,从库连接到主库,主库的 dump 线程从 binlog 读取日志并发送到从库的 IO 线程。
  3. I/O 线程从 master.info 读取到上一次写入的最后的位置。
  4. I/O 线程写入日志到 relay log,更新 master.info 的最后位置。
  5. SQL 线程从 relay-log.info 读取进上一次读取的位置,然后在数据库中执行 sql,执行完更新 relay-log.info 的最后位置。

总结

今天我们聊了 MySQL 的 binlog,binlog 是 MySQL 最重要的日志文件。同时,由于 binlog 本身是二进制的,所以它的结构很神秘。好在 MySQL 为我们提供了一些命令去查看它的内容。

通过今天的学习,我们也知道了 binlog 有 STATEMENT、ROW 和 MIXED 3 种模式,不同的格式下会有不同的事件,他们各有优缺点,MySQL 默认使用 STATEMENT 模式。

每个 binlog 文件都是由不同的事件组成的,几乎所有变更操作都是事件。MySQL 有 30 多种事件,其中我们介绍了 QUERY、XID、FORMAT_DESCRIPTION 等几个事件。binlog 有个孪生兄弟 relay log,这是从库从主库克隆过来的 binlog,它只是用在主从复制场景。relay log 有两个 info 文件 master.info 和 relay-log.info,其中 master.info 服务于从库的 I/O 线程,relay-log.info 服务于从库的 SQL 线程。结合这两个 info 文件,我们回顾了主从复制的完成过程,加深了印象。

本文地址:https://www.yitenyun.com/179.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 TIME_WAIT 运维 负载均衡 JumpServer SSL 堡垒机 跳板机 HTTPS HexHub Docker 服务器 服务器性能 管理口 JumpServer安装 堡垒机安装 Linux安装JumpServer Deepseek 宝塔面板 Linux宝塔 生命周期 esxi esxi6 root密码不对 无法登录 web无法登录 SQL 查询 序列 核心机制 Windows Windows server net3.5 .NET 安装出错 HTTPS加密 Windows宝塔 Mysql重置密码 开源 PostgreSQL 存储引擎 锁机制 宝塔面板打不开 宝塔面板无法访问 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 行业 趋势 Oracle 处理机制 无法访问宝塔面板 Undo Log 机制 Spring Redis 异步化 连接控制 InnoDB 数据库锁 监控 机器学习 优化 万能公式 动态查询 Serverless 无服务器 语言 响应模型 ES 协同 group by 索引 技术 分页查询 openHalo scp Linux的scp怎么用 scp上传 scp下载 scp命令 Postgres OTel Iceberg 缓存方案 缓存架构 缓存穿透 工具 高可用 存储 GreatSQL 连接数 数据 主库 SVM Embedding R edis 线程 日志文件 MIXED 3 国产数据库 Linux 安全 SQLite-Web SQLite 数据库管理工具 R2DBC Netstat Linux 服务器 端口 加密 场景 启动故障 ​Redis 推荐模型 Recursive 自定义序列化 防火墙 黑客 云原生 共享锁 SQLark RocketMQ 长轮询 配置 向量数据库 大模型 Hash 字段 OB 单机版 AI 助手 PG DBA Rsync 信息化 智能运维 Ftp 不宕机 磁盘架构 架构 电商 系统 数据分类 向量库 Milvus Canal Python 业务 IT运维 流量 filelock 修改DNS Centos7如何修改DNS 分库 分表 传统数据库 向量化 • 索引 • 数据库 线上 库存 预扣 语句 MySQL 9.3 聚簇 非聚簇 sftp 服务器 参数 PostGIS mini-redis INCR指令 MVCC 人工智能 推荐系统 同城 双活 redo log 重做日志 MongoDB MCP 开放协议 频繁 Codis 失效 Doris SeaTunnel 缓存 Redisson 锁芯 高效统计 今天这篇文章就跟大家 主从复制 代理 数据类型 虚拟服务器 虚拟机 内存 工具链 事务 Java 开发 INSERT COMPACT 数据备份 千万级 大表 prometheus Alert 窗口 函数 数据结构 ZODB 发件箱模式 容器 网络架构 网络配置 SSH EasyExcel MySQL8 引擎 性能 Web 分布式架构 分布式锁​ 聚簇索引 非聚簇索引 QPS 高并发 崖山 新版本 数据脱敏 加密算法 B+Tree ID 字段 Go 数据库迁移 Web 接口 分布式 集中式 RDB AOF 核心架构 订阅机制 速度 服务器中毒 OAuth2 Token Redis 8.0 分页 自动重启 网络故障 播客 模型 数据页 数据集成工具 读写 容器化 StarRocks 数据仓库 DBMS 管理系统 SpringAI 排行榜 排序 池化技术 连接池 微软 SQL Server AI功能 Redka JOIN Caffeine CP MGR 分布式集群 部署 原子性 Entity 事务隔离 网络 LRU 业务场景 Valkey Valkey8.0 Testcloud 云端自动化 Pottery dbt 数据转换工具 分页方案 排版 数据字典 兼容性 1 ReadView 优化器 sqlmock 事务同步 悲观锁 乐观锁 关系数据库 意向锁 记录锁 日志 Weaviate 单线程 UUIDv7 主键 仪表盘 对象 单点故障 AIOPS UUID ID InfluxDB Order 编程 RAG HelixDB Ansible Pump Crash 代码 IT 双引擎 分布式锁 Zookeeper 产业链 恢复数据 字典 订单 LLM List 类型 线程安全 国产 用户 慢SQL优化 表空间 拦截器 动态代理 解锁 调优 Next-Key RR 互联网 GitHub Git 快照读 当前读 视图 神经系统 矢量存储 数据库类型 AI代理 查询规划 count(*) count(主键) 行数 CAS 算法 技巧 多线程 并发控制 恢复机制 闪回