redisssion分布式锁
分布式锁的问题
基于setnx的分布式锁实现起来并不复杂,不过却存在一些问题。
锁误删问题
第一个问题就是锁误删问题,目前释放锁的操作是基于DEL,但是在极端情况下会出现问题。
例如,有线程1获取锁成功,并且执行完任务,正准备释放锁:
总结一下,误删的原因归根结底是因为什么?
-
超时释放
-
判断锁标示、删除锁两个动作不是原子操作
超时释放问题
除了上述问题以外,分布式锁还会碰到一些其它问题:
-
锁的重入问题:同一个线程多次获取锁的场景,目前不支持,可能会导致死锁
-
锁失败的重试问题:获取锁失败后要不要重试?目前是直接失败,不支持重试
-
Redis主从的一致性问题:由于主从同步存在延迟,当线程在主节点获取锁后,从节点可能未同步锁信息。如果此时主宕机,会出现锁失效情况。此时会有其它线程也获取锁成功。从而出现并发安全问题。
-
...
当然,上述问题并非无法解决,只不过会比较麻烦。例如:
-
原子性问题:可以利用Redis的LUA脚本来编写锁操作,确保原子性
-
超时问题:利用WatchDog(看门狗)机制,获取锁成功时开启一个定时任务,在锁到期前自动续期,避免超时释放。而当服务宕机后,WatchDog跟着停止运行,不会导致死锁。
-
锁重入问题:可以模拟Synchronized原理,放弃setnx,而是利用Redis的Hash结构来记录锁的持有者以及重入次数,获取锁时重入次数+1,释放锁是重入次数-1,次数为0则锁删除
-
主从一致性问题:可以利用Redis官网推荐的RedLock机制来解决
快速入门
首先引入依赖:
<!--redisson-->
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId>
</dependency>
然后配置:
@Configurationpublic class RedisConfig {@Beanpublic RedissonClient redissonClient() {// 配置类Config config = new Config();// 添加redis地址,这里添加了单点的地址,也可以使用config.useClusterServers()添加集群地址 config.useSingleServer().setAddress("redis://192.168.150.101:6379").setPassword("123321");// 创建客户端return Redisson.create(config);}}
使用:
看门狗机制不能设置失效时间,设置失效时间看门狗会失效
lock.unlock() 虽然看起来简单,但是底层释放的是当前锁,不会释放其他的锁
@Autowiredprivate RedissonClient redissonClient;@Testvoid testRedisson() throws InterruptedException {// 1.获取锁对象,指定锁名称RLock lock = redissonClient.getLock("anyLock");try {// 2.尝试获取锁,参数:waitTime、leaseTime、时间单位// 设置失效时间看门狗会失效boolean isLock = lock.tryLock();if (!isLock) {// 获取锁失败处理 ..} else {// 获取锁成功处理}} finally {// 4.释放锁lock.unlock();}}
利用Redisson获取锁时可以传3个参数:
-
waitTime:获取锁的等待时间。当获取锁失败后可以多次重试,直到waitTime时间耗尽。waitTime默认-1,即失败后立刻返回,不重试。
-
leaseTime:锁超时释放时间。默认是30,同时会利用WatchDog来不断更新超时时间。需要注意的是,如果手动设置leaseTime值,会导致WatchDog失效。
-
TimeUnit:时间单位
集成
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.tianji.common.autoconfigure.redisson.aspect.LockAspect;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.time.Duration;
import java.util.ArrayList;
import java.util.List;@Slf4j
@ConditionalOnClass({RedissonClient.class, Redisson.class})
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedissonConfig {private static final String REDIS_PROTOCOL_PREFIX = "redis://";private static final String REDISS_PROTOCOL_PREFIX = "rediss://";@Bean@ConditionalOnMissingBeanpublic LockAspect lockAspect(RedissonClient redissonClient){return new LockAspect(redissonClient);}@Bean@ConditionalOnMissingBean // 当spring容器中没有redissionClient 对象才会创建public RedissonClient redissonClient(RedisProperties properties){log.debug("尝试初始化RedissonClient");// 1.读取Redis配置RedisProperties.Cluster cluster = properties.getCluster();RedisProperties.Sentinel sentinel = properties.getSentinel();String password = properties.getPassword();int timeout = 3000;Duration d = properties.getTimeout();if(d != null){timeout = Long.valueOf(d.toMillis()).intValue();}// 2.设置Redisson配置Config config = new Config();if(cluster != null && !CollectionUtil.isEmpty(cluster.getNodes())){// 集群模式config.useClusterServers().addNodeAddress(convert(cluster.getNodes())).setConnectTimeout(timeout).setPassword(password);}else if(sentinel != null && !StrUtil.isEmpty(sentinel.getMaster())){// 哨兵模式config.useSentinelServers().setMasterName(sentinel.getMaster()).addSentinelAddress(convert(sentinel.getNodes())).setConnectTimeout(timeout).setDatabase(0).setPassword(password);}else{// 单机模式config.useSingleServer().setAddress(String.format("redis://%s:%d", properties.getHost(), properties.getPort())).setConnectTimeout(timeout).setDatabase(0).setPassword(password);}// 3.创建Redisson客户端return Redisson.create(config);}private String[] convert(List<String> nodesObject) {List<String> nodes = new ArrayList<>(nodesObject.size());for (String node : nodesObject) {if (!node.startsWith(REDIS_PROTOCOL_PREFIX) && !node.startsWith(REDISS_PROTOCOL_PREFIX)) {nodes.add(REDIS_PROTOCOL_PREFIX + node);} else {nodes.add(node);}}return nodes.toArray(new String[0]);}
}
几个关键点:
-
这个配置上添加了条件注解
@ConditionalOnClass({RedissonClient.
class
, Redisson.
class
})
也就是说,引用了Redisson依赖,这套配置就会生效。不引入Redisson依赖,配置自然不会生效,从而实现按需引入。 -
RedissonClient的配置无需自定义Redis地址,而是直接基于SpringBoot中的Redis配置即可。而且不管是Redis单机、Redis集群、Redis哨兵模式都可以支持
所以,在微服务中应用的步骤:
-
引入Redisson依赖
-
注入RedissonClient,使用分布式锁
相关文章:
redisssion分布式锁
分布式锁的问题 基于setnx的分布式锁实现起来并不复杂,不过却存在一些问题。 锁误删问题 第一个问题就是锁误删问题,目前释放锁的操作是基于DEL,但是在极端情况下会出现问题。 例如,有线程1获取锁成功,并且执行完任…...
嘎嘎嘎拿到去年想要的包
一年多了 继续,把项目收尾吧 好好学前端,外企!react!从0开始,紧迫!加油!...
前奏编曲:如何编写二段式前奏
选好音源 Pianoteq 6 STAGE比较明亮些,适合做前奏的音源 确定和弦进行 比如4536251,每个小节2和弦,每个小节的和弦弹一下 优化和弦进行衔接和织体 二段式不用对和弦进行就近解决的处理,因为前奏前后要形成对比。 前半部分往…...
征服云端:Kubernetes如何让微服务与云原生技术如虎添翼
引言 在这个数字化转型的时代,微服务架构已经成为构建现代应用程序的首选方式。它不仅提高了开发效率,还增强了系统的可扩展性和灵活性。而随着云计算技术的迅猛发展,云原生的概念逐渐深入人心,它代表了一种全新的软件开发方法论…...
开源AI智能名片系统与高级机器学习技术的融合应用:重塑商务交流的未来
摘要:在数字化浪潮的推动下,人工智能(AI)技术,尤其是机器学习领域的快速发展,正深刻改变着各行各业的面貌。开源AI智能名片系统作为这一变革的先锋,通过集成并优化多种高级机器学习技术…...
Java中synchronized的偏向锁是如何减少锁开销的
偏向锁(Biased Locking)是一种优化 Java synchronized 锁的机制,旨在减少在无竞争情况下的锁开销。它通过将锁偏向于单个线程来优化锁的性能。以下是偏向锁减少锁开销的具体方式和原理: 偏向锁的工作原理 锁的初始状态: 当一个对…...
react18 + ts 使用video.js 直播.m3u8格式的视频流
一、安装依赖 我使用的video.js版本是8.17.3,从 Video.js 7.x 开始,HLS 支持被内置到了 Video.js 中所以不需要安装其他依赖 npm i video.js 二、创建VideoPlayer组件 import React, { useEffect, useRef } from react import videojs from video.js …...
使用 onBeforeRouteLeave 组合式函数提升应用的用户体验
title: 使用 onBeforeRouteLeave 组合式函数提升应用的用户体验 date: 2024/8/14 updated: 2024/8/14 author: cmdragon excerpt: 摘要:本文介绍了在Nuxtjs中使用onBeforeRouteLeave组合式函数来提升应用用户体验的方法。onBeforeRouteLeave允许在组件离开当前路…...
uni-app 吸顶方案总结
效果 页面级 uni.pageScrollTo 官方文档:https://uniapp.dcloud.net.cn/api/ui/scroll.html#pagescrollto 原生头部导航 uni.pageScrollTo({selector: #tabs,duration: 300 });(推荐)需要兼容自定义头部导航 <template><view id"demo1" :styl…...
【C#】知识汇总
目录 1 概述1.1 GC(Garbage Collection)1.1.1 为什么需要GC?1.1.2 GC的工作原理工作原理什么是Root?GC算法:Mark-Compact 标记压缩算法GC优化:Generational 分代算法 1.1.3 GC的触发时间1.1.4 如何减少垃圾…...
1、Unity【基础】3D数学
3D数学 文章目录 3D数学1、数学计算公共类Mathf1、Mathf和Math2、区别3、Mathf中的常用方法(一般计算一次)4、Mathf中的常用方法(一般不停计算)练习 A物体跟随B物体移动 2、三角函数1、角度和弧度2、三角函数3、反三角函数练习 物…...
虚拟机ubuntu22的扩容记录
这里lsblk命令能看到, ubuntu逻辑分区只有29G, 但总分区60G,还有接近30G未使用。 rootx:/home/x# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 63.9M 1 loop /snap/core2…...
Docker 常用配置
Docker 常用配置 1. 配置方法 修改下面位置: Linux:vim /etc/docker/daemon.jsonmacOS:菜单栏图标->Settings->Docker Engine 注意:修改完需要重启Docker Linux:systemctl restart dockermacOS:…...
通过示例了解 .NET Core 中的依赖注入
依赖注入 (DI) 是一种用于实现 IoC(控制反转)的设计模式,可以更好地解耦应用程序内的依赖关系并更轻松地管理它们。.NET Core 内置了对依赖注入的支持,提供了一种有效管理依赖关系的强大方法。 一.什么是依赖注入? 依…...
fetch、FormData上传多张图片
利用fetch方法和FormData对象上传多张图片 formdata()对象可以序列化多张图片 <html><head><meta http-equiv"content-type" content"text/html;charsetUTF-8"/><title>测试fetch和formdata上传多张图片</title></head&…...
C++STL详解(五)——list类的具体实现
一.本次所需实现的三个类及其成员函数接口 链表首先要有结点,因此我们需要实现一个结点类。 链表要有管理结点的结构,因此我们要有list类来管理结点。 链表中还要有迭代器,而迭代器的底层其实是指针。但是我们现有的结点类无法完成迭代器的…...
鸿蒙(API 12 Beta3版)【使用投播组件】案例应用
华为视频接入播控中心和投播能力概述** 华为视频在进入影片详情页播放时,支持在控制中心查看当前播放的视频信息,并进行快进、快退、拖动进度、播放暂停、下一集、调节音量等操作,方便用户通过控制中心来操作当前播放的视频。 当用户希望通…...
【STM32项目】在FreeRtos背景下的实战项目的实现过程(一)
个人主页~ 这篇文章是我亲身经历的,在做完一个项目之后总结的经验,虽然我没有将整个项目给放出来,因为这项目确实也是花了米让导师指导的,但是这个过程对于STM32的实战项目开发都是非常好用的,可以说按照这个过程&…...
C#垃圾处理机制相关笔记
C#编程中的垃圾处理机制主要通过垃圾回收器(Garbage Collector,GC)实现自动内存管理。C#作为一种托管语言,其垃圾处理机制显著减轻了程序员的内存管理负担,与C语言等非托管语言形成鲜明对比。具体介绍如下:…...
C语言memcmp函数
目录 开头1.什么是memcmp函数?2.memcmp函数的内部程序流程图 3.memcmp函数的实际应用比较整型数组比较短整型二维数组比较结构体变量…… 结尾 开头 大家好,我叫这是我58。今天,我们要学一下关于C语言里的memcmp函数的一些知识。 1.什么是memcmp函数?…...
低代码: 组件库测试之Vue环境下的测试工具以及测试环境搭建
Vue Test Utils Vue Test Utils 1 targets Vue 2. Vue Test Utils 2 targets Vue 3. 特别注意要使用 版本 2.0.0 以上 提供特定的方法,在隔离的话环境下,进行组件的挂载,以及一系列的测试 配置开发环境 手动配置, 是比较麻烦的vue cli 是基于插件架构的, 插件可以: 安装对…...
【Vue3】高颜值后台管理模板推荐
ELP - 权限管理系统 基于Vue 3框架与PrimeVue UI组件库技术精心构建的高颜值后台权限管理系统模板。该模板系统已成功实现基于RBAC(Role-Based Access Control)模型的权限管理系统和字典数据管理模块,后端则使用了Spring Boot框架࿰…...
详细介绍Pytorch中torchvision的相关使用
torchvision 是 PyTorch 的一个官方库,主要用于处理计算机视觉任务。提供了许多常用的数据集、模型架构、图像转换等功能,使得计算机视觉任务的开发变得更加高效和便捷。以下是对 torchvision 主要功能的详细介绍: 1. 数据集(Dat…...
AI部署——主流模型推理部署框架
我们以最经典的Yolov5目标检测网络为例解释一下10种主流推理部署框架的大概内容,省略模型训练的过程,只讨论模型转换、环境配置、推理部署等步骤。 Intel的OpenVINO — CPUNvidia的TensorRT — GPU/CPUOpenCV DNN Module — GPU/CPUMicrosoft ONNX Runti…...
PyTorch之loading fbgemm.dll异常的解决办法
前言 PyTorch是一个深度学习框架,当我们在本地调试大模型时,可能会选用并安装它,目前已更新至2.4版本。 一、安装必备 1. window 学习或开发阶段,我们通常在window环境下进行,因此需满足以下条件: Windo…...
Vscode——如何实现 Ctrl+鼠标左键 跳转函数内部的方法
一、对于Python代码 安装python插件即可实现 二、对于C/C代码 安装C/C插件即可实现...
力扣热题100_回溯_78_子集
文章目录 题目链接解题思路解题代码 题目链接 78. 子集 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入ÿ…...
浏览器如何工作(一)进程架构
分享cosine 大佬,版权©️大佬所有 浏览器的核心功能 浏览器,“浏览” 是这个产品的核心,浏览无非分为两步: 获取想浏览的资源 展示得到的资源 现代浏览器还增加了交互功能,这涉及到脚本运行。因此,…...
【LeetCode】两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。 你可以按任意顺序返回答案。 示例 1…...
UE5学习笔记11-为拿取武器添加动画
一、一点说明 动画实例通过扩展为所有机器上的每个字符都存在动画蓝图,动画实例只能访问该计算机上的变量。 二、思路 我在武器组件中有一个武器类的指针,判断当前指针是否为空去判断当前角色是否装备武器 三、实现 1.在角色C类中添加是否装备武器的函…...
做网站需要多少人/唐山建站公司模板
Fedora28安装opencv-4.1.0+opencv_contrib-4.1.0 1.环境配置 OpenCV4.1.0和opencv_contrib-4.1.0的安装包大家可从GitHub上搜索下载,如果不想搜索,可从我的百度网盘下载(同时网盘内也上传了一些Cmake易下载失败的文件): 链接:https://pan.baidu.com/s/1aVCjkfw7Mh0rZe9iZ…...
山东网站建设都有那些/如何在各种网站投放广告
本文实例讲述了静态页面html中跳转传值的JS处理技巧。分享给大家供大家参考,具体如下:在html中通过"?"传值:静态传值在跳转到的页面index2.html中接收:var nameUrlParm.parm("name");代码如下:in…...
东莞网站建设图表/方象科技专注于什么领域
2019独角兽企业重金招聘Python工程师标准>>> win10安装配置nodejs 下载node 官网下载node接下来在命令提示符里(winR)输入node -v和npm -v,如图所示,表示安装完成。测试, 配置node 在nodejs文件目录下&a…...
有趣的网站官网/谷歌seo优化中文章
1、Mybatis优缺点 优点: Mybatis实现了对Dao层的封装,隔离了SQL语句,便于管理,避免了像JDBC那样操作数据集,便于扩展等等。 缺点: Mybatis属于?半自动“ORM”,比Hibernate的工作做得要多很多&a…...
工商经营性网站备案/网站排名优化推广
现在华为主要是买不到手机的处理器芯片,所以理论上可以使用5G云计算的方式实现“云手机”,也就是将手机的计算功能放在远程服务器上,手机本身只作为联网和显示设备。这样一来即使手机没有处理器,也可以实现上网、打游戏等功能。其…...
如何在人力资源网站做合同续签/网站统计分析工具
在注重实效的途径中,为我们介绍了一些原则。 首先是重复的危害。其中有一句关键,系统中的每一项知识都必须具有单一,无歧义,权威的表示。——不要重复你自己。有些重复是强加的,比如说建立具有重复信息的文档ÿ…...