IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> T31-DAY26(Redis分布式锁详解) -> 正文阅读

[大数据]T31-DAY26(Redis分布式锁详解)

Redis分布式锁前面几篇文章已经介绍过了。现在就有通俗易懂的方式再来讲一遍。

在进入正文之前,我们先带着问题去思考:

什么时候需要分布式锁?
加、解锁的代码位置有讲究么?
如何避免出现死锁
超时时间设置多少合适呢?
如何避免锁被其他线程释放
如何实现重入锁?
……

什么时候用分布式锁?

这里借用码哥的一个描述
精子喷射那一刻,亿级流量冲向卵子,只有一个精子能获得与卵子结合的幸运。

造物主为了保证只有一个「精子」能获得「卵子」的宠幸,当有一个精子进入后,卵子的外壳就会发生变化,将通道关闭把其余的精子阻挡在外。

亿级别的精子就好比「并发」流量;
卵子就好比是共享资源;
卵子外壳只允许一个精子进入的特殊蛋白就是一把锁。

而多节点构成的集群,就会有多个 JVM 进程,我们获得同样的效果就需要有一个中间人协调,只允许一个 JVM 中的一个线程获得操作共享资源的资格。
分布式锁就是用来控制同一时刻,只有一个 JVM 进程中的一个线程「精子」可以访问被保护的资源「卵子」。
「每一个生命,都是亿级选手中的佼佼者」,加油。
「每一个生命,都是亿级选手中的佼佼者」,加油。

分布式锁入门

分布式锁应该满足哪些特性?

互斥:在任何给定时刻,只有一个客户端可以持有锁;
无死锁:任何时刻都有可能获得锁,即使获取锁的客户端崩溃;
容错:只要大多数 Redis的节点都已经启动,客户端就可以获取和释放锁。

前面的文章说到了我们可以使用SETNX来加锁。
给大家描述一个场景:
大家敲代码一天累了,想去按摩放松放松。其中28号技师年轻漂亮服务好,大家都喜欢点,所以并发量大,需要分布式锁控制。
同一时刻只能有一个客户预约28号技师。
张三预约28号技师
在这里插入图片描述
这里可以看见张三预约技师成功了,李四再去预约。
在这里插入图片描述
李四约不上了,因为这段时间28号技师要服务张三这个客户。
此刻,申请成功的张三就可以享受 28号 技师的服务(共享资源)。
享受结束后,要及时释放锁,给后来者享受 28号 技师的服务机会。
那么这时候问题来了,要怎么去释放锁呢?
很简单。删除就好了。
在这里插入图片描述
在这里插入图片描述
事情可没这么简单。
这个方案存在一个存在造成锁无法释放的问题,造成该问题的场景如下:

在按摩过程中突然收到线上报警,提起裤子就跑去公司了,没及时执行 DEL 释放锁(客户端处理业务异常,无法正确释放锁);
按摩过程中心肌梗塞嗝屁了,无法执行 DEL指令。

这样,这个锁就会一直占用,锁在我手里,我挂了,这样其他客户端再也拿不到这个锁了。
这个比喻可能不是很好,换一种说法,拿共享充电宝举例子,你租用共享充电宝的时候,就相当于给这个充电宝(共享服务)上了锁,你归还就相当于释放了锁。你要是忘记了还,那么其他客户永远都没办法去租用你手上这个充电宝。这样讲大家是不是好理解多了。

说白了这种方案就是异常导致没有释放锁。
这时候我们可以想到,给锁设置一个超时时间。这样不就解决问题了吗。
Redis 2.6.X 之后,官方拓展了 SET 命令的参数,同时设置超时时间的语义,并且满足原子性。

SET key value NX PX 30000

PX 30000:表示这个锁有一个 30 秒自动过期时间。
在这里插入图片描述
TTL这里就是超时时间,当超过30秒的时候锁就自动删除了。
这样能稳妥的享受一条龙服务了么?
No,还有一种场景会导致释放别人的锁:

客户 1 获取锁成功并设置设置 30 秒超时;
客户 1 因为一些原因导致执行很慢(网络问题、发生 FullGC……),过了 30秒依然没执行完,但是锁过期「自动释放了」;
客户 2 申请加锁成功;
客户 1 执行完成,执行 DEL 释放锁指令,这个时候就把 客户 2的锁给释放了。

有两个关键问题需要解决:

如何合理设置过期时间?
如何避免删除别人持有的锁。

正确设置锁超时

这个时间不能瞎写,一般要根据在测试环境多次测试,然后压测多轮之后,比如计算出平均执行时间 200 ms。

那么锁的超时时间就放大为平均执行时间的 3~5 倍
因为如果锁的操作逻辑中有网络 IO操作、JVM FullGC 等,线上的网络不会总一帆风顺,我们要给网络抖动留有缓冲时间。

那我设置更大一点,比如设置 1 小时不是更安全?

不要钻牛角,多大算大?

设置时间过长,一旦发生宕机重启,就意味着 1 小时内,分布式锁的服务全部节点不可用。

你要让运维手动删除这个锁么?

只要运维真的不会打你。

当然这个方案并不是完美的,因为时间大小无论怎么设置都不合适。

我们可以让获得锁的线程开启一个守护线程,用来给快要过期的锁「续航」。

加锁的时候设置一个过期时间,同时客户端开启一个「守护线程」,定时去检测这个锁的失效时间。

如果快要过期,但是业务逻辑还没执行完成,自动对这个锁进行续期,重新设置过期时间。

你可能自己不会写,但是Redisson帮你解决了这个问题,并且当程序释放锁的时候,

redission还有广播机制通知其他等待线程可以去获取锁了,关于Redisson我就不多说了,上

一篇文章有讲这个问题。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:24:30  更:2021-11-22 12:25:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:45:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码