redis锁_Redis分布式锁机制及实例

398577cdb9057526e1b0af431b08cd12.png

最近项目中针对业务处理需要保证处理的先后顺序,同时对业务应用系统需要多实例部署,因此在针对方法加锁上需要采用分布式锁方式进行,考虑到业务规模及场景使用,最终决定使用Redis做简单的分布式锁即可,使用开源的Redisson框架实现。

废话少说,先不看代码,先看原理

fc6ce6fde5450e7b117c60af9219bb4a.png
RLock lock = redisson.getLock("anyLock");// 最常见的使用方法lock.lock();

以上是Redisson官方给出的基本使用方法,我们在使用过程中会用到不同类型的锁,Redisson也提供了可重入锁、公平锁、联锁、红锁等等锁机制的实现。

这里我们以可重入锁作为例子来分析:

1 加锁机制

从上图可以看到一个客户端请求redis锁的时候,会通过Redisson发送一条lua脚本到redis服务,下边的脚本注释基本说明了加锁机制以及争抢机制:

if (redis.call('exists', KEYS[1]) == 0) //判断键值为anyLock的锁是否存在,0表示不存在then redis.call('hset', KEYS[1], ARGV[2], 1); //不存在则设置键anyLock值为客户端UUID的锁redis.call('pexpire', KEYS[1], ARGV[1]);//设置锁过期时间,默认为30sreturn nil; end; if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) //锁anyLock已经存在,再判断是否为申请锁UUIDthen //如果为同一客户端加锁则hincrby将加锁次数+1redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; //如果为另一个客户端争抢锁,调用pptl获取加锁客户端剩余锁时间再循环请求加锁return redis.call('pttl', KEYS[1]);

解释几个参数含义:

KEYS[1]:指的 RLock lock = redisson.getLock("anyLock"); 中的加锁key:anyLock

ARGV[1]:加锁时间,默认30秒

ARGV[2]:加锁客户端id,类似 a84ee9a6-4d15-4fdc-be06-38f5902c2367:26这样的UUID

2 看门狗自动延期机制

大家都知道,如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。

以上是Redisson官方给出的看门狗实现避免死锁的处理机制,意思是如果客户端所在应用服务节点出现故障,那么已经加上的锁在经过30s之后就过期自动解除,而其它的客户端可以获取到锁;而如果前者所在服务器实例没有故障,30s锁到期,此时业务逻辑还没处理完,其它实例获取到了锁,就会出现业务处理问题,因此通过看门狗每隔10s监测一次,自动对持有锁的客户端续期,保证业务处理完成后释放锁。

3 代码示例

spring-redis.xml配置:

<?xml version="1.0" encoding="UTF-8"?>classpath:redis.properties

测试代码RedisLockTest :

package redis;import org.junit.Test;import org.junit.runner.RunWith;import org.redisson.api.RLock;import org.redisson.api.RedissonClient;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import javax.annotation.Resource;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({"classpath:spring-config.xml"})public class RedisLockTest { @Resource RedissonClient redissonClient; @Test public void testRedisLock(){ CountDownLatch countDownLatch = new CountDownLatch(5); CountDownLatch latch = new CountDownLatch(1); for (int i=0;i

结果输出

==================3秒后开始竞争锁资源====================================开始竞争锁资源================Thread-4==================开始竞争锁资源================Thread-6==================开始竞争锁资源================Thread-5==================开始竞争锁资源================Thread-8==================开始竞争锁资源================Thread-7==================竞争锁资源成功================Thread-8==================竞争锁资源成功================Thread-5==================竞争锁资源成功================Thread-7==================竞争锁资源失败================Thread-6==================竞争锁资源失败================Thread-4==================结束==================

可以看到有的成功了有的失败了,失败是因为在尝试加锁的3S钟时间里没有获取到锁,就放弃了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值