insert … on duplicate key update 可绕过热点行锁瓶颈,本质是利用唯一索引原子性实现“插入即更新”,避免 select for update + 计算 + update 的三步锁流程,适用于无状态累加场景,但要求冲突字段必须有 primary key 或 unique key。

热点行更新卡住,不是并行复制能解决的
并行复制(slave_parallel_workers、slave_parallel_type = LOGICAL_CLOCK)只加速从库回放 relay log,对主库行锁排队毫无作用。所有请求堵在 UPDATE SET x = x + 1 WHERE id = 1 这一行上,从库再快也追不上一个被锁死的源头。
常见错误现象包括:Lock wait timeout exceeded 频发且集中在同一条语句;SHOW ENGINE INNODB STATUS 显示大量事务等待同一 space id + page no;innodb_row_lock_waits 持续飙升但 Threads_running 高而实际 QPS 上不去。
用 INSERT ... ON DUPLICATE KEY UPDATE 合并写请求
这是最轻量、无需额外组件的绕过方案,本质是跳过 SELECT FOR UPDATE + 应用层计算 + UPDATE 的三步锁流程,靠唯一键冲突触发原子更新。
每小时自动在推特搜索中国、加密货币、国际热点、美国热点、特朗普等话题的热度信息,提取前十热点,依据 X 平台真实算法权重(开源代码数据)为每个热点生成高曝光推文或线程。用户提及“推特热点”“Twitter热点”“推特搜索”“热点推文”“生成推文”“社交媒体监控”“Twitter监控”等关键词时触发。
- 必须有
PRIMARY KEY或UNIQUE KEY(如user_id),否则不生效 -
VALUES(click_count)取的是当前 INSERT 行的值,不是整批总和;多次插入同一user_id会自动合并累加 - 不支持带条件的原子判断(比如“余额 > 100 才扣减”),仅适用于无状态累加类场景
- 示例:
INSERT INTO user_counter (user_id, click_count) VALUES (123, 1), (456, 1), (123, 1) ON DUPLICATE KEY UPDATE click_count = click_count + VALUES(click_count)
用 Redis 原子操作做前置缓冲
当写频次远超 MySQL 单行吞吐(比如每秒上千次同 key 更新),就得把压力从 DB 层移走。Redis 不是替代方案,而是“第一道闸口”。
- 用
DECRBY或INCRBY快速预扣/预增,返回负数即拒绝,不进 MySQL - 真正要落库的请求,塞进
Redis Streams或带限速的消费者队列,控制 DB 写入节奏(如稳定 500 QPS) - 后台消费者批量聚合后,再以
INSERT ... ON DUPLICATE KEY UPDATE或REPLACE INTO刷入 MySQL - 注意补偿:消费者失败需重试+幂等,避免漏写或重复写
分桶打散单点压力,而不是硬扛锁
把“一行热”变成“多行温”,是纯 SQL 层最有效的解法。不需要中间件,上线快,回滚也容易。
- 原表:
CREATE TABLE goods (id INT PRIMARY KEY, stock INT)→ 单行即瓶颈 - 改后:
CREATE TABLE goods_stock_shard (goods_id INT, shard_id TINYINT, stock INT, PRIMARY KEY(goods_id, shard_id)) - 初始化时将总库存均分到 N 个
shard_id(如 0~9),扣减时用user_id % 10或RAND()随机选槽位 - 查总库存用
SUM(stock) FROM goods_stock_shard WHERE goods_id = ?,接受短暂不精确(最终一致) - 别在事务里调 HTTP、写日志、sleep——锁持有时间越长,排队越严重
真正卡住的从来不是 MySQL 能力,而是你让所有请求都挤在同一个物理位置上。拆、缓、合,三者选其一或组合落地,比调参、堆硬件更直接有效。










