请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

关于钱包扣减的问题

老师 关于扣减的问题  课程中说的是先扣减redis  再扣减DB  那么如果在高并发场景下  redis连续扣减,但实际上DB没有连续扣减,导致redis和db的数据不统一 这种情况有什么手段来防止?

正在回答 回答被采纳积分+3

1回答

Danny_Idea 2025-10-12 09:57:10

间隔许久,我重新想了下当初这个方案链路,链路可以优化成这样:


链路改为先mysql事务扣减,mysql事务内部发送mq的事务消息,然后在mq的事务消息消费端做redis的decr操作。流程如下:

1. 开启 MySQL 本地事务

2. MySQL 中执行 “扣减余额 SQL”(带条件校验)

3. 事务内发送 MQ(确保 MQ 发送成功才提交事务)

4. 提交 MySQL 事务

5. 消费 MQ 消息,更新 Redis 余额

具体每个环节的细节如下:


1.MySQL 层:用 “条件 SQL” 确保扣减原子性。

这里可以合理运用一些乐观锁机制去扣减余额值,并且在update里面做余额是否充足的判断,例如:

UPDATE user_balance 
SET balance = balance - #{deductAmount}, 
    update_time = NOW()  -- 记录更新时间,用于后续校验
WHERE user_id = #{userId} 
  AND version = #{version}. -- 乐观锁
  AND balance >= #{deductAmount};  -- 关键:防止超扣


2.Redis 层:用 “原子命令” 更新缓存。

消费 MQ 更新 Redis 时,使用类似decr这样的原子性的命令进行操作。


3.MQ 消息可靠性保障

生产端:发送消息使用事务消息,确保不会因为事务提交失败而发送消息的情况。(事务消息可以基于本地事务表去做完善)。

消费端:开启 “手动 ACK”,消费 MQ 消息要在更新 Redis成功后,再手动确认 ACK,另外消费端一定要做好消费幂等的情况,避免超扣。


4.定期补偿巡检任务执行

设计定时任务(如每 5 分钟执行一次),对比 Redis 与 MySQL 的余额,发现不一致则修复。


总结:

这个方案存在1个缺点,就是如何在高并发场景下,mysql的更新操作会成为系统瓶颈,所以可以尝试利用一些读写分离,分库分表的方式去提升吞吐能力。


0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号