spring boot redis分布式锁

news/2024/10/23 5:40:41/

随着现在分布式架构越来越盛行,在很多场景下需要使用到分布式锁。分布式锁的实现有很多种,比如基于数据库、zookeeper等,本文主要介绍使用Redis做分布式锁的方式,并封装成spring boot starter,方便使用

一.Redis分布式锁的实现以及存在的问题

锁是针对某个资源,保证其访问的互斥性,在实际使用当中,这个资源一般是一个字符串。使用Redis实现锁,主要是将资源放到Redis当中,利用其原子性,当其他线程访问时,如果Redis中已经存在这个资源,就不允许之后的一些操作。spring boot使用Redis的操作主要是通过RedisTemplate来实现,一般步骤如下:

将锁资源放入Redis(注意是当key不存在时才能放成功,所以使用setIfAbsent方法):

设置过期时间

释放锁

一般情况下,这样的实现就能够满足锁的需求了,但是如果在调用setIfAbsent方法之后线程挂掉了,即没有给锁定的资源设置过期时间,默认是永不过期,那么这个锁就会一直存在。所以需要保证设置锁及其过期时间两个操作的原子性,spring data的RedisTemplate当中并没有这样的方法。但是在jedis当中是有这种原子操作的方法的,需要通过RedisTemplate的execute方法获取到jedis里操作命令的对象,代码如下:

注意:Redis从2.6.12版本开始set命令支持NX、PX这些参数来达到setnx、setex、psetex命令的效果,文档参见:http://doc.redisfans.com/string/set.html

NX:表示只有当锁定资源不存在的时候才能SET成功。利用Redis的原子性,保证了只有第一个请求的线程才能获得锁,而之后的所有线程在锁定资源被释放之前都不能获得锁。

PX:expire表示锁定的资源的自动过期时间,单位是毫秒。具体过期时间根据实际场景而定

这样在获取锁的时候就能够保证设置Redis值和过期时间的原子性,避免前面提到的两次Redis操作期间出现意外而导致的锁不能释放的问题。但是这样还是可能会存在一个问题,考虑如下的场景顺序:

线程T1获取锁

线程T1执行业务操作,由于某些原因阻塞了较长时间

锁自动过期,即锁自动释放了

线程T2获取锁

线程T1业务操作完毕,释放锁(其实是释放的线程T2的锁)

按照这样的场景顺序,线程T2的业务操作实际上就没有锁提供保护机制了。所以,每个线程释放锁的时候只能释放自己的锁,即锁必须要有一个拥有者的标记,并且也需要保证释放锁的原子性操作。

因此在获取锁的时候,可以生成一个随机不唯一的串放入当前线程中,然后再放入Redis。释放锁的时候先判断锁对应的值是否与线程中的值相同,相同时才做删除操作。

Redis从2.6.0开始通过内置的Lua解释器,可以使用EVAL命令对Lua脚本进行求值,文档参见:http://doc.redisfans.com/script/eval.html

因此我们可以通过Lua脚本来达到释放锁的原子操作,定义Lua脚本如下:

具体意思可以参考上面提供的文档地址

使用RedisTemplate执行的代码如下:

代码中分为集群模式和单机模式,并且两者的方法、参数都一样,原因是spring封装的执行脚本的方法中(RedisConnection接口继承于RedisScriptingCommands接口的eval方法),集群模式的方法直接抛出了不支持执行脚本的异常(虽然实际是支持的),所以只能拿到Redis的connection来执行脚本,而JedisCluster和Jedis中的方法又没有实现共同的接口,所以只能分开调用。

spring封装的集群模式执行脚本方法源码:

至此,我们就完成了一个相对可靠的Redis分布式锁,但是,在集群模式的极端情况下,还是可能会存在一些问题

线程T1获取锁成功

Redis的master节点挂掉,slave自动顶上

线程T2获取锁,会从slave节点上去判断锁是否存在,由于Redis的master slave复制是异步的,所以此时线程T2可能成功获取到锁

为了可以以后扩展为使用其他方式来实现分布式锁,定义了接口和抽象类,所有的源码如下:

二. 基于AOP的Redis分布式锁

在实际的使用过程中,分布式锁可以封装好后使用在方法级别,这样就不用每个地方都去获取锁和释放锁,使用起来更加方便。

首先定义个注解:

装配分布式锁的bean

定义切面(spring boot配置方式)

spring boot starter还需要在resources/META-INF中添加spring.factories文件

这样封装之后,使用spring boot开发的项目,直接依赖这个starter,就可以在方法上加RedisLock注解来实现分布式锁的功能了,当然如果需要自己控制,直接注入分布式锁的bean即可

如果需要使用其他的分布式锁实现,继承AbstractDistributedLock后实现获取锁和释放锁的方法即可


http://www.ppmy.cn/news/399125.html

相关文章

flyme android os 耗电,国内手机OS流畅度排行榜:Flyme第一,MIUI倒数

原标题:国内手机OS流畅度排行榜:Flyme第一,MIUI倒数 前几周鲁大师数据中心公布流畅度最优的十部安卓手机排行榜,其中魅族手机入围四款,360 手机三款,乐视、Zuk 、及 OPPO 各一款。近日鲁大师再次 针对手机 …

android系统流畅度排行,这个手机操作系统流畅度排行,你认可吗?

原标题:这个手机操作系统流畅度排行,你认可吗? 手机操作系统流畅度排行苹果IOS,VIVO Origin OS,小米的MIUI,华为的EMUI,魅族的Flyme,一加的氢OS。说起来手机操作系统的流…

目前最流畅的android手机,目前公认最流畅的4大手机系统,第一当之无愧,用三年不卡顿!...

目前公认最流畅的4大手机系统,第一当之无愧,用三年不卡顿!我们国产的手机品牌在流畅度上已经提升了很多,且使用的寿命也是长了很多,现在一部性能好一点的手机机型也能够使用好几年的时间,不需要在短时间的更…

五大主流手机操作系统

正赶上要做一个与手机操作系统相关的作业,从网上查找了很多这些知识(费了老劲了)。现总结如下: 五大主流手机操作系统 塞班(Symbian) Symbian操作系统的前身是英国宝意昂公司(Psion)…

国产企业级服务器操作系统排名,国产操作系统那个最好排名

国产操作系统在我心中的排名是: 一、华为鸿蒙 二、中兴新支点 三、veket 四、中标麒麟 五、银河麒麟 六、红旗Linux 七.深度linux 可惜了红旗linux,最早做的,可惜没有坚持下来。 当然,也许每个人心里的排名都是不一样的&#xff0…

常见的几种手机操作系统

常见有7种操作系统,优缺点如下: Symbian OS,WM,PalmOS,Linux,Android,iPhoneOS/Mac OS X,BlackBerry 或许智能手机还不算是现在手机的主流,但是势必要成为未来手机市场的主流&…

手机的操作系统

操作系统一般是有shell和kernal/core 组成,RTK主要指内核,直接参与对硬件的操作,而至于我所说的高档RTOS则是很多厂家都买不起也不会用的VxWorks,pSOS之类的产品 我们现在所用的手机都是又各个厂家从国外买来设计图纸,然后根据…

五大手机操作系统

现在市场上的智能手机共有五种不同的操作系统,它们分别是: 1、symbian(塞班)操作系统(uiq、series60、series80、series90) 2. Android(安卓)操作系统 3、windows mobile 4、linux操作系统 5、palm symbian操作系统 代表品牌诺基…