如何解决消费者高频触发订单更新?
目录
一、业务逻辑
二、注意事项
三、解决思路
1.保证命中主键
2. 保证更新语句是幂等的
3. 分布式锁限流(仅当并发极高时)
常见性能/死锁隐患 & 优化对策
一、业务逻辑
[定时任务线程] [RocketMQ 消费者线程]
↓ ↓
查询订单 by ID <- 收到消息
↓ ↓
构造消息 DTO <- 调用 updateOrder()
↓ ↓
RocketMQ 发送 <- 执行 SQL: UPDATE charge_order SET ...
二、注意事项
业务逻辑显示消费者高频触发的后台任务(如 Kafka、RabbitMQ、RocketMQ 等),在并发量大时,不断触发更新操作,而更新操作如果:
-
未控制事务提交时间;
-
锁了范围较大的数据(如用
WHERE status = 1
); -
没有命中合适索引;
就非常容易造成你现在看到的“锁等待堆积 + 死锁”。
三、解决思路
1.保证命中主键
确认表结构中 id
是主键(InnoDB 默认聚簇索引),这点大概率没问题,但还是要核查。
2. 保证更新语句是幂等的
加一层状态判断,避免重复更新
3. 分布式锁限流(仅当并发极高时)
比如你一天有几万订单但集中在一分钟内结束,可以考虑对 charge_order 做 分片或限流处理(如 Hash 到 10 个消费线程池,每个只处理部分订单)。
常见性能/死锁隐患 & 优化对策
问题类型 | 举例 | 优化建议 |
---|---|---|
长事务 | update + 写日志 + 发通知 一起做 | 拆开事务,只把更新放事务里 |
重复更新 | 多次 UPDATE charge_order SET status=2 WHERE id=? | 加 AND status != 2 防止无意义更新锁 |
索引未命中 | 用了 WHERE status=1 AND end_time<? | 确保走主键或组合索引 |
并发更新同一行 | 多个线程同时更新 id=123 | 判断状态、幂等处理;考虑分片 |
批处理触发 | 扫描1000个订单,全部发消息 | 分批分页处理,每秒不要太多并发 |