ROW_BASED_REPLICATION下DELETE操作引发MySQL从库延迟问题咨询
问题1:仅将该删除查询的事务调整为STATEMENT_BASED复制是否可行,会遇到哪些问题?
不可行。当前数据库全局隔离级别为READ COMMITTED,InnoDB引擎在该隔离级别下默认不支持STATEMENT格式的二进制日志,单独为单个事务设置binlog_format=STATEMENT会直接报错,事务无法执行。
就算绕过限制强制使用STATEMENT格式,还会遇到两类问题:
- 该DELETE语句的
{time value}为动态值,主从执行时如果存在时间计算误差,会直接导致主从数据不一致 - 分批删除逻辑如果遇到主库并发写入修改了
last_refresh_time的值,主从执行路径出现差异,也会引发数据不一致
问题2:该修改是否会影响其他事务的INSERT操作?
会。如果全局修改binlog_format为STATEMENT,在READ COMMITTED隔离级别下,所有InnoDB表的插入操作都会直接触发1665错误,错误信息为Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
如果仅为当前DELETE事务临时设置binlog_format=STATEMENT,DELETE操作本身会因为隔离级别限制失败,不会影响其他正常事务。
问题3:仅将该DELETE查询的事务隔离级别调整为REPEATABLE_READ是否可行,是否推荐该操作?
技术上可行,但不推荐。
操作逻辑可跑通:在执行DELETE的会话中,先临时执行SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;,再执行SET SESSION binlog_format = STATEMENT;,之后执行删除操作不会报错,也不会影响其他使用READ COMMITTED隔离级别的业务事务。
不推荐的核心原因有两个:
- 依然存在STATEMENT格式日志带来的主从数据不一致风险,比如时间参数误差、主从表数据差异导致删除行数不一致
- REPEATABLE READ隔离级别下DELETE操作会加更多间隙锁,大幅提升主库锁冲突概率,尤其是你单次删除量级较大的场景,很容易影响正常业务写入。
问题4:针对该从库延迟问题还有哪些优化建议?
- 调整分批删除策略:将每批次删除行数从2000下调到5001000,每批次删除后增加100500ms的休眠时间,避免短时间生成大量行日志,降低从库重放压力
- 开启MySQL 5.7从库并行复制:设置
slave_parallel_type=LOGICAL_CLOCK,slave_parallel_workers调整为4~8(根据从库CPU核心数适配),可让从库并行重放同一批提交的事务,大幅降低删除操作带来的延迟 - 确保
last_refresh_time字段有索引:让DELETE语句可以快速定位待删除行,减少主库执行时间的同时也能缩小binlog体积,降低从库重放负载 - 使用内置限流逻辑的工具执行删除:比如Percona的pt-archiver,自带分批、主从延迟检测逻辑,当从库延迟超过阈值时会自动暂停删除,避免延迟过高影响业务
- 升级MySQL版本:MySQL 8.0对行日志重放效率、并行复制能力都有大幅优化,能有效降低大数量删除带来的从库延迟
内容的提问来源于stack exchange,提问作者vinieth

