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

Redisson中红锁(RedLock)的实现

一、什么是红锁

当在单点redis中实现redis锁时,一旦redis服务器宕机,则无法进行锁操作。因此会考虑将redis配置为主从结 构,但在主从结构中,数据复制是异步实现的。假设在主从结构中,master会异步将数据复制到slave中,一旦某 个线程持有了锁,在还没有将数据复制到slave时,master宕机。则slave会被提升为master,但被提升为slave的 master中并没有之前线程的锁信息,那么其他线程则又可以重新加锁。

二、RedLock算法原理

redlock是一种基于多节点redis实现分布式锁的算法,可以有效解决redis单点故障的问题。官方建议搭建五台 redis服务器对redlock算法进行实现。

在redis官网中,对于redlock算法的实现思想也做了详细的介绍。

地址:https://redis.io/topics/distlock

整个实现过程分为五步:

  • 1)记录获取锁前的当前时间
  • 2)使用相同的key,value获取所有redis实例中的锁,并且设置获取锁的时间要远远小于锁自动释放的时间。假设 锁自动释放时间是10秒,则获取时间应在5-50毫秒之间。通过这种方式避免客户端长时间等待一个已经关闭的实 例,如果一个实例不可用了,则尝试获取下一个实例。
  • 3)客户端通过获取所有实例的锁后的时间减去第一步的时间,得到的差值要小于锁自动释放时间,避免拿到一个 已经过期的锁。并且要有超过半数的redis实例成功获取到锁,才算最终获取锁成功。如果不是超过半数,有可能 出现多个客户端重复获取到锁,导致锁失效。
  • 4)当已经获取到锁,那么它的真正失效时间应该为:过期时间-第三步的差值。
  • 5)如果客户端获取锁失败,则在所有redis实例中释放掉锁。为了保证更高效的获取锁,还可以设置重试策略,在 一定时间后重新尝试获取锁,但不能是无休止的,要设置重试次数。

三、RedLock用法示例

1)新建配置类

@Configuration
public class RedissonRedLockConfig {public RedissonRedLock initRedissonClient(String lockKey){Config config1 = new Config();config1.useSingleServer().setAddress("redis://192.168.200.150:7000").setDatabase(0);RedissonClient redissonClient1 = Redisson.create(config1);Config config2 = new Config();config2.useSingleServer().setAddress("redis://192.168.200.150:7001").setDatabase(0);RedissonClient redissonClient2 = Redisson.create(config2);Config config3 = new Config();config3.useSingleServer().setAddress("redis://192.168.200.150:7002").setDatabase(0);RedissonClient redissonClient3 = Redisson.create(config3);Config config4 = new Config();config4.useSingleServer().setAddress("redis://192.168.200.150:7003").setDatabase(0);RedissonClient redissonClient4 = Redisson.create(config4);Config config5 = new Config();config5.useSingleServer().setAddress("redis://192.168.200.150:7004").setDatabase(0);RedissonClient redissonClient5 = Redisson.create(config5);RLock rLock1 = redissonClient1.getLock(lockKey);RLock rLock2 = redissonClient2.getLock(lockKey);RLock rLock3 = redissonClient3.getLock(lockKey);RLock rLock4 = redissonClient4.getLock(lockKey);RLock rLock5 = redissonClient5.getLock(lockKey);RedissonRedLock redissonRedLock = new RedissonRedLock(rLock1,rLock2,rLock3,rLock4,rLock5);return redissonRedLock;}
}

2)新建测试类,完成加锁与解锁操作

@SpringBootTest
@RunWith(SpringRunner.class)
public class RedLockTest {@Autowiredprivate RedissonRedLockConfig redissonRedLockConfig;@Testpublic void easyLock(){//模拟多个10个客户端for (int i=0;i<10;i++) {Thread thread = new Thread(new RedLockTest.RedLockRunnable());thread.start();}try {System.in.read();} catch (IOException e) {e.printStackTrace();}}private class RedLockRunnable implements Runnable {@Overridepublic void run() {RedissonRedLock redissonRedLock = redissonRedLockConfig.initRedissonClient("demo");try {boolean lockResult = redissonRedLock.tryLock(100, 10, TimeUnit.SECONDS);if (lockResult){System.out.println("获取锁成功");TimeUnit.SECONDS.sleep(3);}} catch (InterruptedException e) {e.printStackTrace();}finally {redissonRedLock.unlock();System.out.println("释放锁");}}}
}

redissonRedLock加锁源码分析

public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {long newLeaseTime = -1;if (leaseTime != -1) {newLeaseTime = unit.toMillis(waitTime)*2;}long time = System.currentTimeMillis();long remainTime = -1;if (waitTime != -1) {remainTime = unit.toMillis(waitTime);}long lockWaitTime = calcLockWaitTime(remainTime);/*** 1. 允许加锁失败节点个数限制(N-(N/2+1)),当前假设五个节点,则允许失败节点数为2*/int failedLocksLimit = failedLocksLimit();/*** 2. 遍历所有节点执行lua加锁,用于保证原子性*/List<RLock> acquiredLocks = new ArrayList<>(locks.size());for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext();) {RLock lock = iterator.next();boolean lockAcquired;/***  3.对节点尝试加锁*/try {if (waitTime == -1 && leaseTime == -1) {lockAcquired = lock.tryLock();} else {long awaitTime = Math.min(lockWaitTime, remainTime);lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS);}} catch (RedisResponseTimeoutException e) {// 如果抛出这类异常,为了防止加锁成功,但是响应失败,需要解锁所有节点unlockInner(Arrays.asList(lock));lockAcquired = false;} catch (Exception e) {// 抛出异常表示获取锁失败lockAcquired = false;}if (lockAcquired) {/***4. 如果获取到锁则添加到已获取锁集合中*/acquiredLocks.add(lock);} else {/*** 5. 计算已经申请锁失败的节点是否已经到达 允许加锁失败节点个数限制 (N-(N/2+1))* 如果已经到达, 就认定最终申请锁失败,则没有必要继续从后面的节点申请了* 因为 Redlock 算法要求至少N/2+1 个节点都加锁成功,才算最终的锁申请成功*/if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {break;}if (failedLocksLimit == 0) {unlockInner(acquiredLocks);if (waitTime == -1 && leaseTime == -1) {return false;}failedLocksLimit = failedLocksLimit();acquiredLocks.clear();// reset iteratorwhile (iterator.hasPrevious()) {iterator.previous();}} else {failedLocksLimit--;}}/*** 6.计算从各个节点获取锁已经消耗的总时间,如果已经等于最大等待时间,则申请锁失败,返回false*/if (remainTime != -1) {remainTime -= System.currentTimeMillis() - time;time = System.currentTimeMillis();if (remainTime <= 0) {unlockInner(acquiredLocks);return false;}}}if (leaseTime != -1) {List<RFuture<Boolean>> futures = new ArrayList<>(acquiredLocks.size());for (RLock rLock : acquiredLocks) {RFuture<Boolean> future = ((RedissonLock) rLock).expireAsync(unit.toMillis(leaseTime), TimeUnit.MILLISECONDS);futures.add(future);}for (RFuture<Boolean> rFuture : futures) {rFuture.syncUninterruptibly();}}/*** 7.如果逻辑正常执行完则认为最终申请锁成功,返回true*/return true;
}

相关文章:

Redisson中红锁(RedLock)的实现

一、什么是红锁 当在单点redis中实现redis锁时&#xff0c;一旦redis服务器宕机&#xff0c;则无法进行锁操作。因此会考虑将redis配置为主从结 构&#xff0c;但在主从结构中&#xff0c;数据复制是异步实现的。假设在主从结构中&#xff0c;master会异步将数据复制到slave中…...

小结:路由器和交换机的指令对比

路由器和交换机的指令有一定的相似性&#xff0c;但也有明显的区别。以下是两者指令的对比和主要差异&#xff1a; 相似之处 基本操作 两者都支持类似的基本管理命令&#xff0c;比如&#xff1a; 进入系统视图&#xff1a;system-view查看当前配置&#xff1a;display current…...

使用yarn命令创建Vue3项目

文章目录 1.技术栈2.创建流程2.1创建vue3项目2.2选择配置项2.3进入项目目录 3.使用Yarn启动项目3.1安装依赖3.2运行项目 1.技术栈 yarnvitevue3 2.创建流程 2.1创建vue3项目 vue create 项目名称2.2选择配置项 直接回车可选择Vue3 2.3进入项目目录 cd 项目名称默认在当前…...

Three.js+Vue3+Vite应用lil-GUI调试开发3D效果(三)

前期文章中我们完成了创建第一个场景、添加轨道控制器的功能&#xff0c;接下来我们继续阐述其他的功能&#xff0c;本篇文章中主要讲述如何应用lil-GUI调试开发3D效果&#xff0c;在开始具体流程和步骤之前&#xff0c;请先查看之前的内容&#xff0c;因为该功能必须在前期内容…...

K8S集群常用命令

1&#xff0c;查看pod kubectl get pods -A 查看所有的pod kubectl get pods 这个只查看namespace为default下的pod&#xff0c;也就是只查看默认命名空间下的pod kubectl get pod -A -o wide 查看所有的pod&#xff0c;并且放出的信息更全&#xff08;包含了pod的ip&#xff0…...

【优先算法】滑动窗口--(结合例题讲解解题思路)(C++)

目录 1. 例题1&#xff1a;最大连续1的个数 1.1 解题思路 1.2代码实现 1.3 错误示范如下&#xff1a;我最开始写了一种&#xff0c;但是解答错误&#xff0c;请看&#xff0c;给大家做个参考 2. 将 x 减到 0 的最小操作数 2.1解题思路 2.2代码实现 1. 例题1&#xff…...

mayavi -> python 3D可视化工具Mayavi的安装

前言 Mayavi是一个基于VTK&#xff08;Visualization Toolkit&#xff09;的科学计算和可视化工具&#xff0c;主要用于数据可视化和科学计算领域。 它提供了一系列的高级可视化工具&#xff0c;包括2D和3D图形、表面和体积渲染、流场可视化等。Mayavi可以通过Python脚本进行调…...

【C++】B2112 石头剪子布

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述游戏规则&#xff1a;输入格式&#xff1a;输出格式&#xff1a;输入输出样例&#xff1a;解题分析与实现 &#x1f4af;我的做法实现逻辑优点与不足 &#x1f4af…...

【Vue】vue3 video 保存视频进度,每次进入加载上次的视频进度

使用 localStorage 存储每个视频的播放进度在组件加载时恢复上次的播放进度在视频播放过程中实时保存进度在组件卸载前保存最终进度使用 timeupdate 事件来监听视频播放进度的变化 在模板中为视频元素添加事件监听&#xff1a; <videoloopautoplaycontrols:id"video_…...

C# 25Dpoint

C# 25Dpoint &#xff0c;做一个备份 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;namespace _25Dpoint {public partial cl…...

如何制作一个高质量的 Dockerfile 镜像:从入门到实践

Docker 是一种轻量级的容器化技术&#xff0c;能够将应用程序及其依赖打包到一个可移植的容器中。Dockerfile 是构建 Docker 镜像的核心文件&#xff0c;它定义了镜像的构建步骤和配置。通过编写 Dockerfile&#xff0c;我们可以自动化地构建镜像&#xff0c;确保应用程序在不同…...

Linux 机器学习

Linux 机器学习是指在 Linux 操作系统环境下进行机器学习相关的开发、训练和应用。 具体步骤 环境搭建&#xff1a; 选择合适的 Linux 发行版&#xff1a;如 Ubuntu、Fedora、Arch Linux 等。Ubuntu 因其易用性和丰富的软件包管理系统&#xff0c;适合初学者&#xff1b;Fed…...

青少年编程与数学 02-006 前端开发框架VUE 25课题、UI数据

青少年编程与数学 02-006 前端开发框架VUE 25课题、UI数据 一、UI数据二、Element Plus处理响应式数据三、Vuetify处理响应式数据 课题摘要:本文探讨了UI数据在用户界面中的重要性和处理方法。UI数据包括展示数据、用户输入、状态数据等&#xff0c;对用户体验和应用交互性有直…...

css实现响应式详解

一、媒体查询&#xff08;Media Queries&#xff09; 基本概念 媒体查询是 CSS3 中用于根据不同的设备特性&#xff08;如屏幕宽度、高度、设备类型等&#xff09;应用不同样式规则的技术。它允许你为特定的媒体类型&#xff08;如屏幕、打印、手持设备等&#xff09;和条件&a…...

python-应用自动化操作方法集合

python-PC应用自动化操作 pywinauto&#xff1a;适合Windows系统的软件&#xff08;GUI&#xff09;&#xff0c;通过遍历窗口&#xff08;对话框&#xff09;和窗口里的UI控件进行定位操作&#xff0c;也可以控制鼠标和键盘输入等 https://geekdaxue.co/read/pywinauto-doc-zh…...

mac地址是用来做什么的

MAC 地址&#xff08;Media Access Control Address&#xff09;是一个唯一的硬件地址&#xff0c;用于在网络中标识设备。每个网络接口卡&#xff08;NIC&#xff09;都有一个唯一的 MAC 地址。MAC 地址是数据链路层&#xff08;OSI模型的第二层&#xff09;使用的地址&#x…...

【Compose multiplatform教程】05 IOS环境编译

了解如何使现有的 Android 应用程序跨平台&#xff0c;以便它在 Android 和 iOS 上都能运行。您将能够在一个位置编写代码并针对 Android 和 iOS 进行测试一次。 本教程使用一个示例 Android 应用程序&#xff0c;其中包含用于输入用户名和密码的单个屏幕。凭证经过验证并保存…...

3D滤波器处理遥感tif图像

import cv2 import numpy as np from osgeo import gdal# 定义 Gabor 滤波器的参数 kSize 31 # 滤波器核的大小 g_sigma 3.0 # 高斯包络的标准差 g_theta np.pi / 4 # Gabor 函数的方向 g_lambda 10.0 # 正弦波的波长 g_gamma 0.5 # 空间纵横比 g_psi np.pi / 2 # …...

fisco bcosV3 Table智能合约开发

环境 &#xff1a; fisco bcos 3.11.0 webase-front : 3.1.1 console 3.8.0 table合约【3.2.0版本后的】 前言 最近在做毕设&#xff0c;数据的存储方式考虑使用fisco-bcos的table表存储&#xff0c;经过这几天的研究&#xff0c;发现对于fisco2和 fisco3版本的table表合约功能…...

leetcode刷题记录(四十八)——128. 最长连续序列

&#xff08;一&#xff09;问题描述 128. 最长连续序列 - 力扣&#xff08;LeetCode&#xff09;128. 最长连续序列 - 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。请你设计并实现时间复…...

HTML中如何保留字符串的空白符和换行符号的效果

有个字符串 储值门店{{thing3.DATA}}\n储值卡号{{character_string1.DATA}}\n储值金额{{amount4.DATA}}\n当前余额{{amount5.DATA}}\n储值时间{{time2.DATA}} &#xff0c; HTML中想要保留 \n的换行效果的有下面3种方法&#xff1a; 1、style 中 设置 white-space: pre-lin…...

Linux入门——环境基础开发(上)

Linux 软件包管理器 yum 什么是软件包 在Linux操作系统中&#xff0c;安装软件的方式通常较为复杂&#xff0c;其基本流程涉及下载程序源代码并通过编译得到可执行程序。然而&#xff0c;这种方法需要开发者具备一定的编程知识和环境配置能力&#xff0c;对于许多用户而言&am…...

c++类和对象---下

文章目录 一、类的静态成员 1.1.静态成员变量&#xff1a;所有对象共享的成员变量。 1.2.静态成员函数&#xff1a;可以访问静态成员变量&#xff0c;但不能访问非静态成员变量。 二、类的继承 2.1.继承&#xff1a;子类继承父类的成员变量和成员函数。 2.2.多态&#xff1a;基…...

组件中的Props

在项目开发中,在开发某些界面时,我们可以将一些代码封装成组件来简化代码。但是,如果某些情况下组件中的某些属性不是一成不变的(比如一个头像+姓名的组件,每次使用时都需要改变其图像src和姓名字符串),我们就可以使用Props。 我们要使用Props,我们需要先在组件中声明…...

并行服务、远程SSH无法下载conda,报错404

原下载代码无效&#xff0c;报错404 wget -c https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh 使用下面代码下载 wget --user-agent"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12…...

迅为RK3568开发板篇OpenHarmony配置HDF驱动控制LED-新增 topeet子系统-编写 bundle.json文件

bundle.json 文件内容如下所示&#xff1a; 下面是对各个字段的解释&#xff1a; 1. name: "ohos/demos" - 这是组件或项目的名称&#xff0c;这里表示它属于 OHOS&#xff08;OpenHarmony OS&#xff09;生态系统下的一个名为"demos"的组件。 2. descri…...

深度剖析RabbitMQ:从基础组件到管理页面详解

文章目录 一、简介二、Overview2.1 Overview->Totals2.2 Overview->Nodesbroker的属性2.3 Overview->Churn statistics2.4 Overview->Ports and contexts2.5 Overview->Export definitions2.6 Overview->Import definitions 三、Connections连接的属性 四、C…...

usb通过hdc连接鸿蒙next的常用指令

参考官方 注册报名https://www.hiascend.com/developer/activities/details/44de441ef599450596131c8cb52f7f8c/signup?channelCodeS1&recommended496144 hdc-调试命令-调测调优-系统 - 华为HarmonyOS开发者https://developer.huawei.com/consumer/cn/doc/harmonyos-guid…...

【落羽的落羽 C语言篇】文件操作

文章目录 一、文件的概念和分类1. 概念和分类2. 文件名3. 数据文件 三、文件操作1. 文件的打开和关闭1.1 流1.2 文件指针1.3 文件的打开和关闭 2. 文件的顺序读写3. 文件的随机读写4. 文件读取的判定5. 文件缓冲区 一、文件的概念和分类 1. 概念和分类 文件是用来保存数据的。…...

RNN之:LSTM 长短期记忆模型-结构-理论详解-及实战(Matlab向)

0.前言 递归&#xff01;循环神经网络Recurrent Neural Network 循环神经网络&#xff08;又称递归神经网络&#xff0c;Recurrent Neural Network&#xff0c;RNN&#xff09;。是一种用于处理序列数据的神经网络结构&#xff0c;具有记忆功能&#xff0c;能够捕捉序列中的时…...