Redisson的分布式锁
Posted Vashon_杨博程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redisson的分布式锁相关的知识,希望对你有一定的参考价值。
前言
在分布式系统中,我们会用到各种锁,之前我们接触过的本地锁比如:synchronized、JUC里的Lock、ReadWriteLock、ReentrantLock、闭锁(CountDownLatch)、信号量(Semaphore)等,这些锁都只能锁本地服务,在分布式系统场景下是锁不住所有服务的。如有要使用本地锁实现锁住所有服务,需要自己来实现分布式锁的逻辑(结合Redis);本篇文章介绍Redisson分布式锁的使用。
准备工作
首先我们在引入Redis依赖的需要排除Redis默认的底层lettuce-core(存在内存泄漏的BUG),改用jedis,maven配置如下:
<!-- spring boot redis缓存引入-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.5.12</version>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.1</version>
</dependency>
<!--以后使用redisson作为所有分布式锁,分布式对象等功能框架-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.0</version>
</dependency>
在使用Redisson时存在常用的两种模式:集群模式、单节点模式,yml的配置如下:
spring:
# redis配置(单节点配置)
redis:
host: localhost
port: 6379
database: 0
password: 123456 #默认为空
timeout: 3000ms #最大等待时间,超时则抛出异常
jedis:
pool:
max-active: 20 #最大连接数,负值表示没有限制,默认8
max-wait: -1 #最大阻塞等待时间,负值表示没有限制,默认-1
max-idle: 8 #最大空闲连接,默认8
min-idle: 0 #默认最小空闲连接,默认0
# redis集群节点配置(cluster模式) 三主三从)
redis:
host: localhost
port: 6379
database: 0
password: 123456 #默认为空
timeout: 3000ms #最大等待时间,超时则抛出异常
jedis:
pool:
max-active: 20 #最大连接数,负值表示没有限制,默认8
max-wait: -1 #最大阻塞等待时间,负值表示没有限制,默认-1
max-idle: 8 #最大空闲连接,默认8
min-idle: 0 #默认最小空闲连接,默认0
cluster:
nodes:
- 127.0.0.1:port1
- 127.0.0.2:port2
- 127.0.0.3:port3
- 127.0.0.4:port4
- 127.0.0.5:port5
- 127.0.0.6:port6
Redisson的配置
配置方法有:程序化配置方法、文件方式配置,我们采用程序化配置,RedissonConfig配置类:
package com.vashon.product.controller;
import com.vashon.common.utils.Result;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
/**
* @ClassName: IndexController
* @projectName: vashon-mall
* @description: TODO
* @author: yangwenxue
* @date: 2022/7/10 15:03
* @Version: 1.0
*/
@RestController
public class IndexController
@Autowired
RedissonClient redissonClient;
@GetMapping("/hello")
public Result indexPage()
//1、获取一把锁,只要锁的名字一样,就是同一把锁
RLock lock = redissonClient.getLock("my-lock");
//2、加锁:阻塞式等待
// lock.lock();
// lock.lock(10, TimeUnit.SECONDS); //10s中后自动解锁,存在的问题:锁到期后不会自动续期。
//1)、锁的自动续期,如果业务超长,运行期间自动给锁续上30s,不用担心业务时间长锁自动过期被删掉
//2)、加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,默认在30s以内自动删除
boolean tryLock = false;
try
tryLock = lock.tryLock(100, 10, TimeUnit.SECONDS);//尝试加锁,最多等到100秒,上锁后10秒自动解锁
catch (InterruptedException e)
e.printStackTrace();
if(tryLock)
try
System.out.println("加锁成功,执行业务..." + Thread.currentThread().getId());
Thread.sleep(30000);
catch (Exception e)
e.printStackTrace();
finally
//3、解锁 假设解锁代码没运行,redisson会不会死锁
System.out.println("释放锁..." + Thread.currentThread().getId());
lock.unlock();
return Result.success();
分布式锁测试:
//1、获取一把锁,只要锁的名字一样,就是同一把锁
RLock lock = redissonClient.getLock("my-lock");
//2、加锁:阻塞式等待
lock.lock();
// lock.lock(10, TimeUnit.SECONDS); //10s中后自动解锁,存在的问题:锁到期后不会自动续期。
//1)、锁的自动续期,如果业务超长,运行期间自动给锁续上30s,不用担心业务时间长锁自动过期被删掉
//2)、加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,默认在30s以内自动删除
try
System.out.println("加锁成功,执行业务..." + Thread.currentThread().getId());
Thread.sleep(30000);
catch (Exception e)
e.printStackTrace();
finally
//3、解锁 假设解锁代码没运行,redisson会不会死锁
System.out.println("释放锁..." + Thread.currentThread().getId());
lock.unlock();
测试结果:
加锁成功,执行业务...116
释放锁...116
加锁成功,执行业务...110
释放锁...110
总结:
1、Redisson的锁使用时,可以像使用JUC的lock一样使用,因为它实现了JUC包下的lock接口;
2、redisson的锁是阻塞式等待,锁会自动续期,如果业务超长,运行期间自动给锁续上30s,不用担心业务时间长锁自动过期被删掉;加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,默认在30s以内自动删除。
3、如果调用lock()方法加锁时带上过期时间,则存在的问题:锁到期后不会自动续期(可以看RedissonLock.tryAcquireAsync代码)。
4、lock()无参方法存在看门狗机制,有参方法没有看门狗机制。
以上是关于Redisson的分布式锁的主要内容,如果未能解决你的问题,请参考以下文章