关于使用 redisson 分布式锁出现的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
eefnrowe
V2EX    Java

关于使用 redisson 分布式锁出现的问题

  •  
  •   eefnrowe 2019-06-05 11:43:25 +08:00 4799 次点击
    这是一个创建于 2395 天前的主题,其中的信息可能已经有所发展或是发生改变。
    先贴一段简单 code:

    //红包锁 redis_lock:redpacket:${redPacketId}
    String lockName = RedisKeys.buildDistributedLockKey("redpacket", redPacketId);
    RLock rLock = redissonClient.getLock(lockName);

    //用户锁 redis_lock:redpacket_userid:${userId}
    String lockUserName = RedisKeys.buidDistributedLockKey("redpacket_userid", userId);
    RLock lockUser = redissonClient.getLock(lockUserName);

    try {
    rLock.lock(10, TimeUnit.SECONDS);
    lockUser.lock(10, TimeUnit.SECONDS);

    //抢红包
    return doUnpack(redPacketId);

    } finally {
    lockUser.unlock();
    rLock.unlock();
    }



    ----------------

    问题如果没有加 lockUser 锁的情况下:
    用 jmeter 测试 单用户 10 个线程并发, 持续测试 5-10 个用户左右, 就肯定会出现一个人执行了两次业务逻辑的问题,
    更加奇怪的是, 我业务逻辑也用 redis 做过重复领取红包的行为判断 用的是 redis set isMember 判断的, 那两次重复执行的请求中, 第二次却没有检查出来!!!

    所以我怀疑我是不是把 redis 哪里给玩坏了??

    ps: redis 配置很简单 就个单节点~
    11 条回复    2019-09-12 16:13:58 +08:00
    snappyone
        1
    snappyone  
       2019-06-05 13:26:47 +08:00
    你的目的是一个用户不能抢同一个红包多次吗?你的 isMember 检查是放在什么位置的呢
    eefnrowe
        2
    eefnrowe  
    OP
       2019-06-05 14:02:22 +08:00
    @snappyone 当然是放在 doUnpack 方法里靠前的

    String userIdsKey = RedisKeys.buildRedPacketUserIdsKey(redPacketId);
    if(redisTemplate.hasKey(userIdsKey)){
    Boolean member = redisTemplate.opsForSet().isMember(userIdsKey, userId);
    if(member){
    throw new CommonException(ResponseCode.ERROR, "不可重复领取此红包");
    }
    redisTemplate.opsForSet().add(userIdsKey, userId);
    }else{
    redisTemplate.opsForSet().add(userIdsKey, userId);
    redisTemplate.expire(userIdsKey, 1, TimeUnit.HOURS);
    }
    snappyone
        3
    snappyone  
       2019-06-05 14:27:55 +08:00
    @eefnrowe
    我感觉是你释放锁的问题,如果一个线程堵塞没拿到锁,在 finally 里面也把这个锁释放了,但是此时拥有锁的并不是他自己。试试 tryLock, 如果加锁失败则不要去释放锁
    eefnrowe
        4
    eefnrowe  
    OP
       2019-06-05 14:55:48 +08:00
    @snappyone tryLock 的 waitTime 跟 leaseTime 设值有什么讲究吗
    eefnrowe
        5
    eefnrowe  
    OP
       2019-06-05 15:28:44 +08:00
    @snappyone

    //红包锁 redis_lock:redpacket:${redPacketId}
    String lockName = RedisKeys.buildDistributedLockKey("redpacket", redPacketId);
    RLock rLock = redissonClient.getLock(lockName);
    try {
    boolean b = rLock.tryLock(3, 10, TimeUnit.SECONDS);
    if(b){
    return doUnpack(redPacketId);
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    } finally {
    rLock.unlock();
    }
    eefnrowe
        6
    eefnrowe  
    OP
       2019-06-05 15:29:15 +08:00
    @snappyone 一样有类似问题
    snappyone
        7
    snappyone  
       2019-06-05 15:34:34 +08:00
    @eefnrowe 我貌似看错了,把 lock 后面的时间看做 waittime 了,不过你可以试下 trylock, 就设置个 5s 就行
    eefnrowe
        8
    eefnrowe  
    OP
       2019-06-05 15:42:36 +08:00
    @snappyone 已经试过啦, 等待 3/5 , 10 超时都试过~ 我有点怀疑是其他环节的问题了..
    ysweics
        9
    ysweics  
       2019-06-05 15:44:38 +08:00
    把红包和用户的两个 key 组装成一个 key,然后只锁一个 key=redpacketid:userid
    eefnrowe
        10
    eefnrowe  
    OP
       2019-06-05 16:13:10 +08:00
    @ysweics 这样红包领取就没有排队机制啦.. 粒度到了用户级别..
    734695609
        11
    734695609  
       2019-09-12 16:13:58 +08:00
    @eefnrowe
    你的问题:如果没有加 lockUser 锁的情况下
    doUnpack 逻辑有问题。
    你只把红包锁住,一个用户的 2 次并发访问,在你的逻辑中,可能都运行到 if(redisTemplate.hasKey(userIdsKey))
    都没有 userIdsKey,所以加了两条,
    当你在 redisson 中加上用户锁时,一个用户的两次并发请求就不会运行到下面的代码了

    我反而有一个问题,在 redisson 的官方文档中
    https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8
    你在 lock 时

    // 加锁以后 10 秒钟自动解锁 官方解释
    // 无需调用 unlock 方法手动解锁 官方解释
    rLock.lock(10, TimeUnit.SECONDS);

    这句代码官方解释是 10 秒后自动解锁,这样的话如果你的业务代码大于 10 秒或者因为某些原因等待超过 10 秒,会不会导致锁被释放掉,锁失效。
    所以我感觉不加时间才是对的,除非你业务需要
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     917 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 22:30 PVG 06:30 LAX 14:30 JFK 17:30
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86