2. Binlog 开启与配置:my.cnf 核心参数详解

好,咱们正式开始动手配置 Binlog。说实话,我见过不少新手,上来就照着网上的配置一顿复制粘贴,结果 Binlog 是开了,但要么磁盘爆了,要么同步丢数据。嗯,今天咱们就把这几个核心参数掰开揉碎了讲清楚。

我个人习惯,在配置任何 MySQL 实例之前,都会先画一张配置决策图。你看下面这张图,就明白这几个参数之间的关系了:

Binlog 核心配置决策图 my.cnf Binlog 配置 server-id 唯一标识实例 log-bin 开启 & 路径 binlog_format 记录模式 expire_logs_days 自动清理 核心原则 server-id 必须唯一 → log-bin 开启后 → 选择合适 format → 设置合理过期时间 ROW 模式(推荐) STATEMENT 模式 MIXED 模式

2.1 server-id:给每个实例一个身份证

先说 server-id。这个参数说白了就是给 MySQL 实例一个唯一编号。在复制架构里,主库和从库必须有不同的 ID,否则复制链路根本建不起来。

配置示例:

[mysqld]
server-id = 1001

我记得有一次,公司新上线一套主从环境,DBA 同事忘了改从库的 server-id,结果从库启动复制后,主库的 Binlog 事件全部被忽略。查了半天,才发现两个实例 ID 都是 1。你想想看,这要是生产环境,数据同步断了几个小时,后果多严重。

我个人习惯,会给 server-id 制定一套编码规则。比如:

  • 第一位:机房编号(1-9)
  • 第二位:集群编号(1-9)
  • 后两位:实例编号(01-99)

这样一看 ID 就知道是哪个机房的哪个集群。比如 1201,就是 1 号机房、2 号集群、第 1 个实例。

注意:server-id 的取值范围是 1 到 2^32-1。不要用 0,0 是特殊值,表示不启用 Binlog 复制功能。

2.2 log-bin:开启 Binlog 的开关

log-bin 是 Binlog 的开关,也是文件路径的基名。你只要在 my.cnf 里写上这一行,Binlog 就开始工作了。

基础配置:

[mysqld]
log-bin = /data/mysql/binlog/mysql-bin

这里我解释一下:mysql-bin 是文件名的前缀。实际生成的文件会是 mysql-bin.000001、mysql-bin.000002…… 依次递增。

我曾经遇到过一个案例,某团队把 Binlog 直接放在了数据目录下,结果磁盘满了,MySQL 直接挂掉。为什么?因为 Binlog 的增长速度远超你的想象。在高并发写入场景下,一天产生几十 GB 的 Binlog 很正常。

我的建议:把 Binlog 单独放在一块独立的磁盘或挂载点上。这样即使 Binlog 写爆了,也不会影响数据文件的读写。路径权限记得给 mysql 用户。

另外,如果你用的是 MySQL 8.0,默认就开启了 Binlog,但路径可能不是你想要的。我建议还是显式配置一下,心里踏实。

2.3 binlog_format:三种记录模式怎么选?

这个参数,可以说是 Binlog 配置里最关键的。它决定了 MySQL 用什么方式记录变更。有三种模式:ROW、STATEMENT、MIXED。

模式 记录方式 优点 缺点
ROW 记录每一行数据的变化 最精确,不会丢数据 日志量大,占用磁盘
STATEMENT 记录执行的 SQL 语句 日志量小,节省空间 某些场景下数据不一致
MIXED 自动切换 ROW 和 STATEMENT 兼顾两者优点 逻辑复杂,偶有意外

我个人强烈推荐使用 ROW 模式。为什么?

你想想看,STATEMENT 模式记录的是 SQL 语句。如果这条语句用了 NOW()、UUID() 这种非确定性函数,主库和从库执行出来的结果可能不一样。我见过一个案例,就是因为用了 RAND(),导致主从数据不一致,最后花了整整两天才修复。

ROW 模式就不一样了。它记录的是每一行数据变更前后的完整内容。不管你怎么折腾,从库拿到的是精确的行数据,不会走样。

推荐配置:

[mysqld]
binlog_format = ROW

当然,ROW 模式也有代价——日志量大。但现在的磁盘便宜,网络带宽也够,这点代价完全可以接受。说白了,用空间换数据一致性,这笔买卖划算。

注意:如果你使用 MIXED 模式,MySQL 会在某些情况下自动切换到 ROW 模式。但切换时机并不总是如你所愿。我建议直接固定为 ROW,省心。

2.4 expire_logs_days:别让 Binlog 撑爆磁盘

Binlog 文件不会自动删除,除非你告诉 MySQL 什么时候删。expire_logs_days 就是干这个的。

配置示例:

[mysqld]
expire_logs_days = 7

这个参数的意思是:Binlog 文件保留 7 天,超过 7 天的文件会在 Binlog 切换或 MySQL 重启时自动清理。

我曾经接手过一个项目,Binlog 保留了 90 天。你猜怎么着?磁盘报警天天响,最后不得不手动清理。但手动清理有风险——万一从库还没追上,你删了 Binlog,从库就彻底断了。

我的经验:保留天数取决于你的备份策略和从库延迟情况。一般建议 3-7 天。如果你有专门的 Binlog 备份系统,甚至可以只保留 1-2 天。

另外,MySQL 8.0 引入了 binlog_expire_logs_seconds 参数,可以精确到秒。如果你需要更精细的控制,可以用这个。

MySQL 8.0 推荐配置:

[mysqld]
binlog_expire_logs_seconds = 604800  # 7天

2.5 完整配置示例

好了,把上面几个参数串起来,一个标准的 Binlog 配置长这样:

[mysqld]
server-id = 1001
log-bin = /data/mysql/binlog/mysql-bin
binlog_format = ROW
expire_logs_days = 7
# MySQL 8.0 可用
# binlog_expire_logs_seconds = 604800
# 可选:控制单个 Binlog 文件大小
max_binlog_size = 1G
# 可选:Binlog 缓存大小
binlog_cache_size = 32M

配置完成后,重启 MySQL 服务,然后执行 SHOW MASTER STATUS; 验证一下:

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+

看到这个输出,说明 Binlog 已经正常工作了。

最后提醒一句:修改 my.cnf 后一定要重启 MySQL 服务。有些参数支持动态修改,但 log-bin 不行,必须重启。别问我怎么知道的——我曾经在线上直接改配置忘了重启,排查了半天才发现 Binlog 根本没生效。