高并发下怎么做余额扣减?

2022-11-25 17:10:18 +08:00
 hhhhhh123

这种场景 数据库 是不是只能加锁啊?
假设 数据库中有两个表 一个是流水表 也就是扣款用, 一个是 userinfo 就是余额在这看
那么并发场景下。怎么保证余额是>0 且数据无误。

我的想法是。1 查询余额 如果减去后余额 >=0 则插入扣款后的余额, 这个过程中加锁。 但是这种如果是并发高一点的话是不是很慢啊?

各位有这块的经验吗? 希望可以指点一下。或者也可以讲解一下你们公司的扣款逻辑是啥? 是如何做的 ?

6905 次点击
所在节点    程序员
40 条回复
rqrq
2022-11-26 01:20:13 +08:00
BEGIN 写在 try 外面。
brust
2022-11-26 07:56:04 +08:00
@hhhhhh123 #8
库存的话
如果是热点 SKU 可以分段锁 比如有 1w 个库存 可以分成 10 个 1000 出来
yogogo
2022-11-26 08:09:52 +08:00
事务加行锁,扣款交易可以先入库,再用异步任务按顺序执行交易扣款。有些第三方代扣服务就是这样设计的
dingyaguang117
2022-11-26 08:29:52 +08:00
乐观锁即可
reeco
2022-11-26 08:46:13 +08:00
实操都是 tcc ,两步提交
love2328
2022-11-26 08:53:33 +08:00
你的想法怕慢 实际不会很慢 并发是同等触发 实际触发时并没有的
xyjincan
2022-11-26 09:15:34 +08:00
@love2328 有一次网卡,连点很多下,10 冲了 50
mrpzx001
2022-11-26 09:22:29 +08:00
用事务不就完事了吗? 怎么都不提事务的?
8355
2022-11-26 10:13:21 +08:00
用户级别并发锁行锁不就可以了吗

改个余额
加订单入库
加资金流水能有几张表
能慢到哪里去啊
你这个下单接口高峰 qps 能有 1000 吗
iseki
2022-11-26 11:30:05 +08:00
如果是扣库存,只要保证别 100 个商品,结果 10000 个请求打到数据库上、也别同一时间点 100 个请求全都在数据库上扣同一个商品,就没什么可担心的,数据库的性能足够。
扣余额就更简单了,限制下不要让一个用户同时发起一堆请求(这本来也该限制吧)
实现上可以用 update cas ,但存在限制不方便时直接 Serializable 性能不一定差( PostgreSQL )
love2328
2022-11-26 11:44:51 +08:00
@xyjincan 点的时候 没有置等待 ? 要么场景不够经验 要么坑用户
8520ccc
2022-11-26 11:48:19 +08:00
@ElmerZhang update xxx set amount = amount - A where amount = B where amount-A>0
codehz
2022-11-26 11:49:18 +08:00
@ElmerZhang 那不如直接 update xxx set amount = amount - A where amount > A (
chenqh
2022-11-26 12:48:53 +08:00
用 redis 锁不就好了吗?
vanillacloud
2022-11-26 12:56:01 +08:00
我觉得在 update 时 「 where 余额 = 扣款前查询的余额」这一步就能规避重复操作的风险,这不能当 standard procedure 吗?
noogel
2022-11-26 13:33:16 +08:00
高并发扣减:
1. 合并请求,在保证事务的前提下,将多个扣款请求合并操作,这样只需要做一次锁操作和写操作。
2. 拆分账户,将热点账户的余额账户拆分成多个子余额账户,以此来降低单个账户扣减操作的并发度。
3. 使用内存数据库扣减,并异步写日志,所有日志结果可以回溯账户余额结果,和内存数据库做对账。
LucasLee92
2022-11-27 11:09:02 +08:00
@noogel 1 和 2 的处理对热点账户的处理都只考虑怎么解决记账问题
1 的问题在于合并记账后余额不足的怎么处理,可能拆分记有些还能成功
2 的问题在于多个账户如何协同管理
3 的实现最终还是会碰到热点账户问题,当然效率比起数据库来说要好很多了
不清楚是否有相应的成熟业务的解决方案文章能看看
hhhhhh123
2022-11-28 09:36:05 +08:00
@ElmerZhang 我理解 第一步和第二步 ,第三部不是特别理解, 为啥只递归一次?
hhhhhh123
2022-11-28 09:41:58 +08:00
@vanillacloud @codehz @8520ccc @richangfan 如果这样的话, 同时有俩个 一个扣款 10 块 一个扣款 5 块。 这样只会执行其中的一个余额。 另外一个就不会执行。 我觉得 8 楼的 第三个条件挺好, 但是递归次数 又不好拿捏。
hhhhhh123
2022-11-28 09:46:21 +08:00
我的新思路是 : 只要保证每个请求都是正确的扣钱请求。 然后参考 8 楼, 当然第三个条件只能是一直递归下去, 吧所有的请求都给操作完。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/897920

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX