php 高并发余额正确_高并发下怎么做余额扣减?

取决于是计费高并发,还是用户高并发。

前者是同一账户,同时并发多个计费请求,导致余额变化,好像一个银行账户,多个银行卡,同时刷卡买东西;后者是多个用户在线,用各自的账户消费,互不影响。

看题设,更像是前者,就基于计费高并发来讨论。

曾遇到过一个需求,每个账户每秒有几百次计费请求,要求很简单,

1,又快又准。

2,余额不为负。

同一个字段被并发修改,很自然会想到用lock,但系统有很多其他业务逻辑,计费只是很小的一部分,要足够的轻,就开始考虑尽量无锁的方案。大概思路如下,

记录持久化,余额内存化。

余额是充值和消费的结果,在不断变化,但充值和消费是记录,一旦发生,不会再变,某时某刻花了10块,这条记录产生了,就永远不会变。这类记录持久化,放在DB里。

有了记录,可以在任何时刻,重建余额。这个余额是否需要持久化,不一定,还要考虑是否存在过期等。我们虽选择持久化余额,但不加锁,因为读写不发生在DB上,而是在内存里。

内存里,用户有两个值,一个是余额,一个是花费。用户消费时,余额不变,花费增加。两个问题,

为什不直接减余额呢?

不改余额,就可以保证内存里的余额始终和DB中的一致,而内存里花费始终和消费记录一致。用户的实时余额 = 余额 - 花费。

内存计费是否加锁?

余额不为负,意味着要先确认实时余额 > 所需花费,才能消费,check, then update,这并不是atomic 的,意味着存在 race condition,计费函数是不是一定要加锁呢?

如果先查余额,再扣钱,的确要加锁;但也可以先扣钱,再查余额,若小于0,则把钱加回来,返回计费失败,阻止消费,这样就不用加锁了。当然,余额和花费应选Atomic数据类型。

这样高并发下的余额扣减就变得非常的轻,对 performance 几乎没有影响,也满足了又快又准的需求。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值