Redis 分布式锁与 Redlock 算法实现
Redis 分布式锁与 Redlock 算法实现
- 一、简介
- 1. Redis的分布式锁
- 2. 分布式锁的实现原理
- 二、Redis 分布式锁使用场景
- 1. 分布式系统中数据资源的互斥访问
- 2. 分布式环境中多个节点之间的协作
- 3. 常见场景及应用
- 三、Redlock算法的原理与实现
- 1. Redlock算法的背景
- 2. Redlock算法的原理
- 3. Redlock算法的缺陷
- 四、Redis Redlock算法的应用
- 1. 实现分布式锁
- 2. 保证锁的可重入性
- 3. 避免死锁
- 五、Redlock算法的优化措施
- 1. 客户端标识
- 2. 指定多个Redis节点
- 3. 加入时钟偏移量
一、简介
1. Redis的分布式锁
Redis是一款基于内存的高性能键值对数据库,通过提供多种数据类型支持,满足了大部分的应用场景,常用的数据类型有字符串、哈希表、列表、集合和有序集合等。在Redis中,可以使用多种方式实现分布式锁,如使用SETNX命令或RedLock算法。
2. 分布式锁的实现原理
分布式锁的实现主要依靠分布式协调服务,如Zookeeper、Etcd和Consul等,实现多个进程之间通过共享资源进行资源访问的协同工作。
二、Redis 分布式锁使用场景
1. 分布式系统中数据资源的互斥访问
当多个进程需要同时访问共享资源时,需要通过加锁机制保证在同一时间只有一个进程能够访问资源,从而避免了竞态条件。
2. 分布式环境中多个节点之间的协作
在分布式环境中,不同的节点可能需要进行协调工作,如分配任务、执行任务等,通过加锁机制保证每个节点领取任务后都能够成功执行任务。
3. 常见场景及应用
订单系统、秒杀系统、分布式任务调度等。
以下是一个使用Java语言实现的Redis分布式锁示例:
import redis.clients.jedis.Jedis;public class RedisDistributedLock {// Redis客户端private Jedis jedis;// 锁的路径private String lockKey;// 锁的持有者private String lockHolder;// 锁的过期时间(单位:毫秒)private int expireTime;// 循环获取锁的时间间隔(单位:毫秒)private int acquireInterval;// 获取锁的最大等待时间(单位:毫秒)private int acquireTimeout;/*** 构造函数* @param jedis Redis客户端* @param lockKey 锁的路径* @param expireTime 锁的过期时间(单位:毫秒)* @param acquireInterval 循环获取锁的时间间隔(单位:毫秒)* @param acquireTimeout 获取锁的最大等待时间(单位:毫秒)*/public RedisDistributedLock(Jedis jedis, String lockKey, int expireTime, int acquireInterval, int acquireTimeout) {this.jedis = jedis;this.lockKey = lockKey;this.expireTime = expireTime;this.acquireInterval = acquireInterval;this.acquireTimeout = acquireTimeout;this.lockHolder = null;}/*** 获取锁* @return 是否获取成功*/public boolean acquire() {// 获取当前时间戳long now = System.currentTimeMillis();// 计算获取锁的最后截止时间long acquireDeadline = now + acquireTimeout;// 循环尝试获取锁while (System.currentTimeMillis() < acquireDeadline) {// 生成随机的锁持有者IDString holder = Long.toString(now) + "|" + Thread.currentThread().getId();// 将锁持有者ID设置到锁的值中,如果设置成功则表示获取锁成功if (jedis.set(lockKey, holder, "NX", "PX", expireTime) != null) {this.lockHolder = holder;return true;}// 如果获取锁失败,则等待一段时间后再次尝试获取try {Thread.sleep(acquireInterval);} catch (InterruptedException e) {e.printStackTrace();}}return false;}/*** 释放锁* @return 是否释放成功*/public boolean release() {// 判断当前锁是否是该线程持有的,如果不是则不能释放if (this.lockHolder != null && this.lockHolder.equals(jedis.get(lockKey))) {jedis.del(lockKey);return true;}return false;}
}
三、Redlock算法的原理与实现
1. Redlock算法的背景
在分布式系统中经常要用到分布式锁,以保证某些操作的原子性,同时避免多个节点同时操作同一个资源。然而传统的分布式锁存在多种问题,例如死锁、宕机等,激发了人们寻求更加安全可靠的分布式锁算法。
2. Redlock算法的原理
Redlock是一个由Redis的创始人开发的分布式锁算法,其思想基于Paxos算法。Redlock算法的流程如下:
- 客户端获取当前时间戳t1。
- 客户端依次向N个Redis节点请求锁,每个请求的锁过期时间为t1+TTL(time to live)。
- 如果客户端在大多数节点上都获得了锁,则客户端获得了锁。
- 如果客户端在少数节点上未能获得锁,则客户端将在所有已获得锁的节点上释放已经获得的锁。
- 如果客户端在所有节点上都未能获得锁,则重复步骤1。
其中N为Redis节点数量,TTL指过期时间。
3. Redlock算法的缺陷
Redlock算法并不完美,存在以下缺陷:
- 时间同步的问题:如果Redis节点系统时间发生偏移,可能会导致锁竞争的严重性问题。
- 网络分区问题:如果出现了网络分区情况,则可能导致多个客户端同时获取了锁,而无法做到原子性。
四、Redis Redlock算法的应用
1. 实现分布式锁
在分布式系统中,实现分布式锁是一项非常关键的任务。基于Redlock算法可以很容易地实现分布式锁。下面是java代码实现过程:
public class RedisDistributedLock {private static final long DEFAULT_EXPIRY_TIME = 30000;private static final int DEFAULT_RETRIES = 3;private static final long DEFAULT_RETRY_TIME = 500;private final JedisPool jedisPool;public RedisDistributedLock(JedisPool jedisPool) {this.jedisPool = jedisPool;}/*** 获取分布式锁* @param lockKey 锁key* @param clientId 客户端标识* @return 是否获取到锁*/public boolean acquire(String lockKey, String clientId) {return acquire(lockKey, clientId, DEFAULT_EXPIRY_TIME, DEFAULT_RETRIES, DEFAULT_RETRY_TIME);}/*** 获取分布式锁* @param lockKey 锁key* @param clientId 客户端标识* @param expiryTime 锁超时时间,单位毫秒* @param retryTimes 尝试获取锁的次数* @param retryInterval 每次尝试获取锁的间隔时间,单位毫秒* @return 是否获取到锁*/public boolean acquire(String lockKey, String clientId, long expiryTime, int retryTimes, long retryInterval) {try (Jedis jedis = jedisPool.getResource()) {int count = 0;while (count++ < retryTimes) {// 生成随机字符串作为value,保证每个客户端的锁值是唯一的String lockValue = UUID.randomUUID().toString();// 尝试获取锁,成功返回1,失败返回0String result = jedis.set(lockKey, lockValue, "NX", "PX", expiryTime);if ("OK".equals(result)) {// 将锁标识与客户端匹配,便于解锁时判断锁是否属于当前客户端jedis.hset("lockClientIdMap", lockKey, clientId);return true;}try {Thread.sleep(retryInterval);} catch (InterruptedException e) {Thread.currentThread().interrupt();return false;}}}return false;}/*** 释放分布式锁* @param lockKey 锁key* @param clientId 客户端标识* @return 是否成功释放锁*/public boolean release(String lockKey, String clientId) {try (Jedis jedis = jedisPool.getResource()) {// 获取锁标识对应的客户端标识,判断锁是否属于当前客户端String storedClientId = jedis.hget("lockClientIdMap", lockKey);if (clientId.equals(storedClientId)) {// 删除锁keyjedis.del(lockKey);// 删除锁标识对应的客户端标识jedis.hdel("lockClientIdMap", lockKey);return true;}}return false;}}
2. 保证锁的可重入性
为了保证锁的可重入性,可以在Redis中存储一个计数器,用于记录当前客户端已获取锁的次数。在释放锁时,判断计数器是否为0,如果不为0,则表示锁仍是当前客户端持有的。
3. 避免死锁
为了避免死锁,需要严格控制锁超时时间和尝试获取锁的次数。在获取锁失败后,需要等待一段时间再尝试获取,避免出现大量客户端同时请求获取锁的情况。
五、Redlock算法的优化措施
1. 客户端标识
在分布式锁的实现中,加入客户端标识可以避免一个客户端误解锁其他客户端持有的锁。
2. 指定多个Redis节点
为了提高系统的可用性,可以指定多个Redis节点,当一个Redis节点出现故障时,系统可以切换到其他可用的节点继续工作。
3. 加入时钟偏移量
为了避免时钟不同步导致的锁失效问题,可以加入时钟偏移量,即在获取锁时获取多个Redis节点的时间,并取其最小值作为锁的过期时间。这样可以保证所有节点使用的是同一个时间作为锁的过期时间,从而避免时钟不同步导致的问题。
相关文章:
Redis 分布式锁与 Redlock 算法实现
Redis 分布式锁与 Redlock 算法实现 一、简介1. Redis的分布式锁2. 分布式锁的实现原理 二、Redis 分布式锁使用场景1. 分布式系统中数据资源的互斥访问2. 分布式环境中多个节点之间的协作3. 常见场景及应用 三、Redlock算法的原理与实现1. Redlock算法的背景2. Redlock算法的原…...

【附安装包】Inventor2024安装教程 机械制图|三维制图
软件下载 软件:Inventor版本:2024语言:简体中文大小:5.61G安装环境:Win11/Win10/Win8/Win7硬件要求:CPU2.5GHz 内存8G(或更高)下载通道①百度网盘丨64位下载链接:https://pan.baidu…...

c++ 判断基类指针指向的真实对象类型
在 c 面向对象使用中,我们常常会定义一个基类类型的指针,在运行过程中,这个指针可能指向一个基类类型的对象,也可能指向的是其子类类型的对象,那现在问题来了,我们如何去判断这个指针到底执行了一个什么类型…...

退出屏保前玩一把游戏吧!webBrowser中网页如何调用.NET方法
本文主要以 HackerScreenSaver 新功能的开发经历介绍 webBrowser中网页如何调用.NET方法的过程。 1. 背景 之前开源了一款名为 HackerScreenSaver 的 Windows 屏保程序。该程序具有模拟黑客炫酷界面的特点,用户可以将自定义的网页作为锁屏界面。不久前,…...

hive-列转行
转成 select customer_code,product_type from temp.temp_xx LATERAL VIEW explode(SPLIT(product_types,,)) table_tmp AS product_type where customer_code K100515182...

【网络】IP网络层和数据链路层
IP协议详解 1.概念 1.1 四层模型 应用层:解决如何传输数据(依照什么格式/协议处理数据)的问题传输层:解决可靠性问题网络层:数据往哪里传,怎么找到目标主机数据链路层(物理层)&…...

基于Spring Gateway路由判断器实现各种灰度发布场景
文章目录 1、灰度发布实现1.1 按随机用户的流量百分比实现灰度1.2 按人群划分实现的灰度1.2.1 通过Header信息实现灰度1.2.2 通过Query信息实现灰度1.2.3 通过RemoteAdd判断来源IP实现灰度 2、路由判断器2.1. After2.2. Before2.3. Between2.4. Cookie2.5. Header2.6. Host2.7.…...

mysql57、mysql80 目录结构 之 Windows
查看mysql 数据存储的位置 /bin:存储可执行文件,主要包含客户端和服务端启动程序,如mysql.exe、mysqld.exe等 /docs:存放一些文档 /include:用于放置一些头文件,如:mysql.h、mysqld_error.h 等 …...

Mac操作系统Safari 17全新升级:秋季推出全部特性
苹果的内置浏览器可能是Mac上最常用的应用程序(是的,甚至比Finder、超级Mac Geeks还要多)。因此,苹果总是为其浏览器Safari添加有用的新功能。在今年秋天与macOS Sonoma一起推出的第17版中,Safari可以帮助你提高工作效…...

UDP通信、本地套接字
#include <sys/types.h> #include <sys/socket > ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);- 参数:- sockfd : 通信的fd- buf : 要发送的数据- len : 发送数据的长度…...

ChatGPT提示与技巧分享:如何作出更好的提示2023年8月
对ChatGPT的一些酷炫技巧感兴趣吗?这里提供了一些可以帮助你充分利用ChatGPT,成为AI工具专家的技巧。 毫无疑问,ChatGPT是目前最广泛使用的人工智能工具之一。它不仅毫不留情地取代了一些特定领域常用的软件小工具(如智能对联、经典语录生…...

网络安全(自学黑客)一文全解
目录 特别声明:(文末附资料笔记工具) 一、前言 二、定义 三、分类 1.白帽黑客(White Hat Hacker) 2.黑帽黑客(Black Hat Hacker) 3.灰帽黑客(Gray Hat Hacker) 四…...

Vue中ElementUI结合transform使用时,发现弹框定位不准确问题
在近期开发中,需要将1920*1080放到更大像素大屏上演示,所以需要使用到transform来对页面进行缩放,但是此时发现弹框定位出错问题,无法准备定位到实际位置。 查看element-ui官方文档无果后,打算更换新的框架进行开发&am…...
(一)连续随机量的生成-基于分布函数
连续随机量的生成-基于分布函数 1. 概率积分变换方法(分布函数)2. Python编程实现指数分布的采样 1. 概率积分变换方法(分布函数) Consider drawing a random quantity X X X from a continuous probability distribution with …...

【springboot】Spring Cache缓存:
文章目录 一、导入Maven依赖:二、实现思路:三、代码开发: 一、导入Maven依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><…...
数学建模-建模算法(4)
python虽然不是完全为数学建模而生的,但是它完整的库让它越来越适合建模了。 - 线性规划:使用scipy.optimize.linprog()函数 python from scipy.optimize import linprogc [-1, 4] A [[-3, 1], [1, 2]] b [6, 4] x0_bounds (None, None) x1_bound…...
python之函数返回数据框
1.原始文件 ##gff-version 3 Chr1A IWGSC_v2.1 gene 40098 70338 33 - . IDTraesCS1A03G0000200;previous_idTraesCS1A02G000100;primconfHC;NameTraesCS1A03G0000200;cdsCDS_OK;mappingfullMatchWithMissmatches Chr1A IWGSC_v2.1 mRN…...
电子商务安全体系架构技术方面
技术方面是本文所要阐述的主要方面,因为它能够依靠企业自 身的努力来达到令人满意的安全保障效果。目前,关于电子商务安全体系的研究比 较多,有基于层次的体系,也有基于对象的体系,还有基于风险管理的体系࿰…...
新安装IDEA 常用插件、设置
新安装IDEA 常用插件、设置 mybatiscodeHelperProRestfulToolkit-fixJrebelmybatis log freepojo to jsonGrep ConsoleMaven HelperCamelCaseCamelCase常用设置 mybatiscodeHelperPro mapper.xml 编码校验 sql 生成,代码生成 RestfulToolkit-fix URI 跳转到对应的…...

ChromeOS 的 Linux 操作系统和 Chrome 浏览器分离
导读科技媒体 Ars Technica 报道称,谷歌正在将 ChromeOS 的浏览器从操作系统中分离出来 —— 让它变得更像 Linux。虽然目前还没有任何官方消息,但这项变化可能会在本月的版本更新中推出。 据介绍,谷歌将该项目命名为 "Lacros"——…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...