V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Ashenone0
V2EX  ›  PHP

关于用 redis 判断库存的问题

  •  
  •   Ashenone0 · 2020-07-15 16:36:16 +08:00 · 3513 次点击
    这是一个创建于 1374 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前看到两种方法。 一种是用 string 类型直接存库存大小,减库存减掉数字的大小就可以了。有人说在高并发时,库存有可能减到负数。 一种是用 list 类型创建与库存大小一致的数据。减库存移除 list 中的元素,这样不会出现第一种的库存为负的问题。 我自己试了下了,使用第二种方法,如果库存量特别大时,创建缓存的会特别慢 请大佬指教一下😂

    16 条回复    2020-07-16 22:57:25 +08:00
    wudila
        1
    wudila  
       2020-07-15 16:45:35 +08:00
    感觉只是计数的话 用第一种就好了.至于并发问题 可以增加一个分布式锁来解决
    Ashenone0
        2
    Ashenone0  
    OP
       2020-07-15 16:57:21 +08:00
    @wudila 类似抢购的那种的话,用第一种+分布式锁是吗?
    colia
        3
    colia  
       2020-07-15 16:59:08 +08:00
    redis 集群做的吗
    TypeErrorNone
        4
    TypeErrorNone  
       2020-07-15 16:59:38 +08:00
    第一种,incr 操作,用 incr 返回的值做是否有剩余库存的判断
    zhongjun96
        5
    zhongjun96  
       2020-07-15 17:01:31 +08:00
    incr 返回值大于 0 就行了
    xuanbg
        6
    xuanbg  
       2020-07-15 17:02:25 +08:00   ❤️ 1
    @Ashenone0 抢购可以先用令牌桶限流,只有有资格的才能购买。你见过电影院检票口阻塞吗?因为卖票的地方给挡住了流量,所以检票就可以很从容。
    TypeErrorNone
        7
    TypeErrorNone  
       2020-07-15 17:04:17 +08:00
    @xuanbg 套娃...抢票怎么处理,如果超发了很多,都过来检票了
    nicreve
        8
    nicreve  
       2020-07-15 17:07:37 +08:00
    如果本身没有扣减库存后购买失败需要加回库存的需求的话,单纯执行 DECR,业务侧判断返回值是否>=0 就可以了。
    稍微复杂点的话就通过 Lua 脚本在 Redis 侧做下简单的处理,只有库存大于 0 时可以 DECR,然后把是否扣减了返回给业务侧。
    xuanbg
        9
    xuanbg  
       2020-07-15 17:10:52 +08:00
    @TypeErrorNone 令牌桶里面令牌发完了就完了啊,怎么可能超发?不过为了避免有些人拿到令牌不下单,一般都会合理设置一些余量,譬如商品 100,那就发 150 个令牌。然后下单减库存加锁避免超卖就行了。
    sujin190
        10
    sujin190  
       2020-07-15 17:13:46 +08:00
    @nicreve #8 不可能没有下单失败补回库存的情况吧,存件减又必须在下单前
    Philippa
        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 的数据库来保存。中间还可以加个队列。
    huntcool001
        12
    huntcool001  
       2020-07-15 17:55:33 +08:00
    "如果库存量特别大时,创建缓存的会特别慢 "

    你提前建立好库存不就行了, 又不是一边秒杀一边建,时间长一点没什么. 而且用 pipeline,别一个一个添加到 list 里.
    wudila
        13
    wudila  
       2020-07-15 18:02:43 +08:00
    @Ashenone0 看你并发流量有多大了.一般情况下这样就行了.流量很大的话可以增加一个队列 异步处理.其实像其他人说的用 incr 的返回值判断下也可以.因为 redis 是单线程的
    312ybj
        14
    312ybj  
       2020-07-15 19:34:17 +08:00 via Android
    流量不大,都可以。 大的话,就得加锁了,肯定会有效率的问题,redis 可以用 redisson 实现分布式群
    yc8332
        15
    yc8332  
       2020-07-16 09:25:08 +08:00
    redis 只保存自增啊,看你是要减还是加,最后的判断是在业务逻辑,比如减到小于 0,那说明库存不足,然后给加回去。。报库存不足就行了
    Ashenone0
        16
    Ashenone0  
    OP
       2020-07-16 22:57:25 +08:00
    @huntcool001 😂刚接触 redis,不知道有 pipeline 。一条条创建发现太慢了,用了 pipeline 基本是无延迟创建 list 。谢谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   922 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 22:11 · PVG 06:11 · LAX 15:11 · JFK 18:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.