并行复制对热点行更新无效,因其仅加速从库回放,不缓解主库InnoDB行锁导致的串行排队;真正解法是绕开单行锁,如用INSERT...ON DUPLICATE KEY UPDATE合并写、Redis原子预扣减或分桶打散热点。

并行复制本身不解决热点行更新延迟——它只加速从库回放,而热点行问题出在主库写入层的锁竞争。想靠 slave_parallel_workers 降 UPDATE SET x = x + 1 WHERE id = 1 的延迟,纯属方向错误。
为什么并行复制对热点行无效?
并行复制(slave_parallel_type = LOGICAL_CLOCK 或 WRITESET)只影响从库 SQL 线程如何重放 relay log,它完全不干预主库的事务执行过程。热点行卡在主库 InnoDB 行锁上,所有并发请求排队等同一把 X 锁,从库再快也追不上一个被堵死的源头。
常见错误现象包括:
-
Lock wait timeout exceeded频发,且集中在同一条UPDATE语句 -
SHOW ENGINE INNODB STATUS中看到大量事务在等待lock struct(s)指向同一space id+page no -
innodb_row_lock_waits持续飙升,但Threads_running高而实际 QPS 上不去
真正该用的方案:绕开单行锁,而不是加速回放
主库层面的热点行瓶颈,必须用非阻塞、非强一致的替代路径来化解。MySQL 8.0 本身不提供“多线程并发更新同一行”的能力,强行堆线程只会恶化排队。
推荐按优先级落地以下方案:
- 用
INSERT ... ON DUPLICATE KEY UPDATE合并写:适用于有唯一键(如user_id)的累加场景,跳过SELECT FOR UPDATE加锁流程,靠冲突触发原子更新 - 前置 Redis 原子操作:
INCR/INCRBY承接高频写,再通过异步消费者(如 Kafka + Go worker)批量落库,把 MySQL 写频次从每秒上千压到每秒几笔 - 分桶打散热点:把原单行计数拆成 N 个逻辑桶(如
counter_shard_0到counter_shard_7),应用层哈希路由,最后聚合查询时SUM()汇总
ON DUPLICATE KEY UPDATE 示例:
INSERT INTO user_click (user_id, count) VALUES (123, 1), (456, 1), (123, 1) ON DUPLICATE KEY UPDATE count = count + VALUES(count);
注意:VALUES(count) 取的是当前 INSERT 行的值(即 1),不是整批总和;且要求 user_id 是 PRIMARY KEY 或 UNIQUE KEY。
如果业务硬性要求主库强一致,只能接受性能上限
那就必须接受 InnoDB 行锁的物理极限:单行 UPDATE ... SET x = x + 1 在常规配置下吞吐约 200–500 QPS。超过这个值,延迟必然累积,且无法通过调参突破。
此时能做的只有:
- 确认是否真需要强一致——点赞、曝光、埋点类指标几乎都可降级为最终一致
- 检查事务内是否有冗余操作:比如在事务里调用 HTTP 接口、读取大字段、做复杂计算,这些都会拉长锁持有时间
- 避免
SELECT ... FOR UPDATE+ 应用层计算 +UPDATE三段式,它把锁范围从“写瞬间”扩大到“读+算+写全过程”
最常被忽略的一点是:很多人把“主从延迟高”和“主库写入慢”混为一谈。只要 Seconds_Behind_Master 在涨,第一反应不该是调 slave_parallel_workers,而是先查主库 innodb_row_lock_time_avg 和慢日志里有没有同 key 的 UPDATE 长期 >100ms——那才是病根所在。


















