Redisson——分布式锁引发的一场线上事故

2 篇文章 0 订阅

项目场景:

最近帮朋友看项目上分布式锁失效(暂时推测,实则不然)引起严重事故,他给我看了出事故的代码,描述相关的业务场景,分布式锁在他们项目里面一直都在使用,而且暂时没有出现相关问题。


问题描述:

第三方软件商会通过接口传输数据,为了避免数据重复(不想重复就让推送者控制一下呗,纯属个人唠叨,对业务不了解,所以不清楚为什么会出现重复推数据),将数据的为唯一标识用作分布式锁的key,在锁生效的时间内,不会接收重复的一批数据,就是这个分布式锁(使用姿势错了)没生效,这一天导致有大概6W左右的重复数据,出问题的代码我就不附上了,附我自己模拟的环境吧。
在这里插入图片描述

    @Test
    void contextLoads() {
        ConcurrencyTester tester = ThreadUtil.concurrencyTest(10000, () -> {
            // 测试的逻辑内容
            HttpUtil.get("http://localhost:9952/getOrder");
        });
    }
        String order = "12306";
        String name = Thread.currentThread().getName();
        /**
         * 获redis锁
         */
        if (RedisUtils.tryLock(order, TimeUnit.SECONDS, 2, 30)) {
            System.out.println(String.format("%s 抢到订单啦", name));
        } else {
            System.err.println(String.format("%s 抢订单失败", name));
        }

看了代码是不是觉得没什么问题呀,但是看实际打印结果,发现同一线程重复抢购了多次,他们怀疑是线程竞争引起的,我用上面的截图马上就打破了这种说法,因为重复抢购的都是同一个线程。


原因分析:

看到这个现象我也很疑惑,为啥都是同一个线程出的问题,其他线程都是好好的。
随后我就去看了一下官网文档对分布式锁的介绍,猜测引发事故的锁是:可重入锁(Reentrant Lock),为何这么说:可重入锁,在同一线程内,外层函数获得锁之后,内层递归函数仍然可以获取到该锁。 说白了就是同一个线程再次进入同样代码时,可以再次拿到该锁。 它的作用是:防止在同一线程中多次获取锁而导致死锁发生。这下就真相大白了,就有我个人相对应的解决方案了:换锁或者在此基础针对同一线程进行特殊处理。


解决方案:

在去设置锁之前先去校验锁的状态即可。

        String order = "12306";
        String name = Thread.currentThread().getName();
        /**
         * 获redis锁
         */
        if (!RedisUtils.isLock(order) &&RedisUtils.tryLock(order, TimeUnit.SECONDS, 2, 30)) {
            System.out.println(String.format("%s 抢到订单啦", name));
        } else {
            System.err.println(String.format("%s 抢订单失败", name));
        }

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值