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

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算法的流程如下:

  1. 客户端获取当前时间戳t1。
  2. 客户端依次向N个Redis节点请求锁,每个请求的锁过期时间为t1+TTL(time to live)。
  3. 如果客户端在大多数节点上都获得了锁,则客户端获得了锁。
  4. 如果客户端在少数节点上未能获得锁,则客户端将在所有已获得锁的节点上释放已经获得的锁。
  5. 如果客户端在所有节点上都未能获得锁,则重复步骤1。

其中N为Redis节点数量,TTL指过期时间。

3. Redlock算法的缺陷

Redlock算法并不完美,存在以下缺陷:

  1. 时间同步的问题:如果Redis节点系统时间发生偏移,可能会导致锁竞争的严重性问题。
  2. 网络分区问题:如果出现了网络分区情况,则可能导致多个客户端同时获取了锁,而无法做到原子性。

四、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安装教程 机械制图|三维制图

软件下载 软件&#xff1a;Inventor版本&#xff1a;2024语言&#xff1a;简体中文大小&#xff1a;5.61G安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.5GHz 内存8G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pan.baidu…...

c++ 判断基类指针指向的真实对象类型

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

退出屏保前玩一把游戏吧!webBrowser中网页如何调用.NET方法

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

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 四层模型 应用层&#xff1a;解决如何传输数据&#xff08;依照什么格式/协议处理数据&#xff09;的问题传输层&#xff1a;解决可靠性问题网络层&#xff1a;数据往哪里传&#xff0c;怎么找到目标主机数据链路层&#xff08;物理层&#xff09;&…...

基于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&#xff1a;存储可执行文件&#xff0c;主要包含客户端和服务端启动程序&#xff0c;如mysql.exe、mysqld.exe等 /docs&#xff1a;存放一些文档 /include&#xff1a;用于放置一些头文件&#xff0c;如&#xff1a;mysql.h、mysqld_error.h 等 …...

Mac操作系统Safari 17全新升级:秋季推出全部特性

苹果的内置浏览器可能是Mac上最常用的应用程序&#xff08;是的&#xff0c;甚至比Finder、超级Mac Geeks还要多&#xff09;。因此&#xff0c;苹果总是为其浏览器Safari添加有用的新功能。在今年秋天与macOS Sonoma一起推出的第17版中&#xff0c;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);- 参数&#xff1a;- sockfd : 通信的fd- buf : 要发送的数据- len : 发送数据的长度…...

ChatGPT提示与技巧分享:如何作出更好的提示2023年8月

​对ChatGPT的一些酷炫技巧感兴趣吗?这里提供了一些可以帮助你充分利用ChatGPT&#xff0c;成为AI工具专家的技巧。 毫无疑问&#xff0c;ChatGPT是目前最广泛使用的人工智能工具之一。它不仅毫不留情地取代了一些特定领域常用的软件小工具&#xff08;如智能对联、经典语录生…...

网络安全(自学黑客)一文全解

目录 特别声明&#xff1a;&#xff08;文末附资料笔记工具&#xff09; 一、前言 二、定义 三、分类 1.白帽黑客&#xff08;White Hat Hacker&#xff09; 2.黑帽黑客&#xff08;Black Hat Hacker&#xff09; 3.灰帽黑客&#xff08;Gray Hat Hacker&#xff09; 四…...

Vue中ElementUI结合transform使用时,发现弹框定位不准确问题

在近期开发中&#xff0c;需要将1920*1080放到更大像素大屏上演示&#xff0c;所以需要使用到transform来对页面进行缩放&#xff0c;但是此时发现弹框定位出错问题&#xff0c;无法准备定位到实际位置。 查看element-ui官方文档无果后&#xff0c;打算更换新的框架进行开发&am…...

(一)连续随机量的生成-基于分布函数

连续随机量的生成-基于分布函数 1. 概率积分变换方法&#xff08;分布函数&#xff09;2. Python编程实现指数分布的采样 1. 概率积分变换方法&#xff08;分布函数&#xff09; Consider drawing a random quantity X X X from a continuous probability distribution with …...

【springboot】Spring Cache缓存:

文章目录 一、导入Maven依赖&#xff1a;二、实现思路&#xff1a;三、代码开发&#xff1a; 一、导入Maven依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><…...

数学建模-建模算法(4)

python虽然不是完全为数学建模而生的&#xff0c;但是它完整的库让它越来越适合建模了。 - 线性规划&#xff1a;使用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…...

电子商务安全体系架构技术方面

技术方面是本文所要阐述的主要方面&#xff0c;因为它能够依靠企业自 身的努力来达到令人满意的安全保障效果。目前&#xff0c;关于电子商务安全体系的研究比 较多&#xff0c;有基于层次的体系&#xff0c;也有基于对象的体系&#xff0c;还有基于风险管理的体系&#xff0…...

新安装IDEA 常用插件、设置

新安装IDEA 常用插件、设置 mybatiscodeHelperProRestfulToolkit-fixJrebelmybatis log freepojo to jsonGrep ConsoleMaven HelperCamelCaseCamelCase常用设置 mybatiscodeHelperPro mapper.xml 编码校验 sql 生成&#xff0c;代码生成 RestfulToolkit-fix URI 跳转到对应的…...

ChromeOS 的 Linux 操作系统和 Chrome 浏览器分离

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

UniAppX项目数据可视化升级:用lime-echart + ECharts打造高性能图表(从Vue2/Vue3到uni-app-x全流程)

UniAppX高性能数据可视化实战&#xff1a;lime-echart与ECharts的深度整合指南 当移动端数据可视化需求遭遇性能瓶颈时&#xff0c;UniAppX框架与lime-echart的组合正在成为技术决策者的新选择。本文将揭示如何在不同技术栈中实现图表渲染性能的突破性提升&#xff0c;从原理剖…...

ZephyrOS--实战Bluetooth LE心率监测

1. 从零开始搭建ZephyrOS开发环境 第一次接触ZephyrOS时&#xff0c;我花了整整两天时间才把开发环境搭好。现在回想起来&#xff0c;其实只要掌握几个关键步骤就能避开那些坑。这里我以nRF52开发板为例&#xff0c;带你快速搭建起心率监测项目的开发环境。 首先需要安装Zephyr…...

Spring Boot Helper插件免费版获取与版本适配全攻略

1. 为什么我们需要Spring Boot Helper插件 作为一个常年使用IntelliJ IDEA开发Spring Boot项目的程序员&#xff0c;我深刻体会到这个插件的重要性。简单来说&#xff0c;它就像是Spring Boot开发的"瑞士军刀"&#xff0c;能帮我们快速创建项目、自动配置依赖、一键…...

2026年03月26日全球AI前沿动态

一句话总结全球AI领域密集发布技术、产品、企业动态&#xff0c;覆盖通用/垂直大模型、专项技术、智能体、机器人、硬件基建等全赛道&#xff0c;中国AI在视频、音乐、办公智能体领域领跑&#xff0c;OpenAI关停Sora战略转型&#xff0c;Arm、苹果、腾讯等大厂新品落地&#xf…...

【读书笔记】《逆风跑者》

《逆风跑者》| 长跑人的阿甘正传 如果你也曾困顿过&#xff0c;迷茫过&#xff0c;被生活压得喘不过气来&#xff0c;那么就拉过一把椅子静静地坐一会儿吧。听我说说这位无声跑者的事儿&#xff0c;和他一起不屈不挠地寂静奔跑一次。 &#x1f4d6; 关于这本书 《逆风跑者》是…...

华为Matebook 13双系统实战:Win10与Ubuntu 16.04无缝共存指南

1. 为什么选择华为Matebook 13安装双系统 作为一名长期使用双系统开发的工程师&#xff0c;我最近在华为Matebook 13上成功部署了Win10Ubuntu 16.04双系统组合。这款13英寸的轻薄本确实给了我不少惊喜——2K全面屏、1.3kg超轻机身、第八代i5处理器&#xff0c;这些硬件配置对于…...

UniApp多主题开发避坑指南:为什么SCSS+Require比Vuex方案更优雅?

UniApp多主题开发实战&#xff1a;SCSS动态加载方案深度解析与性能优化 在移动应用开发领域&#xff0c;主题切换功能已成为提升用户体验的重要环节。UniApp作为跨平台开发框架&#xff0c;如何实现高效、灵活的主题管理一直是开发者关注的焦点。本文将深入探讨基于SCSS变量与动…...

MySQL视图实战:用SQL视图搞定学生奖学金评定与补考名单(附完整代码)

MySQL视图实战&#xff1a;用SQL视图搞定学生奖学金评定与补考名单&#xff08;附完整代码&#xff09; 教务管理系统中&#xff0c;数据处理效率直接影响决策质量。想象一下每学期末&#xff0c;教务处老师需要从数十万条记录中筛选奖学金候选人和补考名单——传统的手写SQL查…...

FastAdmin+PHPStudy保姆级安装教程:从下载到配置数据库的完整流程

FastAdminPHPStudy极速开发环境搭建实战指南 作为一名长期使用FastAdmin框架的开发者&#xff0c;我深知一个顺畅的本地开发环境对项目效率的影响。本文将带你从零开始&#xff0c;用最简洁的方式完成FastAdmin与PHPStudy的完美搭配&#xff0c;避开那些新手常踩的"坑&quo…...

zotero-style:提升文献管理效率的3个核心方案

zotero-style&#xff1a;提升文献管理效率的3个核心方案 【免费下载链接】zotero-style zotero-style - 一个 Zotero 插件&#xff0c;提供了一系列功能来增强 Zotero 的用户体验&#xff0c;如阅读进度可视化和标签管理&#xff0c;适合研究人员和学者。 项目地址: https:/…...