使用 Redis 计数的问题

2019-09-19 11:11:08 +08:00
 mamasan

比如有个业务需求售卖某种商品, 为了防止超发, 使用 redis 原子计数.

但是 incr 是, 如果 key 未命中会从 0 从新开始.

那是不是这种情况就不能用 redis 去做计数了?

15069 次点击
所在节点    Redis
21 条回复
optional
2019-09-19 11:13:23 +08:00
我的方案,写一个 incrNx 的 lua 脚本
tt67wq
2019-09-19 11:21:02 +08:00
自减呢?
zpfhbyx
2019-09-19 13:18:32 +08:00
商品如果数量不是很大的话,搞个 redis 的队列,卖一个取一个啊.
zjsxwc
2019-09-19 13:29:12 +08:00
最简单是跑个进程检查新支付的订单是否超卖,发现超卖就退款取消订单

fluorinedog
2019-09-19 13:45:32 +08:00
用 decr 啊,先把商品数量仍进 redis
mamasan
2019-09-19 14:30:04 +08:00
decr 一样也会未命中啊, 那不是少发了?
x537196
2019-09-19 14:45:25 +08:00
一般使用 3L 的方案
Thinklong
2019-09-19 15:44:46 +08:00
你们都是几年的工程师?还在用队列或者自减?用分布式锁啊 setnx
0NF09LJPS51k57uH
2019-09-19 16:31:31 +08:00
为什么会未命中?感觉 incr 和 decr 没问题啊,我项目里用这个限制桶大小,一年多了没出现过这个问题。
0NF09LJPS51k57uH
2019-09-19 16:33:40 +08:00
@Thinklong setnx 如何实现可重入?退一步讲有简单的方案没必要用分布式锁,本身就是高并发场景,增加 io 开销确定是好方案吗?
yc8332
2019-09-19 16:58:34 +08:00
哪里会有命中问题啊?你是不是对命中的理解有偏差。。。未命中是说缓存中没有需要去数据库取,你这种计数的不存在这种问题。
sujin190
2019-09-19 17:44:10 +08:00
@phantomzz #10 先加判断超过了,然后下单失败再减下来?
如果是做成锁的话,本来就不可重入吧,什么时候锁也可以重入了

楼主的问题是是不是商品一直在卖,担心中间有空闲再开卖有可能 redis key 不存在了,然后可能会超?其实感觉如果你用来做库存限制,那么 redis 就不应该是缓存,而应该是持久化数据库,所以 key 不应该超时,持久化要开,每次商品修改也要同步更新 redis 值才行吧,否则就做成分布式锁吧,库存的更新检查还是以数据库为主
0NF09LJPS51k57uH
2019-09-19 19:19:36 +08:00
@sujin190

考虑再三还是决定回你一下,如果不知道可重入锁,并发编程的书再去看一看。入门知识,你应该毕业不久。

在高并发场景下,不建议直接读写数据库,建议 缓存+队列 实现 异步+削峰,redis 控制超卖(不谈风控),然后丢进队列,中 /后台慢慢消费,异步处理订单后续流程。使用分布式锁+DB 去同步处理订单,增加不必要的 IO 开销。这些例子网上都烂大街了,可以到处去找来看一看
earther01
2019-09-19 19:24:45 +08:00
我想知道针对楼主防止超卖的问题,把库存提前加进 redis 里,每次卖出一个就原子减一,减到小于 0 就报无库存,有啥问题?
0NF09LJPS51k57uH
2019-09-19 19:33:14 +08:00
@earther01 楼主应该对 redis 的 hit 和 miss 有一点点误解,按照他的提问,我猜测他的理解应该是:访问一个 redis 中实际存在的 key,是有几率 miss 的…
sujin190
2019-09-19 21:39:15 +08:00
@phantomzz #13 如果你说的是操作系统那个可重入锁的话,认真说这真是个很不严谨且偷懒的设计,web 这种场景中更不应该出现,难道你只加锁不解锁的么,需要啥重入

而且你这给出建议不考虑实际场景啊,大多数情况下,加个锁增加的 io 多还是队列异步中后台一大串 io 多,还不说维护复杂性在那呢,大多数场景下,加锁加直接该数据库库存是最容易实现最容易维护最容易稳定的方案了,能在这种情况下用满数据库 IO 的都已经是很高销售额了
dusu
2019-09-20 00:54:00 +08:00
inc 和 dec 都需要额外处理高并发下一次购买多件的问题
zuicaidenage
2019-09-20 09:54:09 +08:00
lua 了解一下
capljf
2019-09-20 10:35:18 +08:00
如果库存有变更 新增库存或者分销走一部分库存 ,那 inc 和 dec 都不好使了吧。看业务场景
Aresxue
2019-09-20 10:46:28 +08:00
@phantomzz 你这种方式可以说是很快的一种方案了,业务要求没那么严格的话(比如 5000 件不能超卖但是可以少一小部分)是一个很不错的方案,但如果要求强一致性的业务(5000 件都要卖完不多不少或者少的数量有严格限制要低于多少),你异步处理的回滚可能不够及时导致最终少卖了一部分,这时候其实是有必要上分布式锁的,为了一致性性能是要牺牲一些的。所以说来说去还是那句废话,看业务。。。

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

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

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

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

© 2021 V2EX