1 基本概念
BinLog是一种记录所有MySQL数据库表结构变更以及表数据变更的二进制日志。BinLog中不会记录诸如select和show这类查询操作的日志。BinLog有如下两个重要的使用场景
- 主从复制:在主数据库上开启BinLog,主数据库把BinLog发送至从数据库,从数据库获取BinLog后通过IO线程将日志吸入到中继日志,也就是Relay Log中。然后通过SQL线程将Relay Log中的数据同步至从数据库,从而达到主从数据库的一致性。
- 数据恢复:当MySQL数据库发生故障或者崩溃时,可以通过BinLog进行数据恢复。
2 记录模式
2.1 Row模式
- 记录内容:记录数据行的实际变更(如某行的字段从
A
变为B
)。 - 特点:
- 优点:复制更精确,不会出现因语句执行环境不同导致的主从数据不一致。
- 缺点:日志量大(尤其是批量操作时),性能略低。大批量操作时候,会产生大量的二进制日志。比如使用alter table操作修改用友大量数据的数据表结构时,会使二进制日志的内容暴涨,产生大量的二进制日志,从而大大影响主从数据库的同步性能。
- 适用场景:对数据一致性要求高的场景(如金融系统),或使用了不确定函数的环境。
2.2 Statement模式
- 记录内容:记录 SQL 语句本身(如
INSERT
、UPDATE
)。 - 特点:
- 优点:日志量小,节省存储空间,性能较高。由于不记录数据的修改细节,只是记录数据表结构和数据变更的SQL语句,因此产生的二进制日志数据量比较小,这样能够减少磁盘的IO操作,提升数据存储和恢复的效率。
- 缺点:某些语句在复制时可能导致主从数据不一致(如
NOW()
、RAND()
等函数,或使用触发器、存储过程时)。
- 适用场景:语句确定性高、无特殊函数或触发器的环境。
2.3 Mixed模式
- 记录内容:自动选择使用 STATEMENT 或 ROW 模式:
- 默认使用 STATEMENT 模式。
- 遇到不确定语句(如
RAND()
)或可能导致数据不一致的操作时,自动切换为 ROW 模式。
- 特点:
- 优点:平衡了性能和数据一致性。
- 缺点:仍可能存在少量特殊场景下的不一致风险。
- 适用场景:大多数生产环境的默认选择。
3 文件结构
3.1 单个Binlog文件内部结构
每个Binlog文件由以下几部分组成:
3.1.1 文件头(4字节)
- 魔术数字
0xfe 0x62 0x69 0x6e
(即"bin"前面加0xfe)
3.1.2 事件序列
- 由多个事件(Event)按时间顺序排列组成
- 每个事件代表一个数据库操作或元数据变更
3.1.3 文件尾
- 当文件正常关闭时,会写入一个
Rotate Event
指向下一个文件 - 非正常关闭时可能没有文件尾
3.2 事件(Event)结构
每个事件包含以下部分:
部分 | 大小 | 说明 |
---|---|---|
事件头 | 19字节 | 包含事件元数据 |
事件体 | 可变 | 事件的具体内容 |
校验和 | 4字节(可选) | 事件的CRC32校验值 |
3.2.1 事件头详细结构(19字节):
偏移量 | 长度 | 字段 | 说明 |
---|---|---|---|
0 | 4 | timestamp | 事件发生的时间戳 |
4 | 1 | type_code | 事件类型代码 |
5 | 4 | server_id | 产生事件的服务器ID |
9 | 4 | event_length | 整个事件长度(头+体) |
13 | 4 | next_position | 下一个事件的位置 |
17 | 2 | flags | 事件标志位 |
3.3 常见事件类型
类型代码 | 事件类型 | 说明 |
---|---|---|
0x01 | START_EVENT_V3 | 旧版本开始事件 |
0x02 | QUERY_EVENT | 执行SQL语句(STATEMENT 模式) |
0x04 | ROTATE_EVENT | binlog文件切换 |
0x0f | FORMAT_DESCRIPTION_EVENT | 文件格式描述 |
0x10 | XID_EVENT | 事务提交事件 |
0x11 | TABLE_MAP_EVENT | 表映射事件(ROW模式) |
0x12 | WRITE_ROWS_EVENT | 插入行事件(ROW模式) |
0x13 | UPDATE_ROWS_EVENT | 更新行事件(ROW模式) |
0x14 | DELETE_ROWS_EVENT | 删除行事件(ROW模式) |
0x15 | INCIDENT_EVENT | 服务器异常事件 |
3.4 不同模式下的事件差异
3.4.1 STATEMENT 模式
- QUERY_EVENT:直接记录 SQL 语句。
+--------+----------------+-------------------+ | 头信息 | 数据库名长度 | SQL语句 | +--------+----------------+-------------------+
3.4.2 ROW 模式
- TABLE_MAP_EVENT:定义表结构(表 ID、列类型等)。
- WRITE_ROWS_EVENT:记录插入的行数据。
+--------+-------+----------------+----------------+ | 头信息 | 表ID | 列掩码 | 行数据 | +--------+-------+----------------+----------------+
4 BinLog和Redo Log的区别
4.1 所属层次与适用范围
- redo log:属于InnoDB 存储引擎特有的日志,仅 InnoDB 会使用,其他存储引擎(如 MyISAM)不支持。
- binlog:属于MySQL 服务器层(Server 层) 的日志,所有存储引擎(包括 InnoDB、MyISAM 等)都可以使用,是 MySQL 全局的日志机制
4.2 日志类型与记录内容
维度 | redo log | binlog |
---|---|---|
日志类型 | 物理日志 | 逻辑日志 |
记录内容 | 记录数据页(Page)的物理修改(如 “将数据页 X 的偏移量 Y 处的值从 A 改为 B”) | 记录 SQL 操作的逻辑变化(如 “插入一条 id=1 的记录”“更新 id=2 的记录的 name 字段”) |
特点 | 与具体数据页绑定,依赖 InnoDB 的页结构,具有幂等性,多次操作的前后状态可能是一致的 | 与存储引擎无关,仅记录逻辑操作,不依赖底层数据结构 |
4.3 写入方式
- redo log:
是循环写(circular write) 的日志,有固定大小。当日志写满后,会覆盖最早的日志(前提是这些日志对应的修改已同步到磁盘数据文件)。 - binlog:
是追加写(append write) 的日志,不会覆盖旧内容。当一个 binlog 文件写满,会自动创建新文件(文件名按 “binlog.000001、binlog.000002” 递增),旧文件会保留(可通过expire_logs_days
设置自动清理时间)
4.4 写入时机与事务关联
- redo log:在事务执行过程中实时写入(并非等到事务提交)。例如,执行
update t set a=1 where id=1
时,每修改一个数据页,就会同步记录 redo log(但此时 redo log 处于 “未提交” 状态,事务提交后才会标记为 “可持久化”)。 - binlog:在事务提交时写入(默认配置下)。当事务执行
commit
时,MySQL 会将该事务的逻辑操作(如整个update
语句的逻辑)写入 binlog,作为事务完成的记录。BinLog日志的记录方式与事务的提交顺序有关,并且一个事务的BinLog中间不会插入其他事务的BinLog。而Redo Log记录的是物理页的修改,最后一个提交的事务记录会覆盖之前的所有未提交的事务记录,并且一个事务的Redo Log中间会插入其他事务的Redo Log
4.5 核心作用与场景
- redo log:核心作用是保证事务的持久性(ACID 中的 D) ,防止数据库崩溃后的数据丢失。
- 场景:数据库宕机后重启时,InnoDB 会通过 redo log 恢复 “已提交但未写入磁盘数据文件(.ibd)” 的修改,确保数据不丢失。
- binlog:核心作用是记录数据的逻辑变更,用于主从复制和数据恢复。
- 场景 1:主从复制中,从库通过读取主库的 binlog,重演逻辑操作以同步数据;
- 场景 2:数据恢复时,可通过 binlog 重演指定时间范围内的操作(如 “恢复到昨天 18 点的数据”)。
4.6 为何需要两种日志?
两者的设计目标互补:
- redo log 是 InnoDB 为了保证自身存储引擎的 “崩溃恢复能力” 而设计的,解决了 “内存数据页未刷盘时宕机” 的问题(避免数据丢失);
- binlog 是 MySQL Server 层为了实现 “跨存储引擎的复制和恢复” 而设计的,解决了 “数据同步到从库” 或 “基于时间点的全量恢复” 问题。
实际中,两者通过 “两阶段提交”(prepare + commit)保证一致性:事务提交时,先写 redo log 的 prepare 阶段,再写 binlog,最后写 redo log 的 commit 阶段。这样即使中途宕机,也能通过两个日志的状态判断事务是否需要最终提交。
4.7 总结
对比维度 | redo log | binlog |
---|---|---|
所属层次 | InnoDB 存储引擎层 | MySQL Server 层 |
日志类型 | 物理日志(数据页修改) | 逻辑日志(SQL 逻辑变更) |
写入方式 | 循环写(固定大小,覆盖旧日志) | 追加写(文件递增,不覆盖) |
核心作用 | 保证事务持久性(崩溃恢复) | 主从复制、时间点恢复 |
适用存储引擎 | 仅 InnoDB | 所有存储引擎 |