栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

项目场景:

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


问题描述:

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

    @Test
    void contextLoads() {
        ConcurrencyTester tester = ThreadUtil.concurrencyTest(10000, () -> {
            // 测试的逻辑内容
            HttpUtil.get("http://localhost:9952/getOrder");
        });
    }
        String order = "12306";
        String name = Thread.currentThread().getName();
        
        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();
        
        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));
        }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/710978.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号