java吧 关注:1,235,310贴子:12,703,037

大家好,想问一下类似于银行转账的开发思路有吗?

只看楼主收藏回复

比如库存10张卡,现在转账5张,因为服务器压力很大,所以我需要在MQ队列里完成扣库存的逻辑,那么我的业务设计是这样的:
① 先判断当前库存(剩余10张),再判断redis的未扣卡数量(第一次为0),库存10 - 未扣卡数量0 = 10,表示库存充足,标识转账成功,未扣卡数量变为5。
②接着发送MQ队列,在队列里面扣库存完成之后,库存剩余5,再把未扣卡数量重置为0。
③如果MQ队列里面的库存还没有扣除,库存剩余10,未扣卡数量还剩下5,那么下一次转账20张,库存10 - 未扣卡数量5,表示库存剩余5,此时不能转账成功
这个设计逻辑有个问题,就是如果MQ队列里面库存扣除成功之后,未扣卡数量却没有重置为0,就会导致数据错误。我想问问大家,有没有一些比较好的案例可以提供我思考呢?


IP属地:广东1楼2023-07-01 12:13回复
    保证2个操作在同一事务


    IP属地:福建来自Android客户端2楼2023-07-01 12:42
    收起回复
      用redis的锁,保证不会被过多消费。或者开多个锁,每个锁下只有3-4张卡。这样可以被三个线程同时消费


      IP属地:安徽来自Android客户端3楼2023-07-01 15:05
      收起回复
        数据库用了mongodb然后用redis做缓存吗?你这里的未扣数量实际是指待扣数量,对吧?所以,库存-待扣=真实库存。现在的问题是,待扣-1,库存-1没有同步进行,导致真实库存失真。提供一个思路:库存和待扣都用redis做缓存,mq处理成功后,mongodb库存和redis中的库存和待扣都减一,如果需要的话redis中两个数据可以用一个lua脚本扣减。这样新来的业务要判断库存,如果有并发也还是有问题,需要加分布式锁如redis锁,防止并发判断真实库存是否足够。


        IP属地:广东来自Android客户端4楼2023-07-01 16:09
        回复
          库存-待扣,应该叫预留库存/预期库存,应把预留库存也放到redis中,使用increby来加减这个库存


          IP属地:广东来自Android客户端5楼2023-07-01 16:22
          回复
            不知道,没做过


            IP属地:广西来自iPhone客户端6楼2023-07-01 17:09
            收起回复
              为什么你会觉得这样做会减轻服务器压力呢?服务器总量不变的情况下,你所说的方式应该是需要用到分布式事务吧,你能够把握得了吗?还有你这个业务需要给前端扣减成功响应吗?如果需要,你说的方式就不能用了,因为你的方式是异步的


              IP属地:广东来自Android客户端7楼2023-07-01 18:03
              收起回复
                为啥要设计一个未扣卡数量 如果查询数据库一条sql就搞定了 不用这么麻烦吧


                IP属地:河南8楼2023-07-01 21:18
                收起回复
                  这业务 单体加锁1s完成1000次完全不是问题,有什么好设计的。有那么大的业务量?


                  IP属地:江苏来自Android客户端9楼2023-07-01 21:39
                  收起回复
                    可以参考秒杀下的redis并发减库存的场景,一般都是把库存放到redis里面,直接对redis减库存,然后异步的修改数据库的库存。


                    IP属地:广东来自Android客户端10楼2023-07-02 00:56
                    收起回复
                      看看分布式事物框架,不依赖数据库提供的那个事物的


                      IP属地:广西来自Android客户端11楼2023-07-02 01:04
                      收起回复
                        你这个其实就是高并发下库存扣减的场景。redis重置失败就失败好了,不影响实际业务,不会超,这里你需要告警感知到这个事情发生,另外就是需要一个扫描频率比较高的定时任务去做对账,把不一致的数据修回来


                        IP属地:江西来自Android客户端12楼2023-07-02 01:33
                        收起回复
                          经典的seata分布式事务问题吧


                          IP属地:北京来自Android客户端13楼2023-07-02 06:00
                          收起回复
                            手动回滚,把库存再加5,这样计算下来可用还是5,然后未扣卡数量应该减5而不是重置为0,不然会有问题


                            IP属地:湖南来自Android客户端14楼2023-07-02 08:52
                            回复
                              你的问题在于未扣卡数量和库存实际扣减没有在一个事务里。正常应该都在一个事务内的。
                              保证跨数据源种类的事务一致,一般都得自己去实现了,mongodb想要实现类似事务操作应该是需要副本。


                              IP属地:辽宁15楼2023-07-03 13:51
                              回复