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

news/2025/3/26 18:45:33/文章来源:https://www.cnblogs.com/yunbaomengnan/p/18340041

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

分布式锁的演进

基本原理
我们可以同时去一个地方“占坑”,如果占到,就执行逻辑。否则就必须等待,直到释放锁。“占坑”可以去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();}}

 

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/777062.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TinyVue v3.17.0 正式发布,推出了一款基于 Quill 2.0 的富文本编辑器,功能强大、开箱即用!

你好,我是 Kagol。 我们非常高兴地宣布,2024年6月26日,TinyVue 发布了 v3.17.0 🎉。 TinyVue 每次大版本发布,都会给大家带来一些实用的新特性,上一个版本我们重构了 chart-core,新增 CircleProcessChart 圆环进度图等6个新的图表组件,并增加了 Statistic 数据统计组件…

成品app直播源码搭建,常用数据处理手段代码分析

成品app直播源码搭建,常用数据处理手段代码分析数据合并数据准备首先定义一个 DataFrame 数据集:import pandas as pddf_a = pd.DataFrame(columns=[name, rank], data=[[C, 1], [java, 2], [python, 3], [golang, 4]]) df_b = pd.DataFrame(columns=[name, year], data=[[ja…

VUE动态路由和按钮的实现

动态路由 动态菜单 //通过循环组件完成动态菜单<el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" text-color="#fff":collapse="isCollapse" router default-active sty…

最小圆覆盖

性质一:最小圆覆盖是唯一的 证:若存在两个最小圆,如下显然所有点只能存在于两个圆的交集中,于是以中间那条实心蓝线为直径做一个圆,这个圆显然更小而且能够覆盖所有点 性质二:若我们已经用最小覆盖圆覆盖了所有点,设这些点的点集为\(S\),现在我们新加入一个点\(p\),若…

匈牙利算法--二分图的最大匹配

匈牙利算法--二分图的最大匹配给定一个二分图,其中左半部包含 n1个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m 条边。 数据保证任意一条边的两个端点都不可能在同一部分中。 请你求出二分图的最大匹配数。二分图的匹配:给定一个二分图 G,在 G的一…

vsftpd源码学习(一)

文件介绍文件名 作用access.c 定义了检查有无权限访问指定文件的函数ascii.c 定义了二进制数据转ascii数据的函数banner.c 定义了提示信息相关函数main.c 定义了主函数oneprocess.c 定义了单进程方式相关的函数twoprocess.c 定义了多进程方式相关的函数makefile vsftpd的makefi…

洛谷P3369 普通平衡树之板子

洛谷P3369题解 传送锚点 摸鱼环节 【模板】普通平衡树 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:插入一个数 \(x\)。 删除一个数 \(x\)(若有多个相同的数,应只删除一个)。 定义排名为比当前数小的数的个数 \(+1\)。查询 \(x\…

读零信任网络:在不可信网络中构建安全系统07设备信任

设备安全1. 设备信任 1.1. 在零信任网络中建立设备信任至关重要,这也是非常困难的一个环节 1.2. 建立设备信任是基石,直接影响零信任网络架构的成败 1.3. 大多数网络安全事件都和攻击者获得信任设备的控制权相关,这种情况一旦发生,信任就将被彻底瓦解,无法通过设备来确保安…

GPGPU技术杂谈

GPGPU技术杂谈1.GPGPU行业概述GPU最初的设计目标是为了提升计算机对图形、图像、视频等数据的处理性能,解决CPU在图形图像领域处理效率低的难题。随着GPU在并行计算方面性能优势的逐步显现以及并行计算应用范围的逐步拓展,GPU逐渐分化成两条分支,一条是传统意义的GPU,延续专…

C++编译错误的正确查找方式

C++编译错误的正确查找方式 在VS2019或者2022中,代码发生错误: 1、自己排查 2、自己排除不了,就复制错误的代码提示到浏览器查看,然后看到的是CSDN文章 推荐去编译器官网查找,你会发现新大陆!查找编译器错误链接: https://learn.microsoft.com/zh-cn/cpp/error-messages…

音视频相关

1.音视频相关 1.一些基本数据格式封装格式:MP4,RMVB,TS,FLV,AVI 视频编码数据:H.264,MPEG2,VC-1 音频编码数据:AAC,MP3,AC-3 视频像素数据:YUV420P,RGB 音频采样数据:PCM2.播放视频文件的流程 3.编码格式及工具 1)封装格式:视频码流和音频码流按照一定的格式存储在一个文…