当前位置: 首页 > news >正文

从原理到实践,分析 Redisson 分布式锁的实现方案(二)

        上篇讲解了如何用 Redis 实现分布式锁的方案,它提供了简单的原语来实现基于Redis的分布式锁。然而,Redis作为分布式锁的实现方式也存在一些缺点。本文将引入Redisson来实现分布式锁。

一、Redisson是什么

        Redisson是一个基于Redis的分布式Java框架。它提供了丰富的功能和工具,帮助开发者在分布式系统中解决数据共享、并发控制和任务调度等问题。通过使用Redisson,开发者可以轻松地操作Redis的分布式对象(如集合、映射、队列等),实现可靠的分布式锁机制,以及管理和调度分布式环境中的任务和服务。

Redisson提供的功能

  1. 分布式对象:

    • 分布式集合(Set、SortedSet、List)
    • 分布式映射(Map)
    • 分布式队列(Queue、Deque)
    • 分布式锁(Lock)
    • 分布式计数器(AtomicLong)
  2. 分布式限流:

    • 令牌桶算法(Rate Limiter)
    • 漏桶算法(Rate Limiter)
  3. 分布式发布订阅:

    • 发布订阅模式(Pub-Sub)
    • 消息监听器容器(Message Listener Container)
  4. 分布式锁和同步:

    • 可重入锁(ReentrantLock)
    • 公平锁(FairLock)
    • 联锁(MultiLock)
    • 红锁(RedLock)
    • 读写锁(ReadWriteLock)
    • 信号量(Semaphore)
    • 闭锁(CountDownLatch)
    • 栅栏(CyclicBarrier)
  5. 分布式服务和任务调度:

    • 远程服务(Remote Service)
    • 分布式任务调度器(Task Scheduler)
    • 分布式延迟队列(Delayed Queue)
  6. 分布式地理空间索引(Geospatial Index):

    • 地理位置存储
    • 地理位置搜索
  7. 分布式布隆过滤器(Bloom Filter)和可布隆过滤器(Bloom Filter)。

  8. 分布式缓存:

    • 对Redis进行本地缓存
    • Spring缓存注解支持
  9. 分布式连接池:

    • 支持连接池管理和维护
  10. Redis集群和哨兵支持:

    • 支持Redis集群模式
    • 支持Redis哨兵模式
    • 对于使用Redis集群部署的场景,Redisson可以自动识别和操作集群中的多个节点,保证数据的高可用性和扩展性。而对于使用Redis哨兵模式部署的场景,Redisson可以监控并切换到可用的主从节点,实现高可靠性和容错能力。
  11. Spring集成:

    • 与Spring框架的无缝集成
    • 支持Spring缓存注解

二、Redisson分布式锁

Redisson的分布式锁的特点

  1. 线程安全:分布式锁可以确保在多线程和多进程环境下的数据一致性和可靠性。

  2. 可重入性:同一个线程可以多次获取同一个锁,避免死锁的问题。
  3. 锁超时:支持设置锁的有效期,防止锁被长时间占用而导致系统出现问题。
  4. 阻塞式获取锁:当某个线程尝试获取锁时,如果锁已经被其他线程占用,则该线程可以选择等待直到锁释放。
  5. 无阻塞式获取锁:当某个线程尝试获取锁时,如果锁已经被其他线程占用,则该线程不会等待,而是立即返回获取锁失败的信息。  

Redisson的分布式锁的缺点 

  1. 单点故障:Redisson的分布式锁依赖于Redis集群,如果Redis集群出现故障或不可用,可能导致分布式锁的可靠性和可用性受到影响。因此,在使用Redisson分布式锁时,需要特别关注Redis集群的稳定性和高可用性。

  2. 锁竞争:当多个线程同时请求获取分布式锁时,可能出现锁竞争的情况。如果锁竞争较为激烈,可能会导致性能下降和请求超时等问题。此外,由于Redisson分布式锁是基于Redis进行实现的,如果Redis节点的处理能力无法满足高并发的锁请求,可能会导致锁请求被延迟或阻塞。

  3. 死锁风险:分布式环境下,由于网络通信、节点故障等因素,可能导致锁无法正常释放,从而引发死锁问题。需要合理设计和使用锁的超时时间、自动释放机制等来降低死锁风险。

  4. 锁粒度管理:在分布式环境下,锁的粒度管理是一个重要的问题。过于细粒度的锁可能导致并发性能下降,而过于粗粒度的锁可能会影响系统的可伸缩性和并发性能。需要根据具体的业务场景和并发访问模式合理选择锁的粒度。

  5. 数据一致性:使用分布式锁保证多个操作的原子性是很常见的应用场景之一。然而,分布式锁通常只能提供粗粒度的互斥访问,不能保证数据的完全一致性。在一些特定的应用场景中,可能需要额外的措施来确保数据的最终一致性。

Redisson分布式锁源码分析

public interface RLock extends Lock, RLockAsync {String getName();void lockInterruptibly(long var1, TimeUnit var3) throws InterruptedException;boolean tryLock(long var1, long var3, TimeUnit var5) throws InterruptedException;void lock(long var1, TimeUnit var3);boolean forceUnlock();boolean isLocked();boolean isHeldByThread(long var1);boolean isHeldByCurrentThread();int getHoldCount();long remainTimeToLive();
}

   RLock接口主要继承了Lock接口,它是Redisson提供的用于分布式锁的核心接口,它定义了获取锁和释放锁等方法 ,并扩展了很多方法。

如:

  • void lock(long leaseTime, TimeUnit unit)

    • 功能:获取锁,并设置锁的自动释放时间。
    • 参数:
      • leaseTime:锁的自动释放时间。
      • unit:时间单位。
  • RFuture<Void> lockAsync(long leaseTime, TimeUnit unit)

    • 功能:异步方式获取锁,并设置锁的自动释放时间。
    • 参数:
      • leaseTime:锁的自动释放时间。
      • unit:时间单位。
    • 返回值:一个RFuture对象,表示异步操作的结果。
  • boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException

    • 功能:尝试在指定的等待时间内获取锁,并设置锁的自动释放时间。
    • 参数:
      • waitTime:等待获取锁的最大时间量。
      • leaseTime:锁的自动释放时间。
      • unit:时间单位。
    • 返回值:如果在等待时间内成功获取锁,则返回true;否则返回false
    • 异常:如果在等待获取锁的过程中被中断,则抛出InterruptedException

        通过上述方法,RLock接口提供了更多对lock()方法的拓展,使得在获取锁时可以设置自动释放时间或进行异步操作。这样可以更加灵活地控制锁的行为,适应不同场景下的需求。

        除了上述拓展,RLock接口还提供了其他方法来支持可重入锁、公平锁、红锁、读写锁等特性,以便满足更为复杂的分布式锁需求。

三、Spring Boot 整合 Redisson 分布式锁 

添加Maven依赖

<!-- Redisson依赖 -->
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.16.2</version>
</dependency><!-- Spring Data Redis依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

 配置Redisson连接application.yml

spring:redis:cluster:nodes:- 127.0.0.1:7000- 127.0.0.1:7001- 127.0.0.1:7002password: yourRedisPassword

创建Redisson客户端

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissonConfig {@Value("${spring.redis.cluster.nodes}")private String clusterNodes;@Value("${spring.redis.password}")private String password;@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useClusterServers().addNodeAddress(clusterNodes.split(",")).setPassword(password);return Redisson.create(config);}
}

使用分布式锁

        在需要使用分布式锁的地方注入RedissonClient实例,并使用getLock方法创建一个分布式锁对象(RLock)。

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class SomeService {@Autowiredprivate RedissonClient redissonClient;public void doSomething() {String lockKey = "myLock"; // 锁的keyRLock lock = redissonClient.getLock(lockKey);try {lock.lock(); // 获取锁// 在这里执行需要加锁保护的代码} finally {lock.unlock(); // 释放锁}}
}

RLock.lock()

        使用Rlock.lock() 方法时 ,如果当前没有其他线程或进程持有该锁,那么调用线程将立即获得锁定,并继续执行后续的代码。如果其他线程或进程已经持有了该锁,那么调用线程将被阻塞,直到该锁被释放为止。

此外,Rlock.lock() 方法还具有以下特点:

  1. 可重入性:同一个线程可以多次调用 Rlock.lock() 方法而不会造成死锁,只需确保每次 lock() 调用都有相应的 unlock() 调用与之匹配。
  2. 超时机制:可以通过 lock() 方法中的参数设置等待锁的超时时间,避免因为无法获得锁而一直等待。
  3. 自动续期:当线程持有锁的时间超过设置的锁的过期时间时,Redisson 会自动延长锁的有效期,避免因为业务执行时间过长而导致锁过期。
  4. 防止死锁:Redisson 通过唯一标识锁的 ID 来区分不同的锁,防止发生死锁。

lock() 方法加锁流程

RLock.unlock()

   RLock.unlock()方法用于释放由Redission分布式锁所保护的资源。它允许持有锁的线程主动释放锁,从而允许其他线程获取该锁并访问共享资源。

注意事项:

  • RLock.unlock()方法应该在保护的临界区代码执行完毕后进行调用,以确保锁的及时释放。
  • 在多线程环境下,释放锁的顺序应该与获取锁的顺序相对应,以避免死锁或资源争用的问题。
  • 如果当前线程没有持有锁,调用RLock.unlock()方法不会抛出异常,也不会影响其他线程。
  • 如果Redisson客户端刚加锁成功,并且未指定leaseTime,后台会启动一个定时任务watchdog每隔10s检查key,key如果存在就为它⾃动续命到30s;在watchdog定时任务存在的情况下,如果不是主动释放锁,那么key将会⼀直的被watchdog这个定时任务维持加锁。但是如果客户端宕机了,定时任务watchdog也就没了,也就没有锁续约机制了,那么过完30s之后,key会⾃动被删除、key对应的锁也自动被释放了。

unlock()方法解锁流程


四、更多内容

Spring Boot 集成 Redisson分布式锁

从原理到实践,分析 Redis 分布式锁的多种实现方案

相关文章:

从原理到实践,分析 Redisson 分布式锁的实现方案(二)

上篇讲解了如何用 Redis 实现分布式锁的方案&#xff0c;它提供了简单的原语来实现基于Redis的分布式锁。然而&#xff0c;Redis作为分布式锁的实现方式也存在一些缺点。本文将引入Redisson来实现分布式锁。 一、Redisson是什么 Redisson是一个基于Redis的分布式Java框架。它提…...

QT【day3】

思维导图&#xff1a; 闹钟&#xff1a; //widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTimerEvent> #include<QTimer> #include<QTime> //时间类 #include<QPushButton> //按钮类头文件 #include<QDebug&…...

模版模式和策略模式的区别

前言 模版模式和策略模式在日常开发中经常遇到&#xff0c;这两个设计模式有啥区别&#xff0c;这里简单总结下。 模版模式简单demo // 抽象模板类 abstract class AbstractClass {// 模板方法定义了算法的骨架public void templateMethod() {// 执行固定的步骤step1();step…...

Github搭建个人博客全攻略

Github搭建个人博客全攻略 一、Github二、配置博客仓库三、配置Git用户SSH密钥四、Deploy Key or Token方法一&#xff1a; Deploy Key方法二&#xff1a; Token 五、Hexo六、 主题七、 发布博文八、参考链接 一、Github Github是开发者的代码仓库&#xff0c;一个开源和分享社…...

gensim conherence model C_V 值与其他指标负相关BUG

在我用gensim3.8.3 conherence model分析京东评论主题模型时&#xff0c; C_V 与npmi、u_mass出现了强烈的皮尔逊负相关&#xff1a; 这些地方也反映了类似问题&#xff1a; https://github.com/dice-group/Palmetto/issues/12 https://github.com/dice-group/Palmetto/issue…...

QT DAY3

1.思维导图 2.完成闹钟的实现 头文件 #include <QTextToSpeech> #include <QTextEdit> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTQLineEdit *edit1new QLineEdit;// QTextEdit *edit2new QTe…...

TortoiseGit(小乌龟)使用问题总结

1.git clone fatal authentication failed for ‘请求路径‘&#xff0c; git clone 用户没有权限 待定 参考&#xff1a; 1.git clone fatal authentication failed for ‘请求路径‘&#xff0c; git clone 用户没有权限_git clone fatal: authentication failed for_椰子…...

106、Redis和Mysql如何保证数据一致

Redis和Mysql如何保证数据一致 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不一致先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中,这种方案能解决1方案的问题,但是在高并发下性能较低,而且仍然会出现数据不一致的问题,比如线程1删除了…...

SpringBoot+jasypt-spring-boot-starter实现配置文件明文加密

1.使用环境 springboot:2.1.4.RELEASE JDK:8 jasypt-spring-boot-starter:3.0.2 2.引入依赖 !-- 配置文件加密 --> <dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><ver…...

k8s核心概念

一、集群架构与组件 1&#xff0c;相关组件 【1】 master node三个组件 k8s的控制节点&#xff0c;对集群进行调度管理&#xff0c;接受集群外用户去集群操作请求master node 组成&#xff08;四个组件&#xff09;&#xff1a;控制面 API Server&#xff1a;通信kube-Sche…...

opencv 处理的视频 保存为新视频 ,新视频 无法读取

问题描述&#xff1a; 如题 问题原因&#xff1a; 其实就是保存的帧如果处理成灰度图&#xff08;单通道&#xff09;的话&#xff0c;保存为新视频&#xff0c;则新视频读取不了 解决办法&#xff1a; 处理成三通道&#xff0c;保存的新视频即可被读取 代码&#xff1a; Vi…...

《golang设计模式》第一部分·创建型模式-02-原型模式(Prototype)

文章目录 1. 概念1.1 简述1.2 角色1.3 类图 2. 代码示例2.1 设计2.2 代码2.3 类图 1. 概念 1.1 简述 用原型实例指定创建对象的种类&#xff0c;并且通过拷贝这些原型创建新的对象 1.2 角色 Prototype&#xff08;抽象原型类&#xff09;&#xff1a;它是声明克隆方法的接口…...

SpringCloudAlibaba微服务实战系列(一)Nacos服务注册发现

SpringCloudAlibaba微服务实战系列&#xff08;一&#xff09;Nacos服务注册发现 实战前先做一个背景了解。 单体架构、SOA和微服务 单体架构&#xff1a;近几年技术的飞速发展&#xff0c;各种各样的服务已经进入到网络化。单体架构发布时只需要打成一个war或jar包发布即可&a…...

23.7.27 牛客暑期多校4部分题解

1010 - Kong Ming Qi 1005 - Data Generation 题意、思路待补 code #include <bits/stdc.h> using namespace std; const long long MOD 998244353; int t; long long n, m; long long sub(long long a, long long b) {return a - b < 0 ? a - b MOD : a - b;}…...

Ubuntu 20.04 安装教程

最近貌似很多同学都在下载 ubuntu 虚拟机&#xff0c;但网上很多的安装教程不是很全&#xff0c;所以今天重新更新一下这篇博文&#xff08;更新日期&#xff1a;2022.12.3&#xff09;&#xff0c;希望能帮到大家。除此之外&#xff0c;安装过程确实比较繁琐&#xff0c;可能会…...

如何评判算法好坏?复杂度深度解析

如何评判算法好坏&#xff1f;复杂度深度解析 1. 算法效率1.1 如何衡量一个算法好坏1.2 算法的复杂度 2 时间复杂度2.1 时间复杂度的概念2.1.1 实例 2.2 大O的渐进表示法2.3 常见时间复杂度计算举例 3 空间复杂度4 常见复杂度对比5 结尾 1. 算法效率 1.1 如何衡量一个算法好坏 …...

【HashMap】2352. 相等行列对

2352. 相等行列对 解题思路 使用哈希容器遍历grid数组 将每一行的字符全部转换为StringBuilde对象 然后存入map中遍历每一列 将其转换为字符串 然后查找Map中是否存在 如果存在 统计 class Solution {public int equalPairs(int[][] grid) {// 哈希容器Map<String,Intege…...

如何声明静态方法 和 实现?

如何声明静态方法 和 实现&#xff1f;在 C 中&#xff0c;声明和实现静态方法&#xff08;静态成员函数&#xff09;与普通成员函数有一些区别。静态方法属于类本身&#xff0c;而不是类的对象&#xff0c;因此在声明和实现时需要特殊的语法。 声明静态方法&#xff1a; 在类…...

哈工大计算机网络课程局域网详解之:无线局域网

哈工大计算机网络课程局域网详解之&#xff1a;无线局域网 文章目录 哈工大计算机网络课程局域网详解之&#xff1a;无线局域网IEEE 802.11无线局域网802.11体系结构802.11&#xff1a;信道与AP关联 本节介绍一下平时经常使用的一个无线局域网技术&#xff0c;也就是通常我们使…...

系统集成|第六章(笔记)

目录 第六章、整体管理6.1 项目整体管理概述6.2 主要过程6.2.1 制订项目章程6.2.2 制订项目管理计划6.2.3 指导与管理项目工作6.2.4 监控项目工作6.2.5 实施整体变更控制6.2.6 结束项目或阶段 上篇&#xff1a;第五章、立项管理 第六章、整体管理 6.1 项目整体管理概述 概述&a…...

MySQL主从复制环境部署

文章目录 MySQL主从复制什么是主从复制&#xff1a;为什么需要主从复制&#xff1a;配置文件修改-主&#xff1a;时间同步&#xff1a;重启服务-主&#xff1a;创建同步用户&#xff1a;查看主上的二进制文件名及位置&#xff1a;配置-从&#xff1a;测试:注&#xff1a; MySQL…...

day42-servlet下拉查询/单例模式

0目录 1.Servlet实现下拉查询&#xff08;两表&#xff09; 2.单例模式 1.实战 1.1 创建工程&#xff0c;准备环境... 1.2 接口 1.3 重写方法 1.4 servlet 1.5 list.jsp list.jsp详解 2.单例模式 2.1 饿汉模式&#xff1a;在程序加载时直接创建对象&#…...

docker中设置容器健康检查

文章目录 一、docker-compose方式二、Dockerfile方式三、docker run方式四、查看检查日志 一、docker-compose方式 在docker-compose中加入healthcheck healthcheck 支持下列选项&#xff1a; test&#xff1a;健康检查命令&#xff0c;例如 ["CMD", "curl&quo…...

azure-cognitiveservices-speech api error while using with AWS Lambda

Azure 语音评估服务 Cancellation Reason 初始化平台失败 1.在mac上安装 pip install azure-cognitiveservices-speech1.30.0正常运行没有问题&#xff0c;服务部署到docker 容器中后调用Azure语音评估服务报错 Cancellation Reason 初始化平台失败 2.解决方案&#xff0c;变…...

系统集成项目管理工程师挣值分析笔记大全

系统集成项目管理工程师挣值分析笔记大全 挣值分析是一种项目管理技术&#xff0c;用于量化和监控项目绩效。它通过比较计划值&#xff08;PV&#xff09;、实际成本&#xff08;AC&#xff09;和挣值&#xff08;EV&#xff09;三个参数来评估项目的进展情况和成本绩效。 挣值…...

TCP 协议【传输层协议】

文章目录 1. 简介1.1 TCP 协议是什么1.2 TCP 协议的作用1.3 什么是“面向连接” 2. 简述 TCP2.1 封装和解包2.2 TCP 报文格式2.3 什么是“面向字节流”2.4 通过 ACK 机制实现一定可靠性 3. 详述 TCP3.1 基本认识TCP 报头格式16 位源/目标端口号32 位序列号*32 位确认应答号4 位…...

Golang 中的 time 包详解(二):time.Duration

在日常开发过程中&#xff0c;会频繁遇到对时间进行操作的场景&#xff0c;使用 Golang 中的 time 包可以很方便地实现对时间的相关操作。接下来的几篇文章会详细讲解 time 包&#xff0c;本文讲解一下 time 包中的 time.Duration 类型。 time.Duration time.Duration 类型是…...

Linux 学习记录58(ARM篇)

Linux 学习记录58(ARM篇) 本文目录 Linux 学习记录58(ARM篇)一、GIC相关寄存器1. 系统框图2. 中断号对应关系 二、GICD寄存器1. GICD_CTLR2. GICD_ISENABLERx3. GICD_IPRIORITYRx4. GICD_ITARGETSRx5. GICD_ICPENDRx 三、GICC寄存器1. GICC_PMR2. GICC_CTLR3. GICC_IAR4. GICC_…...

【一文搞懂】—带霍尔编码器的直流有刷减速电机

文章目录 一、直流有刷电机二、减速比三、霍尔编码器3.1 霍尔编码器3.2 霍尔编码器测速原理 四、测速程序设计4.1 跳变沿检测4.2 计算转速 一、直流有刷电机 宏观上说直流有刷电机由固定部分&#xff08;定子&#xff09;和旋转部分&#xff08;转子&#xff09;组成。在定子上…...

滴水逆向三期笔记与作业——02C语言——05 正向基础/05 循环语句

目录 一、缓冲区溢出的HelloWorld二、永不停止的HelloWorld三、基础知识3.1 变量的声明3.2 类型转换&#xff08;一般用于小转大&#xff09;3.3 表达式3.4 语句和程序块3.5 参数与返回值3.6 关系运算符3.7 逻辑运算符&#xff1a;&& || !3.8 单目运算符3.9 三目运算符…...