Redis分布式锁

ops/2024/9/25 10:36:06/

为什么需要分布式

在多线程环境中,如果多个线程同时访问共享资源(例如商品库存等秒杀场景下),会发生数据竞争,可能会导致出现脏数据或者系统问题,威胁到程序的正常运行。

我的项目中为了保证共享资源被安全的访问,使用了互斥锁对资源进行了保护,即同一时刻只有一个线程访问并修改资源,其他线程需要等到该线程释放才能去访问。

我们传统的单机多线程情况下:

Synchronized锁是锁本地的,属于JVM级别的(只能解决同一个jvm下多线程间的互斥),如果多个 JVM 进程共享同一份资源的话,使用本地锁就没办法实现资源的互斥访问了。因此我们引进了分布式锁。

分布式锁的定义

满足分布式系统下多进程可见并且互斥的锁。多个服务器(tomcat)之间可见的锁。

使用场景:同一个数据只能被修改一次,或者秒杀【数据的变化是需要被感知】

分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程一起进行,让程序串行执行。

分布式锁底层主要用了redissetnx命令:由于Redis是单线程的,用了setnx命令之后,只有一个客户端对某一个key设置值,在没有过期或删除key的时候其他客户端是不能设置这个key的。

setnx

Java代码中为setIfAbsent。这个命令在Redis中用于仅在指定的键不存在的时候设置键的值。如果键已存在,则不会执行任何操作,并且返回0表示设置失败。如果键不存在,则会设置新的值,并返回1表示设置成功。,

①防止误删其他锁,需要加个判断的逻辑,同时为了保证原子性

为了防止误删到其他的锁,这里我们建议使用 Lua 脚本通过 key 对应的 value(唯一值)来判断。

选用 Lua 脚本是为了保证解锁操作的原子性。因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,从而保证了锁释放操作的原子性。

②为了防止在删除锁的时候,服务器突然宕机,导致锁一直不存在,我们需要加个过期时间

具体怎么实现的?

我们通过UUID来区分不同JVM发来的请求,这样将来在删除锁之前进行判断的时候就不会误删

private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";
@Override
public boolean tryLock(long timeoutSec) {// 获取线程标示String threadId = ID_PREFIX + Thread.currentThread().getId();// 获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);
}

删除锁

public void unlock() {// 获取线程标示String threadId = ID_PREFIX + Thread.currentThread().getId();// 获取锁中的标示String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);// 判断标示是否一致if(threadId.equals(id)) {// 释放锁stringRedisTemplate.delete(KEY_PREFIX + name);}
}

setnx底层实现过程

Redis使用一个哈希表来存储键值对,当执行setnx命令时,Redis会去哈希表中查找指定的键。如果键存在,则返回0,如果键不存在则Redis会创建一个新的键值对,并将值与键关联起来。


通过添加过期时间做为兜底方案还不够保险,如果操作共享资源的时间大于过期时间,就会出现锁提前过期的问题,进而导致分布式锁直接失效。但如果锁的超时时间设置过长,又会影响到性能。


引出了Redisson框架

分布式锁中如何合理控制锁的有效时长

的确,这个时间是通过setnx直接指定的。不能过长也不能过短。

因此我们当时采用的是redis的一个框架redisson实现的 给锁续期(看门狗机制)

尽可能保证锁是业务完成之后自己释放的,而不是因为过期而释放的。

当锁住的一个业务还没有执行完成的时候,在redisson中引入一个看门狗机制。每隔一段时间就检查当前业务是否还持有锁,如果持有则增加当前业务持有锁的时间,当业务执行完成之后则释放锁就可以了。

同时,在高并发条件下,一个业务有可能会执行很快,客户1持有锁的时候,客户2来了也不会马上拒绝,它会不断尝试获取锁,如果客户1释放之后,客户2也能马上持有锁,性能也能得到提升。


http://www.ppmy.cn/ops/40366.html

相关文章

TCP实现文件传输以及下载

目录 1.上传文件思路 2.下载文件思路 3.上传文件代码 4.下载文件代码 5.运行格式 1.上传文件思路 上传文件就相当于客户端发送文件 步骤: 创建套接字连接服务器获取文件大小循环少量多次发送关闭文件和套接字 2.下载文件思路 下载文件就相当于服务器端接收…

Java Web 学习笔记(一) —— MySQL(3)

目录 1 Mysql 函数1.1 日期函数1.2 判断函数1.3 字符函数1.4 数学函数 2 Mysql 性能2.1 提高操作数据库性能2.2 执行次数比较多的语句2.3 sql语句的执行效率 3 Mysql 优化(***)3.1 定位慢查询3.2 SQL执行计划3.3 索引3.3.1 索引介绍与分类3.3.2 索引的使…

利用PS在不伤背景的前提下根据颜色去除图像上不想要的内容

下面为一个例子,去除图像上红色的虚线 Step1.用套索工具框选带有颜色的部分 Step2.切换到魔术棒工具,上端选项中,点击与选区交叉,连续这一项不要勾选 Step3.在需要去除的部分点击一下即可在框选范围内选中所有同颜色的区域&#x…

python跟C++选哪个?

选择使用Python还是C取决于你的具体需求和项目背景。我这里有一套编程入门教程,不仅包含了详细的视频讲解,项目实战。如果你渴望学习编程,不妨点个关注,给个评论222,私信22,我在后台发给你。 在通信工程行业…

最美博客POETIZE个人博客系统源码

源码说明: POETIZE个人博客系统源码 | 最美博客 这是一个基于SpringBoot、Vue2和Vue3的开源项目,支持移动端自适应,并具备完善的前台和后台管理功能。 网站分为两个模块: 1. 博客系统:包括文章、表白墙、图片墙、收…

绍兴ISO27001认证:信息安全认证的金钥匙

🌈🌈绍兴ISO27001认证:✌️信息安全认证的金钥匙🔑 💘随着信息技术的飞速发展,💁信息安全问题日益凸显。🔐为了提升信息安全管理水平,👮保障企业数据资产安全…

NSSCTF Web方向的例题和相关知识点(一)

[SWPUCTF 2021 新生赛]jicao 解题: 打开环境,是一段php代码 包含了flag.php文件,设定了一个POST请求的id和GET请求的json 语句会对GET请求的数据进行json解码 如果id和json变量的值都等于设定字符串,则得到 flag 我们可以使用…

MySQL优化

索引失效 CREATE TABLE tradelog (id int(11) NOT NULL,tradeid varchar(32) DEFAULT NULL,operator int(11) DEFAULT NULL,t_modified datetime DEFAULT NULL,PRIMARY KEY (id),KEY tradeid (tradeid),KEY t_modified (t_modified) ) ENGI…