Redisson联锁

2023-12-25 08:48
文章标签 redisson 联锁

本文主要是介绍Redisson联锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、联锁概述

联锁(RedissonMultiLock)对象可以将多个RLock对象关联为一个联锁,实现加锁和解锁功能。每个RLock对象实例可以来自于不同的Redisson实例。

如果负责储存分布式锁的某些Redis节点宕机以后,而且这些锁正好处于锁住状态,就会出现死锁问题。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗。看门狗的作用是在Redisson实例被关闭前,不断延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒,也可以通过修改Config.lockWatchdogTimeout来另行指定。

二、实践

我是在Springboot项目中使用的Redisson分布式锁。

2.1 pom.xml
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.14.1</version>
</dependency>
2.2 application.properties
server.port=8083## master 数据源配置
master.datasource.url=jdbc:mysql://10.5.146.156:3306/USDP?useUnicode=true&characterEncoding=utf8
master.datasource.username=root
master.datasource.password=click1
master.datasource.driverClassName=com.mysql.jdbc.Driver# 连接池的配置信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 初始化大小:建立物理连接的个数
spring.datasource.initialSize=5  
# 最小连接数
spring.datasource.minIdle=5  
# 最大连接数
spring.datasource.maxActive=20  
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000  
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000  
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000  
# 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用
spring.datasource.validationQuery=SELECT 1 FROM DUAL  
spring.datasource.testWhileIdle=true  
spring.datasource.testOnBorrow=false  
spring.datasource.testOnReturn=false  
# 打开PSCache,并且指定每个连接上PSCache的大小;
# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭
spring.datasource.poolPreparedStatements=false  
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20  
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙;
# 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:监控统计用的filter:stat, 日志用的filter:log4j, 防御sql注入的filter:wall
spring.datasource.filters=stat,wall,log4j  
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000## 打印SQL语句
##SpringBoot默认是使用info级别,没有指定级别的就用Springboot默认规定的级别:root级别
logging.level.com.test=INFO
#该属性用来配置日志文件名,如果该属性不配置,默认文件名为spring.log
logging.file=/opt/applog/interfaceautotestagent/test.log
#logging.file=/var/log/test.log
logging.pattern.console=%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n
#指定文件中日志的输出格式
logging.pattern.file=%msg%n# REDIS
# Redis数据库索引(默认为0)
spring.redis.database=0
## Redis服务器地址
#spring.redis.host=10.237.78.40
## Redis服务器连接端口
#spring.redis.port=6379
## Redis服务器连接密码(默认为空)
#spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=16
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0
# 连接超时时间(毫秒)spring boot 1.x,redisson新加的
spring.redis.timeout=60000
# 执行命令超时时间,单位毫秒
spring.redis.command-timeout: 15000
# 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
spring.redis.test-on-borrow: true
# 集群模式下,逗号分隔的键值对(主机:端口)形式的服务器列表
#spirng.redis.cluster.nodes=10.237.79.150:6379,10.237.79.150:6380,10.237.79.151:6379,10.237.79.151:6380,10.237.79.152:6379,10.237.79.152:6380
spirng.redis.cluster.nodes=172.24.83.165:6379,172.24.83.165:6380,172.24.83.165:6381,172.24.83.165:6382,172.24.83.165:6383,172.24.83.165:6384
# 集群模式下,集群最大转发的数量
spring.redis.cluster.max-redirects=3
# 最大的连接重试次数
spring.redis.cluster.max-attempts=5#activemq
spring.activemq.broker-url=tcp://10.237.78.6:61616
spring.activemq.user=
spring.activemq.password=
#spring.activemq.in-memory=true
#spring.activemq.pool.enabled=false
#使用发布/订阅模式时,下边配置需要设置成 true  是否使用默认的destination type来支持 publish/subscribe,默认: false
spring.jms.pub-sub-domain=true
##指定最小的并发消费者数量
#spring.jms.listener.concurrency = 10
##指定最大的并发消费者数量
#spring.jms.listener.max-concurrency = 10
2.3 RedisConfigProperties
package com.test.config;import lombok.Data;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;import java.util.List;@Data
@Component
@PropertySource("classpath:application.properties")
public class RedisConfigProperties {@Value("${spirng.redis.cluster.nodes}")private String redisClusterNodes;
}
2.4 RedissonConfig
package com.test.config;import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.ArrayList;
import java.util.List;@Configuration
public class RedissonConfig {@Autowiredprivate RedisConfigProperties redisConfigProperties;@Beanpublic RedissonClient redissonClient1() {//redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加List<String> clusterNodes = new ArrayList<>();for (int i = 0; i < 2; i++) {clusterNodes.add("redis://" + redisConfigProperties.getRedisClusterNodes().split(",")[i]);}Config config = new Config();// 添加集群地址ClusterServersConfig clusterServersConfig = config.useClusterServers().addNodeAddress(clusterNodes.toArray(new String[clusterNodes.size()]));
//        // 设置密码
//        clusterServersConfig.setPassword(redisConfigProperties.getPassword());RedissonClient redissonClient = Redisson.create(config);return redissonClient;}@Beanpublic RedissonClient redissonClient2() {//redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加List<String> clusterNodes = new ArrayList<>();for (int i = 2; i < 4; i++) {clusterNodes.add("redis://" + redisConfigProperties.getRedisClusterNodes().split(",")[i]);}Config config = new Config();// 添加集群地址ClusterServersConfig clusterServersConfig = config.useClusterServers().addNodeAddress(clusterNodes.toArray(new String[clusterNodes.size()]));
//        // 设置密码
//        clusterServersConfig.setPassword(redisConfigProperties.getPassword());RedissonClient redissonClient = Redisson.create(config);return redissonClient;}@Beanpublic RedissonClient redissonClient3() {//redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加List<String> clusterNodes = new ArrayList<>();for (int i = 4; i < 5; i++) {clusterNodes.add("redis://" + redisConfigProperties.getRedisClusterNodes().split(",")[i]);}Config config = new Config();// 添加集群地址ClusterServersConfig clusterServersConfig = config.useClusterServers().addNodeAddress(clusterNodes.toArray(new String[clusterNodes.size()]));
//        // 设置密码
//        clusterServersConfig.setPassword(redisConfigProperties.getPassword());RedissonClient redissonClient = Redisson.create(config);return redissonClient;}
}
2.5 使用联锁
RLock lock1 = redissonClient1.getLock("lock1");
RLock lock2 = redissonClient2.getLock("lock2");
RLock lock3 = redissonClient3.getLock("lock3");RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 所有的锁都上锁成功才算成功。
lock.lock();
...
lock.unlock();

RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 给lock1,lock2,lock3加锁,如果没有手动解开的话,(leaseTime=10s)10秒钟后将会自动解开
lock.lock(10, TimeUnit.SECONDS);// 为加锁等待(waitTime=100s)100秒时间,并在加锁成功10秒钟后自动解开
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();

这篇关于Redisson联锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/534920

相关文章

Redisson的几种锁的通俗说明

Redisson的几种锁 Redisson 提供了多种分布式锁,每种锁都有其特定的使用场景,常见的包括: RLock(可重入锁):允许同一线程多次获取锁。RReadWriteLock(读写锁):多个线程可以同时读取数据,写操作是独占的。RSemaphore(信号量):限制同一时刻能够访问共享资源的线程数量。RCountDownLatch(闭锁):一个或多个线程等待其它线程完成任务。RFairL

Rides实现分布式锁,保障数据一致性,Redisson分布式事务处理

分布式环境下分布式锁有三种方式: 基于数据库分布式锁 基于Redis分布式锁 基于zk分布式锁 本帖只介绍Redis分布式锁 为什么需要用到分布式锁?         在单机环境下一个服务中多个线程对同一个事物或数据资源进行操作时,可以通过添加加锁方式(synchronized和lock)来解决数据一致性的问题。         但是如果出现多个服务的情况下,这时候我们在通过s

使用redisson 实现redis 的延迟任务

1、原理介绍 简单说下redis实现延迟队列的原理:把所有需要延时执行的任务添加到有序集合里面;并将任务的执行时间设置为分值,另外再使用另一个线程来查找有序集合里面是否存在可以被立即执行的任务,如果有的话就从有序集合里面移除那个任务,并将其添加到另一个执行队列里面。 而 Redisson 封装了接口给我们使用,我们只需要调用接口就可以直接使用,不需要关心redis具体实现原理。 2、使用

Redisson与Redis分布式锁

Redis分布式锁 Redis分布式锁是一种在分布式系统中用于确保多个进程对共享资源互斥访问的机制。它通常通过Redis的原子指令来实现,比如使用SETNX(Set if Not eXists)指令来设置键,如果键不存在则操作成功,可以认为获取了锁;如果键已存在,则操作失败,表示锁被其他进程持有。但是,这种基本的实现可能会遇到各种问题,如锁无法自动释放导致的死锁问题,或者在高并发情况下的锁安全性

利用 Redisson 实现延迟消息队列:一种高效订单取消方案

文章目录 一、发送延迟消息:定时触发订单取消二、监听延迟队列:自动处理过期订单三、取消订单的实现逻辑四、总结 在电商平台中,订单生成后如果长时间未被处理,我们通常需要自动取消这些订单。这种需求不仅能够提升用户体验,还能有效管理库存和资源分配。而如何实现这一需求,延迟消息队列无疑是一个高效的解决方案。今天,我们就来聊聊如何使用 Redisson 实现一个简洁且强大的延迟消息处理机制

【分布式锁】基于Redisson的分布式锁实现

以下代码是基于Redisson的分布式锁实现 yml文件中配置redis # Spring配置spring:# redis 配置redis:host: 127.0.0.1database: 1password:port: 6379address: redis://127.0.0.1:6379 编写配置类,注册redisClinet /*** @description Redisson

Redisson-Lock-加锁原理

归档 GitHub: Redisson-Lock-加锁原理 Unit-Test RedissonLockTest 说明 源码类:RedissonLock // 加锁入口@Overridepublic void lock() { lock(-1, null, false);}/*** 加锁实现 */private void lock(long leaseTime, TimeUni

Redisson-DelayedQueue-原理

归档 GitHub: Redisson-DelayedQueue-原理 Unit-Test RedissonDelayedQueueTest 常规测试 @Testpublic void testCommon() throws InterruptedException {RBlockingQueue<String> destinationQueue = redisson.getBlock

Redisson PRO 、Jedis 性能比较

前言:  我们都对Redis的性能感兴趣,而且根据大多数人的知识,Redis通常以大约55000-75000 ops / sec的速度执行,所有响应延迟均为亚毫秒级。 使用Redisson PRO,我们设法将限制提升到更高的水平,大约100000-213000 ops / sec,同时将延迟保持在相同的亚毫秒级别。 为了衡量相对性能,我们将结果与最流行的Redis Java客户端 - J

Redisson 源码分析 —— 调试环境搭建

本文基于 Redisson 3.11.4-SNAPSHOT 版本 依赖工具 MavenGitJDKIntelliJIDEA 源码拉取 从官方仓库 https://github.com/redisson/redisson Fork 出属于自己的仓库。 为什么要 Fork ?既然开始阅读、调试源码,我们可能会写一些注释,有了自己的仓库,可以进行自由的提交。 在拉取项目的过程中,我们来看看每个