binlog_row_image=full会显著推高带宽,因其在row格式下对每次update/delete均记录整行前后镜像,即使只改一个字段也传输全部列;改用minimal可仅传where条件列和实际修改列,实测体积减少75%,但需配合logical_clock并行复制、足够worker线程及版本兼容性验证。

MySQL主从复制带宽高,往往不是网络本身的问题,而是 binlog 日志内容太“胖”——尤其是 binlog_row_image=FULL 时,UPDATE/DELETE 每次都传整行前后镜像,宽表一更新,几十MB就发出去了。
为什么 binlog_row_image=FULL 会推高带宽
ROW 格式下,binlog_row_image 控制每条变更记录携带多少字段数据:
-
FULL(默认):UPDATE 记录变更前的整行 + 变更后的整行;DELETE 记录删除前的整行。哪怕只改一个status字段,也把 50 列全打一遍 -
MINIMAL:只传 WHERE 条件用到的列(前镜像)+ 实际被修改的列(后镜像)。改status就只传id和status,体积常压到 1/3~1/2 -
NOBLOB:不推荐,兼容性差,且对带宽优化不如MINIMAL明确
实测:某业务宽表(32 列,含多个 TEXT),单条 UPDATE 在 FULL 下生成 1.2MB binlog 事件;切到 MINIMAL 后仅 280KB —— 不是压缩算法,是根本少传了 75% 字段。
binlog_row_image=MINIMAL 的生效前提和坑点
这个参数改了不一定立刻省带宽,得看从库怎么回放:
- 必须搭配
slave_parallel_type=LOGICAL_CLOCK(MySQL 5.7+ 默认),否则从库仍按单线程串行读 relay log,MINIMAL虽然减小了日志体积,但并行度没提升,延迟可能照旧 - 从库
slave_parallel_workers得设够(建议 CPU 核数 × 1.5),否则逻辑时钟分组后没线程可跑,照样积压 - 主库改完要执行
SET GLOBAL binlog_row_image = 'MINIMAL',无需重启,但已有大事务在写入时仍按旧规则记日志,效果从下个事务开始 - 注意应用兼容性:某些旧版 ORM 或审计工具依赖完整镜像,切之前先在测试环境验证解析逻辑
比 binlog_row_image 更直接的带宽控制手段
如果已经用了 MINIMAL 还扛不住,说明日志量基数太大,得叠加其他措施:
- 开启
slave_compressed_protocol=ON:主从传输层启用 zlib 压缩,实测稳定压到 40%~60% 原体积。但注意 MySQL 5.7.21 以下 + 半同步复制会触发卡主库 Bug,务必核对版本 - 避免大事务:单个事务更新百万行?它会生成一个超大 binlog event,TCP 包头开销+重传风险陡增。拆成 1k 行/批,带宽更平滑
- 检查
max_allowed_packet:设太小(如 4MB)会让大事务被拆包,增加 TCP 头部冗余;设太大(如 1GB)又浪费内存。建议 64MB~256MB 之间按实际最大事务调 - 别用
du -sh /var/lib/mysql/mysql-bin.*估算带宽:磁盘上 binlog 是全量落盘的,而复制只传其中一部分(GTID 过滤、库名过滤、压缩后数据),两者数值毫无可比性
真正影响带宽的是“发了多少字节”,不是“写了多少字节”。binlog_row_image=MINIMAL 是最轻量、最安全的日志瘦身方式,但它只是起点——后面还得看并行回放能不能跟上、压缩协议开不开、事务粒度控没控住。漏掉任意一环,带宽都可能在某个凌晨突然冲顶。











