Untitled
Q: 当前实现会对业务异常(如库存不足)抛出RuntimeException,导致消息重复投递。
1 | createVoucherOrder 中 |
A:
- 不可恢复错误(如重复订单):记录日志并正常返回
可恢复错误(如数据库超时):抛出异常触发重试
Q:
1 | public void handleVoucherOrder(VoucherOrder voucherOrder) { |
handleVoucherOrder中的
redisson锁与redis+lua重复了吗?有必要删除吗?
A:有,否则相当于做了三重校验:Redis Lua → Redisson 锁 → 数据库唯一性,性能会打折
Q:幂等性保障
目前在 createVoucherOrder 里只是查 count 判断是否下过单。
更推荐在 数据库表层面加唯一索引:
1
ALTER TABLE voucher_order ADD UNIQUE KEY uk_user_voucher (user_id, voucher_id);
这样即使 RocketMQ 消息重复投递也能防止重复下单。
Q:
1 | boolean success = seckillVoucherService.update() |
这段以后并发高了怎么解决?
Q:
RocketMQ 在极端情况下可能会“重复投递”,所以消费端必须幂等。
已经在 DB 里有 query().eq(“user_id”, userId).eq(“voucher_id”, …) 判断,但更好的办法是
建唯一索引,直接用 DB 保证幂等。
Q:
现在 throw new RuntimeException,RocketMQ 会重试。
但要注意:如果是逻辑性错误(比如用户已下过单),重试是没意义的,会死循环。
建议只对系统性异常(DB 连接超时、Redis 挂了)抛异常,让 MQ 重试;如果是业务性错误,直
接 log.warn 并吞掉
Q.RocketMQ监听器抛出异常.消息被送回消费者,消费者再次尝试处理。由于相同原因(库存仍为0)失败,抛出异常,再次被重新安排。这就形成了一个无限循环
1 |
|
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.