目前看到两种方法。 一种是用 string 类型直接存库存大小,减库存减掉数字的大小就可以了。有人说在高并发时,库存有可能减到负数。 一种是用 list 类型创建与库存大小一致的数据。减库存移除 list 中的元素,这样不会出现第一种的库存为负的问题。 我自己试了下了,使用第二种方法,如果库存量特别大时,创建缓存的会特别慢 请大佬指教一下😂
1
wudila 2020-07-15 16:45:35 +08:00
感觉只是计数的话 用第一种就好了.至于并发问题 可以增加一个分布式锁来解决
|
3
colia 2020-07-15 16:59:08 +08:00
redis 集群做的吗
|
4
TypeErrorNone 2020-07-15 16:59:38 +08:00
第一种,incr 操作,用 incr 返回的值做是否有剩余库存的判断
|
5
zhongjun96 2020-07-15 17:01:31 +08:00
incr 返回值大于 0 就行了
|
6
xuanbg 2020-07-15 17:02:25 +08:00 1
@Ashenone0 抢购可以先用令牌桶限流,只有有资格的才能购买。你见过电影院检票口阻塞吗?因为卖票的地方给挡住了流量,所以检票就可以很从容。
|
7
TypeErrorNone 2020-07-15 17:04:17 +08:00
@xuanbg 套娃...抢票怎么处理,如果超发了很多,都过来检票了
|
8
nicreve 2020-07-15 17:07:37 +08:00
如果本身没有扣减库存后购买失败需要加回库存的需求的话,单纯执行 DECR,业务侧判断返回值是否>=0 就可以了。
稍微复杂点的话就通过 Lua 脚本在 Redis 侧做下简单的处理,只有库存大于 0 时可以 DECR,然后把是否扣减了返回给业务侧。 |
9
xuanbg 2020-07-15 17:10:52 +08:00
@TypeErrorNone 令牌桶里面令牌发完了就完了啊,怎么可能超发?不过为了避免有些人拿到令牌不下单,一般都会合理设置一些余量,譬如商品 100,那就发 150 个令牌。然后下单减库存加锁避免超卖就行了。
|
11
Philippa 2020-07-15 17:39:32 +08:00 via iPhone
我从没做过这类业务,但感觉抢购主要是超售,售少了几个没关系可以继续卖。用一个 list,来订单就 pop,pop 失败了就返回失败。成功了再生成订单。有些人不付款,超时后把队列填回去就好了。用 incrby 还是 decrby 都要查询,查询这个动作会消耗额外一次网络传输。即使用 pipeline,那也要做两个操作。相反,list 做修改时它本来就是用 quicklist 的,pop 的时候就必须检查长度。同时两端 pop 和 append 操作都是 O(1)操作。当然 load balance 首先要限制 ratelimit,不要直接把 redis 打爆了。订单一定要用 acid 的数据库来保存。中间还可以加个队列。
|
12
huntcool001 2020-07-15 17:55:33 +08:00
"如果库存量特别大时,创建缓存的会特别慢 "
你提前建立好库存不就行了, 又不是一边秒杀一边建,时间长一点没什么. 而且用 pipeline,别一个一个添加到 list 里. |
13
wudila 2020-07-15 18:02:43 +08:00
@Ashenone0 看你并发流量有多大了.一般情况下这样就行了.流量很大的话可以增加一个队列 异步处理.其实像其他人说的用 incr 的返回值判断下也可以.因为 redis 是单线程的
|
14
312ybj 2020-07-15 19:34:17 +08:00 via Android
流量不大,都可以。 大的话,就得加锁了,肯定会有效率的问题,redis 可以用 redisson 实现分布式群
|
15
yc8332 2020-07-16 09:25:08 +08:00
redis 只保存自增啊,看你是要减还是加,最后的判断是在业务逻辑,比如减到小于 0,那说明库存不足,然后给加回去。。报库存不足就行了
|
16
Ashenone0 OP @huntcool001 😂刚接触 redis,不知道有 pipeline 。一条条创建发现太慢了,用了 pipeline 基本是无延迟创建 list 。谢谢
|