只有修改数据的sql(如insert/update/delete/ddl)才会触发binlog写入,事务提交前mysql串行写入binlog再通知存储引擎提交,binlog与redo log通过xa协调保证一致性。

主库执行SQL后,binlog怎么被触发写入
不是所有SQL都会进binlog,只有实际修改数据的语句(INSERT、UPDATE、DELETE、DDL等)才会被记录;SELECT、SHOW、SET这类不改数据的语句不会写入。关键点在于:事务提交前,MySQL就把变更事件串行写入binlog,再通知存储引擎提交——这意味着binlog和引擎层(如InnoDB)的日志(redo log)是两套独立日志,靠XA协调保证一致性。
常见误区:autocommit=0时,没显式COMMIT,binlog就不会落盘;而autocommit=1下,每条DML自动成一个事务,立刻写binlog。如果主库崩溃在binlog写完但redo log未刷盘之间,从库可能多出一条“幻影事务”,这是异步复制固有风险。
从库SQL线程如何重放relay-log,为什么容易卡住
SQL Thread是单线程串行执行relay-log里所有事件的,哪怕主库是并行写入的10个事务,从库也得一个一个按序执行。这就是主从延迟(Seconds_Behind_Master > 0)最根本的原因。
- 大事务(比如
DELETE FROM huge_table WHERE ...)会阻塞后续所有事件执行,延迟飙升 - 主库短平快的高并发写,在从库变成“长尾排队”,尤其遇到锁表、慢查询、磁盘I/O瓶颈时更明显
-
replicate_do_db或replicate_ignore_table这类过滤规则会让SQL线程跳过某些事件,但位置指针仍推进,容易造成“跳过逻辑”和实际数据不一致
2025年起MySQL 8.0默认启用WRITESET并行复制(需binlog_transaction_dependency_tracking=WRITESET),能基于行级依赖判断哪些事务可并行回放——但前提是主库用的是ROW格式binlog,且事务不跨库操作。
主从延迟对应用读取的直接影响
应用连从库做SELECT时,如果没做任何延迟感知,很可能读到“过期数据”。比如下单成功(主库已写入),立刻查订单列表(连了从库),却返回空——这不是bug,是复制机制决定的。
- 业务强一致性读(如刚写完就查)必须走主库,或加
SELECT ... FOR UPDATE强制主库路由 - 中间件(如ShardingSphere、MyCat)的读写分离策略若没配置
maxReplicationLag阈值,会把请求发给延迟2分钟的从库 -
show slave status\G里的Seconds_Behind_Master是估算值,实际延迟可能更大(尤其当SQL线程正在执行一个大事务时,该值会冻结不动)
真正要监控的不是这个字段,而是Relay_Log_Pos和Read_Master_Log_Pos的差值——它反映I/O线程拉了多少日志还没被SQL线程消费,更接近真实积压量。
为什么reset master在从库上执行会彻底断掉复制
reset master清空主库所有binlog文件,并重置mysql-bin.000001,但不会通知从库。从库的IO Thread还在按旧的Master_Log_File和Master_Log_Pos去拉日志,结果得到Could not find first log file name in binary log index file错误,复制中断。
- 误操作后不能靠
CHANGE MASTER TO硬切新日志名——因为旧事务已丢失,强行继续会导致主从数据不一致 - 正确做法是重新做一次全量同步:
mysqldump --single-transaction --master-data=2导出+恢复,再CHANGE MASTER TO指向dump中记录的位置 - 生产环境应禁用
reset master权限,或通过sql_log_bin=0临时关闭当前会话的binlog写入来规避风险
真正难处理的不是流程本身,而是复制链路上每个环节都可能“静默失败”:网络抖动让IO Thread断连却不报错、磁盘满导致relay-log写不进去、甚至slave_skip_errors跳过主键冲突后,后续更新直接错位——这些细节比原理更消耗排查时间。










