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

《微服务实战》 第二十八章 分布式锁框架-Redisson

前言

Redisson 在基于 NIO 的 Netty 框架上,充分的利⽤了 Redis 键值数据库提供的⼀系列优势,在Java 实⽤⼯具包中常⽤接⼝的基础上,为使⽤者提供了⼀系列具有分布式特性的常⽤⼯具类。使得原本作为协调单机多线程并发程序的⼯具包获得了协调分布式多机多线程并发系统的能⼒,⼤⼤降低了设计和研发⼤规模分布式系统的难度。同时结合各富特⾊的分布式服务,更进⼀步简化了分布式环境中程序相互之间的协作。

1、redisson工作原理

在这里插入图片描述

2、看门狗原理

A服务先运行,在运行B服务,还没释放A的锁,A就挂了,会不会死锁呢?
答:没有导致死锁,因为底层有看门狗机制
默认指定锁时间为30s(看门狗时间)
锁的自动续期:若是业务超长,运行期间自动给锁上新的 30s,不用担心业务时间过长,锁就自动过期
加锁的业务只要运行完成,就不会给当前锁续期,及时不手动解锁,锁默认在30s 后自动删除。

3、spring boot与redisson的整合

3.1、添加库存服务:

stock-service

3.2、添加依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2021.0.4.0</version></dependency>--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.19.1</version></dependency>

3.3、添加配置

3.3.1、单机

redisson:addr:singleAddr:host: redis://localhost:6379password: 123456database: 0pool-size: 10

3.3.2、集群

redisson:addr:cluster:hosts: redis://47.96.11.185: 6370,...,redis://47.96.11.185:6373password : 123456

3.3.3、主从

redisson:addr:masterAndSlave:masterhost: redis : //47.96.11.185 : 6370slavehosts: redis://47.96.11.185: 6371,redis://47.96.11.185:6372password : 123456database : 0

3.4、配置RedissonClient

3.4.1、单机

/*** 配置RedissonClient*/
@Configuration
public class RedissonConfig {@Value("${redisson.addr.singleAddr.host}")private String host;@Value("${redisson.addr.singleAddr.password}")private String password;@Value("${redisson.addr.singleAddr.database}")private int database;@Value("${redisson.addr.singleAddr.pool-size}")private int poolSize;@Beanpublic RedissonClient redissonClient(){Config config = new Config();config.useSingleServer().setAddress(host).setPassword(password).setDatabase(database).setConnectionPoolSize(poolSize).setConnectionMinimumIdleSize(poolSize);return Redisson.create(config);}
}

3.4.2、集群

/*** 配置RedissonClient*/
@Configuration
public class RedissonConfig {@Value("${redisson.addr.cluster.hosts}")private String hosts;@Value("${redisson.addr.cluster.password}")private String password;/*** 集群模式** @return*/@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useClusterServers().addNodeAddress(hosts.split("[,]")).setPassword(password).setScanInterval(2000).setMasterConnectionPoolSize(10000).setSlaveConnectionPoolSize(10000);return Redisson.create(config);}
}

3.4.3、集群

/*** 配置RedissonClient*/
@Configuration
public class RedissonConfig {@Value("${redisson.addr.masterAndSlave.masterhost}")private String masterhost;@Value("${redisson.addr.masterAndSlave.slavehosts}")private String slavehosts;@Value("${redisson.addr.masterAndSlave.password}")private String password;@Value("${redisson.addr.masterAndSlave.database}")private int database;/*** 主从模式** @return*/@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useMasterSlaveServers().setMasterAddress(masterhost).addSlaveAddress(slavehosts.split("[,]")).setPassword(password).setDatabase(database).setMasterConnectionPoolSize(10000).setSlaveConnectionPoolSize(10000);return Redisson.create(config);}
}

3.5、Redisson的使用

  • 获取锁 —— 公平锁和⾮公平锁
    // 获取公平锁
    RLock lock = redissonClient . getFairLock ( skuId );
    // 获取⾮公平锁
    RLock lock = redissonClient . getLock ( skuId );
  • 加锁 —— 阻塞锁和⾮阻塞锁
    // 阻塞锁(如果加锁成功之后,超时时间为 30s ;加锁成功开启看⻔狗,剩 5s 延⻓过期时间)
    lock . lock ();
    // 阻塞锁(如果加锁成功之后,设置⾃定义 20s 的超时时间)
    lock . lock ( 20 , TimeUnit . SECONDS );
    // ⾮阻塞锁(设置等待时间为 3s ;如果加锁成功默认超时间为 30s )
    boolean b = lock . tryLock ( 3 , TimeUnit . SECONDS );
    // ⾮阻塞锁(设置等待时间为 3s ;如果加锁成功设置⾃定义超时间为 20s )
    boolean b = lock . tryLock ( 3 , 20 , TimeUnit . SECONDS );
  • 释放锁
    lock . unlock ();
  • 应⽤示例
    // 公平⾮阻塞锁
    RLock lock = redissonClient . getFairLock ( skuId );
    boolean b = lock . tryLock ( 3 , 20 , TimeUnit . SECONDS );
  • 减库存加锁案例

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.TimeUnit;@RestController
@RequestMapping("/stock")
public class StockController {@Autowiredprivate RedissonClient redissonClient;@GetMapping("/reduceStock")public void reduceStock(@RequestParam String productId){// 获取⾮公平锁RLock lock = this.redissonClient.getLock("stock:" + productId);// 阻塞锁(如果加锁成功之后,设置⾃定义 20s 的超时时间)lock.lock(30, TimeUnit.SECONDS);System.out.println("加锁成功." + Thread.currentThread().getName());try {TimeUnit.SECONDS.sleep(25);} catch (InterruptedException e) {e.printStackTrace();}finally {System.out.println("解锁成功." + Thread.currentThread().getName());lock.unlock();}}
}

测试:浏览器发起两次两次减库存
http://localhost:8099/stock/reduceStock?productId=001

3.6、aop实现分布式锁

3.6.1、定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributeLock {/*** 参数下标* @return*/int[] lockIndex() default {-1} ;/*** 锁的等待时间* @return*/long waitTime() default 3000;/*** 时间单位* @return*/TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

3.6.2、定义切面

/*** 定义分布式锁的切面*/
@Component
@Aspect
public class DistributeLockAspect {@Autowiredprivate RedissonClient redissonClient;@Around(value = "@annotation(lock)")public void distibuteLock(ProceedingJoinPoint proceedingJoinPoint, DistributeLock lock){Signature signature = proceedingJoinPoint.getSignature();StringBuilder stringBuilder = new StringBuilder();//方法所属的类String declaringTypeName = signature.getDeclaringTypeName();String name = signature.getName();stringBuilder.append(declaringTypeName);stringBuilder.append(name);//获取调用方法的参数Object[] args = proceedingJoinPoint.getArgs();int[] ints = lock.lockIndex();if(args != null) {final int length = args.length;if (length >0) {//考虑下标越界for (int anInt : ints) {//把合法下标值放到sbif (anInt >= 0 && anInt < length){stringBuilder.append(JSON.toJSONString(args[anInt]));}}}}//将方法的信息转成md5,作为锁的标识String key = SecureUtil.md5(stringBuilder.toString());//获取锁RLock rLock = redissonClient.getLock(key);//从注解获取时间单位TimeUnit timeUnit = lock.timeUnit();//从注解等待时间long waitTime = lock.waitTime();//执行业务代码try {//加锁rLock.tryLock(waitTime,timeUnit);System.out.println("成功加锁。" + Thread.currentThread().getName());proceedingJoinPoint.proceed();} catch (Throwable e) {e.printStackTrace();}finally {//解锁rLock.unlock();System.out.println("成功解锁。" + Thread.currentThread().getName());}}
}

注解的使用:

@DistributeLock(lockIndex = {0,1},waitTime = 3,timeUnit = TimeUnit.SECONDS)

相关文章:

《微服务实战》 第二十八章 分布式锁框架-Redisson

前言 Redisson 在基于 NIO 的 Netty 框架上&#xff0c;充分的利⽤了 Redis 键值数据库提供的⼀系列优势&#xff0c;在Java 实⽤⼯具包中常⽤接⼝的基础上&#xff0c;为使⽤者提供了⼀系列具有分布式特性的常⽤⼯具类。使得原本作为协调单机多线程并发程序的⼯具包获得了协调…...

局部搜索,变邻域搜索算法

目录 局部搜索 02 变邻域搜索算法 局部搜索 1.1 局部搜索是什么玩意儿? 官方一点:局部搜索是解决优化问题的一种启发式算法。对于某些计算起来非常复杂的优化问题,比如各种NP-难问题,要找到最优解需要的时间随问题规模呈指数增长,因此诞生了各种启发式算法来退而求其次…...

软件工程实训——第一天

第一天 前后分离 前端&#xff1a;android 后端&#xff1a;springbootmbatis-plus 高心星 软件工程的思维来开发项目 问题定义 可行性研究 需求分析 概要设计 详细设计 编码 测试 维护 需求分析 1.用户的信息管理 2.新增支出 3.新增收入 4.支出统计 5.收入…...

嵌入式C语言中if/else如何优化详解

观点一&#xff08;灵剑&#xff09;&#xff1a; 前期迭代懒得优化&#xff0c;来一个需求&#xff0c;加一个if&#xff0c;久而久之&#xff0c;就串成了一座金字塔。 当代码已经复杂到难以维护的程度之后&#xff0c;只能狠下心重构优化。那&#xff0c;有什么方案可以优雅…...

【LSTM】读取时间序列数据 | 时间序列数据的小批量划分方法

由于序列数据本质上是连续的&#xff0c;因此我们在处理数据时需要解决这个问题。当序列过长而不能被模型一次性全部处理时&#xff0c;我们希望能拆分这样的序列以便模型方便读取。 Q&#xff1a;怎样随机生成一个具有n个时间步的mini batch的特征和标签&#xff1f; A&…...

K8s in Action 阅读笔记——【12】Securing the Kubernetes API server

K8s in Action 阅读笔记——【12】Securing the Kubernetes API server 12.1 Understanding authentication 在上一章中&#xff0c;我们提到API服务器可以配置一个或多个认证插件&#xff08;授权插件也是同样的情况&#xff09;。当API服务器接收到一个请求时&#xff0c;它…...

爆肝整理,3个月从功能进阶自动化测试,一跃成测试卷王...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 首先先了解自动化…...

人生这场概率游戏,怎么玩

只会标准答案&#xff0c;是不可救药的愚蠢 那么为了便于理解&#xff0c;我用一些典型的案例来讲解&#xff0c;什么是概率游戏&#xff0c;以及这个游戏&#xff0c;应该怎么玩。 比如典型的相亲&#xff0c;婚恋。人生大事&#xff0c;用标准答案来说&#xff0c;你的意中人…...

Redis笔记

缓存过期时间很重要&#xff01;redis是单线程的 对于内存过多的3中方案&#xff1a; 惰性删除&#xff1a; 在定时删除的基础上&#xff0c;对于已经过期了的数据&#xff0c;redis的随机选择算法一直没有选中这个数据&#xff0c;所以导致它就一直没被删除&#xff0c;但是…...

centos 安装supervisor并运行网站

前言 之前一直用宝塔的**进程守护管理器【Supervisor】**来启动一些项目,如ThinkPHP、Hyperf的项目,或laravel的一些命令。如果不用宝塔怎么办呢? 一、简介[supervisor] [Supervisor] 是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支…...

Hadoop面试题十道

问题 1&#xff1a;Hadoop是什么&#xff1f; 答案&#xff1a;Hadoop是一个开源的分布式计算框架&#xff0c;用于处理大规模数据集的存储和处理。它基于Google的MapReduce和Google文件系统&#xff08;GFS&#xff09;的思想&#xff0c;旨在解决大数据量的处理和分析问题。…...

使用Docker-Compose对Docker容器集群快速编排

目录 一、Docker-Compose1、Docker-Compose使用场景2、Docker-Compose简介3、Docker-Compose安装部署4、YAML 文件格式及编写注意事项5、Docker Compose配置常用字段6、Docker Compose 常用命令7、Docker Compose 文件结构8、docker Compose撰写nginx 镜像9、docker Compose撰写…...

React-Redux 对Todolist修改

在单独使用redux的时候 需要手动订阅store里面 感觉特别麻烦 不错的是react有一个组件可以帮我们解决这个问题, 那就是react-redux。 react-redux提供了Provider 和 connent给我们使用。 先说一下几个重点知道的知识 Provider 就是用来提供store里面的状态 自动getState()co…...

初识微信小程序

新建小程序 创建一个新的微信小程序项目&#xff1a; 打开微信开发者工具&#xff0c;点击“新建项目”。 在弹出的窗口中&#xff0c;填写小程序的 AppID、项目名称和项目目录等信息。 点击“确定”按钮&#xff0c;等待微信开发者工具自动下载并安装所需的依赖库和框架。 …...

我们该如何入门编程呢

提醒&#xff1a;以下内容仅做参考&#xff0c;可自行发散。在发布作品前&#xff0c;请把不需要的内容删掉。 随着信息技术的快速发展&#xff0c;编程已经成为一个越来越重要的技能。那么&#xff0c;我们该如何入门编程呢&#xff1f;选择编程语言&#xff1a;选择一种编程…...

App 软件开发《判断6》试卷及答案

App 软件开发《判断6》试卷及答案 文章目录 App 软件开发《判断6》试卷及答案判断题&#xff08;对的打“√”&#xff0c;错的打“”&#xff1b;共0分&#xff09;1&#xff0e;”ionic resources --icon"命令用于生成适应不同分辨率的App图标所应用的图片。(✔)2&#…...

MVC工作原理

MVC工作原理 有视图的情况 1.客户端&#xff08;浏览器&#xff09;发起请求&#xff0c;DispatcherServlet拦截请求。 2.DispatcherServlet根据请求信息调用HandlerMapping。HandlerMapping根据uri去匹配查询能处理的Handler&#xff08;也就是我们所说的Controller&#x…...

使用 Redis 统计网站 UV 的方法

使用 Redis 统计网站 UV 的方法(概率算法) 文章目录 前言思路HyperLogLog 使用 Redis 命令操作使用 Java 代码操作 HyperLogLog 实现原理及特点使用 Java 实现 HyperLogLog小结 前言 网站 UV 就是指网站的独立用户访问量Unique Visitor&#xff0c;即相同用户的多次访问需要…...

黑客工具软件大全

黑客工具软件大全100套 给大家准备了全套网络安全梓料&#xff0c;有web安全&#xff0c;还有渗透测试等等内容&#xff0c;还包含电子书、面试题、pdf文档、视频以及相关的网络安全笔记 &#x1f447;&#x1f447;&#x1f447; 《黑客&网络安全入门&进阶学习包》 &a…...

uniapp主题切换功能的第二种实现方式(scss变量+require)

在上一篇 “uniapp主题切换功能的第一种实现方式&#xff08;scss变量vuex&#xff09;” 中介绍了第一种如何切换主题&#xff0c;但我们总结出一些不好的地方&#xff0c;例如扩展性不强&#xff0c;维护起来也困难等等&#xff0c;那么接下我再给大家介绍另外一种切换主题的…...

# 蓝牙音频相关知识

蓝牙音频相关知识 文章目录 蓝牙音频相关知识1 音频源2 蓝牙音频编解码器3 一些标准4 蓝牙音频其他相关知识4.1 蓝牙版本4.2 ANC&#xff08;主动降噪&#xff09;4.3 音响相关参数4.4 音质评价4.5 HI-Fi声音特点4.6 耳机线材4.7 耳机分类4.8 IP防尘防水等级4.9 噪音与量化噪音…...

【AI作画】使用DiffusionBee with stable-diffusion在mac M1平台玩AI作画

DiffusionBee是一个完全免费、离线的工具。它简洁易用&#xff0c;你只需输入一些标签或文本描述&#xff0c;它就能生成艺术图像。 DiffusionBee下载地址 运行DiffusionBee的硬性要求&#xff1a;MacOS系统版本必须在12.3及以上 DBe安装完成后&#xff0c;去C站挑选自己喜欢…...

2 STM32库函数 之 通用同步异步收发器(USART、串口)所有函数的介绍及使用

2 STM32库函数 之 通用同步异步收发器&#xff08;USART、串口&#xff09;所有函数的介绍及使用 前言一、USART固件库函数预览二、USART固件库函数具体介绍2.1 库函数 USART_DeInit2.2 库函数 USART_Init2.2.1 USART_InitTypeDef structure2.2.2 USART_InitTypeDef 成员 USART…...

SpringCloudAlibaba整合Sentinel实现流量控制熔断降级

目录 一、概念 二、整合Sentinel控制台 三、Sentinel规则配置 四、@SentinelResource资源保护注解...

CentOS 7安装 Postgre

零、前置条件 系统CentOS 7&#xff0c;并已联网&#xff0c;已安装gcc或者g编译器&#xff0c;GNU make版本3.80或以上&#xff0c;系统有至少一个除root之外的普通用户user gcc安装-参考链接查看make命令的版本——make --version更新make版本-参考链接postgresql的使用一般…...

rpc 异步非阻塞 io 配置 线程池和队列

相关 雪崩 - 如何重试 - sla和重试风暴的双保证_个人渣记录仅为自己搜索用的博客-CSDN博客 接口耗时公式 耗时 cpu时间 io时间 线程池数量 最佳数目 1s / 平均cpu时间 * 内核数. 最大平均cpu时间 接口耗时- all外部io时间. 结合gc , linux本身其他线程, 只会还少点. …...

【Turfjs的java版本JTS】前面讲了Turfjs可以实现几何计算,空间计算的功能,如果后端要做这项功能也有类似的类库,JTS

JTS Java Topology Suite 几何计算&#xff1a; 1. 前端js就用这个 Turfjs的类库。参考网站&#xff1a; 计算两线段相交点 | Turf.js中文网 2. 后端java语言就可以用 JTS这个类库&#xff0c;参考网站&#xff1a; JTS参考网站&#xff1a; 1. https://github.com/locatio…...

从Window中先多瞥几眼

JavaFx17官方文档中有如下的描述: Window类是一个顶层窗口类,在其中可以承载场景,并与用户交互。窗口可以是Stage、PopupWindow或其他类似的顶层窗口。 JavaFX Stage类是顶级的JavaFX容器。初级阶段由平台搭建。其他Stage对象可以由应用程序构造。 许多Stage属性是只读的…...

【STM32训练—WiFi模块】第二篇、STM32驱动ESP8266WiFi模块获取天气

目录 第一部分、前言 1、获取心知天气API接口 2、硬件准备 第二部分、电脑串口助手调试WIFI模块获取天气 1、ESP8266获取天气的流程 2、具体步骤 第三部分、STM32驱动ESP8266模块获取天气数据 1、天气数据的解析 1.1、什么函数来解析天气数据&#xff1f; 2.1、解析后…...

Maven私服

Maven 私服是一种特殊的远程仓库&#xff0c;它是架设在局域网内的仓库服务&#xff0c;用来代理位于外部的远程仓库&#xff08;中央仓库、其他远程公共仓库&#xff09;。 建立了 Maven 私服后&#xff0c;当局域网内的用户需要某个构件时&#xff0c;会按照如下顺序进行请求…...

深圳做电商网站/推广平台排行榜

吉林实验室洗煤压滤机欢迎来电,在冬季&#xff0c;被过滤液也会发生变化&#xff0c;从而间接的影响压滤机。过滤液在这个季节&#xff0c;其活动性没在夏季那么强&#xff0c;所以其流动性也会降低一些&#xff0c;这样就是导致了被过滤液在穿过滤布时的速度会减慢&#xff0c…...

网站建设代码问卷调查/上海专业做网站

一开始装ubuntu的时候&#xff0c;好多初学者不知道如何添加源&#xff0c;如此问题反反复复&#xff0c;新手又不怎么去GOOGLE&#xff0c;现在我把这些问题整理下&#xff0c;帮助新手理解并使用&#xff1a;什么是 Ubuntu Linux 软件源源&#xff0c;在ubuntu下&#xff0c;…...

教育网站开发用例图/seo诊断方法步骤

jna jni我最近偶然发现了一个不错的框架&#xff0c;如果您不得不使用本机代码的话&#xff0c;您会喜欢的。 在此框架之前&#xff0c;如果需要调用本机代码&#xff0c;则可以使用JNI 。 JNI使用了一个经过验证的但复杂且容易出错的过程。 首先&#xff0c;您像往常一样编写J…...

个人装修队/武汉排名seo公司

这是一道区间贪心的题目&#xff0c;对于这道题&#xff0c;由于岛屿的位置在坐标轴上是确定的&#xff0c;而雷达的位置及数量则无法确定&#xff0c;因此我们可以根据岛屿来确定雷达的位置及数量。首先&#xff0c;我们可以根据岛屿的位置以及雷达的半径来确定覆盖该岛屿的雷…...

做网站的软件dw/免费建网站

PPP-C#conf tPPP-C(config)#vpdn enable //启用路由器的虚拟专用拨号网络---***d 由于ADSL的PPPoE应用是通过虚拟拨号来实现的所以在路由器中需要使用VPDN的功能PPP-C(config)#int e1/0 // 路由器内网接口PPP-C(config-if)#no shutPPP-C(config-if)#i…...

做动态网站必学/广告推广网站

💥 项目专栏:【Pandas数据处理100例目录】Python数据分析玩转Excel表格数据 前言 大家好,我是阿光。 本专栏整理了《Pandas数据分析处理》,内包含了各种常见的数据处理,以及Pandas内置函数的使用方法,帮助我们快速便捷的处理表格数据。 正在更新中~ ✨ 🚨 我的项目…...