首页 > 其他分享 >定制直播软件,分布式锁的演进你了解多少?

定制直播软件,分布式锁的演进你了解多少?

时间:2024-08-03 09:28:48浏览次数:5  
标签:Map return 演进 categoriesDb lock getCatalogJsonDbWithRedisLock 直播 stringRedisTemp

定制直播软件,分布式锁的演进你了解多少?

分布式锁的演进

基本原理
我们可以同时去一个地方“占坑”,如果占到,就执行逻辑。否则就必须等待,直到释放锁。“占坑”可以去redis,可以去数据库,可以去任何大家都能访问的地方。等待可以自旋的方式。

阶段一

 

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
        //阶段一
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111");
        //获取到锁,执行业务
        if (lock) {
            Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
            //删除锁,如果在此之前报错或宕机会造成死锁
            stringRedisTemplate.delete("lock");
            return categoriesDb;
        }else {
            //没获取到锁,等待100ms重试
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonDbWithRedisLock();
        }
    }
 
public Map<String, List<Catalog2Vo>> getCategoryMap() {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        String catalogJson = ops.get("catalogJson");
        if (StringUtils.isEmpty(catalogJson)) {
            System.out.println("缓存不命中,准备查询数据库。。。");
            Map<String, List<Catalog2Vo>> categoriesDb= getCategoriesDb();
            String toJSONString = JSON.toJSONString(categoriesDb);
            ops.set("catalogJson", toJSONString);
            return categoriesDb;
        }
        System.out.println("缓存命中。。。。");
        Map<String, List<Catalog2Vo>> listMap = JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Catalog2Vo>>>() {});
        return listMap;
    }

 

问题: setnx占好了位,业务代码异常或者程序在页面过程中宕机。没有执行删除锁逻辑,这就造成了死锁

解决: 设置锁的自动过期,即使没有删除,会自动删除

阶段二

 

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111");
        if (lock) {
            //设置过期时间
            stringRedisTemplate.expire("lock", 30, TimeUnit.SECONDS);
            Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
            stringRedisTemplate.delete("lock");
            return categoriesDb;
        }else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonDbWithRedisLock();
        }
    }

 

问题: setnx设置好,正要去设置过期时间,宕机。又死锁了。

解决: 设置过期时间和占位必须是原子的。redis支持使用setnx ex命令。

阶段三

 

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
    //加锁的同时设置过期时间,二者是原子性操作
    Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "1111",5, TimeUnit.SECONDS);
    if (lock) {
        Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
        //模拟超长的业务执行时间
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stringRedisTemplate.delete("lock");
        return categoriesDb;
    }else {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getCatalogJsonDbWithRedisLock();
    }
}

 

问题: 删除锁直接删除???如果由于业务时间很长,锁自己过期了,我们直接删除,有可能把别人正在持有的锁删除了。

解决: 占锁的时候,值指定为uuid,每个人匹配是自己的锁才删除。

阶段四

 

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
        String uuid = UUID.randomUUID().toString();
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
      //为当前锁设置唯一的uuid,只有当uuid相同时才会进行删除锁的操作
        Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS);
        if (lock) {
            Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
            String lockValue = ops.get("lock");
            if (lockValue.equals(uuid)) {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                stringRedisTemplate.delete("lock");
            }
            return categoriesDb;
        }else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonDbWithRedisLock();
        }
    }

 

问题: 如果正好判断是当前值,正要删除锁的时候,锁已经过期,别人已经设置到了新的值。那么我们删除的是别人的锁

解决: 删除锁必须保证原子性。使用redis+Lua脚本完成

阶段五-最终形态

 

public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
        String uuid = UUID.randomUUID().toString();
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS);
        if (lock) {
            Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
            String lockValue = ops.get("lock");
            String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                    "    return redis.call(\"del\",KEYS[1])\n" +
                    "else\n" +
                    "    return 0\n" +
                    "end";
            stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), lockValue);
            return categoriesDb;
        }else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getCatalogJsonDbWithRedisLock();
        }
    }

 

保证加锁【占位+过期时间】和删除锁【判断+删除】的原子性。更难的事情,锁的自动续期。

以上就是定制直播软件,分布式锁的演进你了解多少?, 更多内容欢迎关注之后的文章

标签:Map,return,演进,categoriesDb,lock,getCatalogJsonDbWithRedisLock,直播,stringRedisTemp
From: https://www.cnblogs.com/yunbaomengnan/p/18340041

相关文章

  • 直播软件怎么开发,你还在为如何创建线程池发愁吗?
    直播软件怎么开发,你还在为如何创建线程池发愁吗?为什么要使用多线程提高响应速度:对于耗时操作,使用线程可以避免阻塞主线程,提高应用程序的响应速度。实现并行操作:在多CPU系统中,使用线程可以并行处理任务,提高CPU利用率。改善程序结构:将一个既长又复杂的进程分为多个线程,可以使其......
  • 成品app直播源码搭建,常用数据处理手段代码分析
    成品app直播源码搭建,常用数据处理手段代码分析数据合并数据准备首先定义一个DataFrame数据集:importpandasaspddf_a=pd.DataFrame(columns=['name','rank'],data=[['C',1],['java',2],['python',3],['golang',4]])df_b......
  • Datawhale AI夏令营(AI+生命科学)深度学习-Task3直播笔记
    机器学习lgm上分思路    1、引入新特征(1)对于Task2特征的再刻画        GC含量是siRNA效率中的一个重要且基本的参数,可以作为模型预测的特征。这是因为低GC含量会导致非特异性和较弱的结合,而高GC含量可能会阻碍siRNA双链在解旋酶和RISC复合体作用下的解旋。......
  • ElasticSearch分布式搜索引擎原理与代码实例讲解
    ElasticSearch分布式搜索引擎原理与代码实例讲解1.背景介绍1.1问题的由来在当今的数字时代,海量的数据被不断产生和存储。如何高效地检索和管理这些庞大的数据集成为了一个关键挑战。传统的关系型数据库虽然在事务处理和数据一致性方面表现出色,但在处理非结构化数据和......
  • 最大努力通知【分布式事务解决方案】
    优质博文:IT-BLOG-CN一、概述最大努力通知也是一种解决分布式事务的方案,下面是一个充值的例子:交互流程:【1】账户系统调用充值系统接口;【2】充值系统完成支付处理向账户系统发起充值结果通知,若通知失败,则充值系统按策略进行重复通知;【3】账户系统接收到充值结果通知修......
  • 万字干货:从消息流平台Serverless之路,看Serverless标准演进
    摘要:如今,Serverless化已经成为消息流平台发展的新趋势,而如何更好地基于Serverless化的消息流平台进行应用设计和开发,则成为了一个值得思考的问题。本文分享自华为云社区《9000字干货:从消息流平台Serverless之路,看Serverless标准演进》,作者:华为云PaaS服务小智。这是一个最美好的......
  • 淘客返利系统中的分布式事务处理与保障一致性的方案
    淘客返利系统中的分布式事务处理与保障一致性的方案大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨如何在淘客返利系统中处理分布式事务,并确保数据的一致性。分布式事务处理是微服务架构中的一个关键问题,它涉及到多个服务和数据库的......
  • [分布式]并发访问
    分布式系统设计中的并发访问解决方案|得物技术引言随着互联网信息技术的飞速发展,数据量不断增大,业务逻辑也日趋复杂,对系统的高并发访问、海量数据处理的场景也越来越多。如何用较低成本实现系统的高可用、易伸缩、可扩展等目标就显得越发重要。为了解决这一系列问题,系统架构也......
  • 从零构建直播生态系统:直播软件平台源码的完整搭建指南
    开发一个直播软件平台源码的完整流程涉及精细规划、技术决策、环境配置、功能实现、服务集成以及最终部署等多个关键环节。以下是一个全新的、详尽的步骤指南:需求分析与规划市场调研:首先,进行市场调研,了解目标用户群体的需求,以及竞争对手的产品特点。功能规划:基于调研结果,明确......
  • 分享一些直播软件的测试点
    归纳了的几个直播软件的测试点,并附上思维导图。UI测试1、UI设计是否符合设计稿2、内容测试输入框说明文字的内容与产品需求一致是否有错别字3、导航测试,不同的连接页面之间导航链接是否有效,是否跳转是否正确4、图形测试自适应界面设计,内容根据窗口大小自适应旋转......