使用 Redis 实现分布式锁的基本思路

使用 Redis 实现分布式锁的基本思路

在分布式系统中,多个进程或服务可能会同时访问共享资源(如数据库、缓存、文件等),这可能会导致数据不一致并发冲突。Redis 由于其高性能单线程模型,是实现分布式锁的一个常见选择。本文将详细介绍使用 Redis 实现分布式锁的基本思路,包括 实现方式锁的释放可能存在的问题 以及 优化方案

1. 基本思路

Redis 是一个高性能的内存数据库,具有 单线程执行命令原子操作 的特点,因此可以用 SETNXSET if Not Exists)等命令实现分布式锁。实现思路如下:

  1. 加锁

    • 使用 SET key value NX PX timeout 原子命令,确保只有一个客户端能成功设置锁,并带有超时时间。
  2. 解锁

    • 只有加锁的客户端才能释放锁(防止误解锁)。
    • 采用 Lua 脚本保证检查锁值和删除锁的操作是原子的。
  3. 超时自动释放

    • 设置过期时间,防止进程异常退出导致死锁。
  4. 续租机制(可选)

    • 如果任务执行时间较长,可以使用 看门狗机制 续租。

2. 实现步骤

2.1 加锁

使用 SET key value NX PX timeout 让多个客户端竞争锁:

SET lock_key random_value NX PX 5000  # 5秒过期时间
解释:
  • lock_key:锁的唯一标识(如 "order:123:lock")。
  • random_value:每个客户端生成的唯一值,防止误删锁(UUID)。
  • NX:如果 key 不存在才设置(保证互斥性)。
  • PX 5000:超时 5000 毫秒,防止死锁。

2.2 解锁

释放锁时,必须保证:

  • 只有加锁的客户端能解锁
  • 删除锁的操作是原子的
实现方式

使用 Lua 脚本来确保“检查 + 删除”操作的原子性:

if redis.call("GET", KEYS[1]) == ARGV[1] thenreturn redis.call("DEL", KEYS[1])
elsereturn 0
end

Redis 命令:

EVAL "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end" 1 lock_key random_value

2.3 处理锁超时

锁自动释放

设置 PX timeout 使 Redis 过期删除 key,避免死锁。

锁续期(可选)

如果任务执行时间可能超过锁的超时时间,可以:

  • 手动续租

    • 任务完成前,每隔一段时间调用 PEXPIRE lock_key timeout 续租。
  • 看门狗机制

    • 客户端定期检查,如果还持有锁,就续租。
    • 如果客户端异常退出,Redis 仍会在超时时间到后自动删除锁。

2.4 多进程竞争锁

多个进程同时竞争锁时:

  1. 只有一个进程能成功获取锁。
  2. 失败的进程可以采用 自旋等待指数退避 方式重试:
    • 自旋锁:短时间频繁重试。
    • 指数退避:每次等待时间翻倍(加随机抖动),减少 Redis 压力。

3. 进阶优化

3.1 RedLock:分布式 Redis 集群锁

如果 Redis 运行在集群模式下,为了提高可用性,可以采用 RedLock 算法:

  • 多个 Redis 实例 上尝试获取锁(一般 5 个)。
  • 必须在大多数实例上成功加锁(如 3/5)。

3.2 可重入锁

默认情况下,Redis 分布式锁 不是可重入的(即同一客户端多次 SETNX 会失败)。
解决方案:

  • 使用 hash 存储 计数器,同一个客户端多次加锁时递增计数,释放锁时递减:
    HSET lock_key owner random_value
    HINCRBY lock_key counter 1
    

3.3 共享锁 / 读写锁

  • 共享锁(Read Lock):多个读进程可以同时持有锁(通常用 ZSET)。
  • 写锁(Write Lock):写操作必须独占。

4. 代码示例(Python 实现)

import redis
import uuid
import timeclass RedisLock:def __init__(self, redis_client, lock_key, timeout=5):self.redis = redis_clientself.lock_key = lock_keyself.value = str(uuid.uuid4())  # 生成唯一锁值self.timeout = timeout  # 过期时间(秒)def acquire(self):"""尝试获取锁"""return self.redis.set(self.lock_key, self.value, nx=True, ex=self.timeout)def release(self):"""释放锁,使用 Lua 脚本确保原子性"""lua_script = """if redis.call("GET", KEYS[1]) == ARGV[1] thenreturn redis.call("DEL", KEYS[1])elsereturn 0end"""return self.redis.eval(lua_script, 1, self.lock_key, self.value)# 示例使用
redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)lock = RedisLock(redis_client, "my_lock", timeout=5)
if lock.acquire():print("锁获取成功")time.sleep(3)  # 模拟任务lock.release()
else:print("锁获取失败")

5. 总结

需求方案
互斥性SET lock_key value NX PX timeout
可靠释放Lua 脚本 GET + DEL 原子操作
超时防死锁PX timeout 过期
续租机制PEXPIRE 或 看门狗
集群支持RedLock 算法
可重入性计数器 + HSET
共享锁ZSET 实现

Redis 分布式锁适用于高性能分布式系统,但也有缺点:

  • 需要严格管理超时和续租,避免误删锁。
  • RedLock 适用于 多 Redis 实例,但会增加复杂度。
  • 如果对可靠性要求极高,可以考虑 Zookeeper 分布式锁

你可以根据实际业务需求,选择合适的实现方式 🚀。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9254.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试经典150题——图

文章目录 1、岛屿数量1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、被围绕的区域2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、克隆图3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 4、除法求值4.1 题目链接4.2 题目描述4.3 解题代码4.4 解题思路 5、课…

Celery

https://www.bilibili.com/video/BV1RGDEY5ERB 架构 简单任务 执行 包结构 本示例: app 添加任务 获取结果 配置延时任务 任务配置 beat 提交定时任务

Spring事务和事务传播机制

一.事务简单介绍 事务是⼀组操作的集合,是⼀个不可分割的操作.事务会把所有的操作作为⼀个整体,⼀起向数据库提交或者是撤销操作请求.所以这组操作要么同时成功,要么同时失败。 二.Spring中的事物 1.编程式事务(手动写代码操作事务) 2.声明式事务(利用注解自动开启和提交事…

XSS 漏洞全面解析:原理、危害与防范

目录 前言​编辑 漏洞原理 XSS 漏洞的危害 检测 XSS 漏洞的方法 防范 XSS 漏洞的措施 前言 在网络安全的复杂版图中,XSS 漏洞,即跨站脚本攻击(Cross - Site Scripting),是一类极为普遍且威胁巨大的安全隐患。随着互…

本地Harbor仓库搭建流程

Harbor仓库搭建流程 本文主要介绍如何搭建harbor仓库,推送本地镜像供其他机器拉取构建服务 harbor文档:Harbor 文档 | 配置 Harbor YML 文件 - Harbor 中文 github下载离线安装包 Releases goharbor/harbor 这是harbor的GitHub下载地址&#xff0c…

K8S 快速实战

K8S 核心架构原理: 我们已经知道了 K8S 的核心功能:自动化运维管理多个容器化程序。那么 K8S 怎么做到的呢?这里,我们从宏观架构上来学习 K8S 的设计思想。首先看下图: K8S 是属于主从设备模型(Master-Slave 架构),即有 Master 节点负责核心的调度、管理和运维,Slave…

5分钟带你获取deepseek api并搭建简易问答应用

目录 1、获取api 2、获取base_url和chat_model 3、配置模型参数 方法一:终端中临时将加入 方法二:创建.env文件 4、 配置client 5、利用deepseek大模型实现简易问答 deepseek-v3是截止博文撰写之日,无论是国内还是国际上发布的大模型中…

ResNeSt: Split-Attention Networks 参考论文

参考文献 [1] Tensorflow Efficientnet. https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet. Accessed: 2020-03-04. 中文翻译:[1] TensorFlow EfficientNet. https://github.com/tensorflow/tpu/tree/master/models/official/efficien…

Ansible自动化运维实战--通过role远程部署nginx并配置(8/8)

文章目录 1、准备工作2、创建角色结构3、编写任务4、准备配置文件(金甲模板)5、编写变量6、编写处理程序7、编写剧本8、执行剧本Playbook9、验证-游览器访问每台主机的nginx页面 在 Ansible 中,使用角色(Role)来远程部…

马尔科夫模型和隐马尔科夫模型区别

我用一个天气预报和海藻湿度观测的比喻来解释,保证你秒懂! 1. 马尔可夫模型(Markov Model, MM) 特点:状态直接可见 场景:天气预报(晴天→雨天→阴天…)核心假设: 下一个…

decison tree 决策树

熵 信息增益 信息增益描述的是在分叉过程中获得的熵减,信息增益即熵减。 熵减可以用来决定什么时候停止分叉,当熵减很小的时候你只是在不必要的增加树的深度,并且冒着过拟合的风险 决策树训练(构建)过程 离散值特征处理:One-Hot…

Microsoft Visual Studio 2022 主题修改(补充)

Microsoft Visual Studio 2022 透明背景修改这方面已经有很多佬介绍过了,今天闲来无事就补充几点细节。 具体的修改可以参考:Microsoft Visual Studio 2022 透明背景修改(快捷方法)_material studio怎么把背景弄成透明-CSDN博客文…

Python实现U盘数据自动拷贝

功能:当电脑上有U盘插入时,自动复制U盘内的所有内容 主要特点: 1、使用PyQt5创建图形界面,但默认隐藏 2、通过CtrlAltU组合键可以显示/隐藏界面 3、自动添加到Windows启动项 4、监控USB设备插入 5、按修改时间排序复制文件 6、静…

[c语言日寄]越界访问:意外的死循环

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是…

数据分析系列--①RapidMiner软件安装

目录 一、软件下载及账号注册 1.软件下载 1.1 CSDN下载国内下载,国内镜像相对快,点击下载 1.2 官网软件下载地址:AI Studio 2025.0 ,服务器在国外相对较慢. 2.软件注册 2.1 点击 注册界面 开始注册,如图: 3.邮箱验证 二、软件安装 1. 新年文件夹,名字最好为英文名 2. 双…

新增文章功能

总说 过程参考黑马程序员SpringBoot3Vue3全套视频教程,springbootvue企业级全栈开发从基础、实战到面试一套通关_哔哩哔哩_bilibili 之前又偷懒几天。回老家没事干,玩也玩不好,一玩老是被家里人说。写代码吧还是,他们都看不懂&a…

LangGraph系列-1:用LangGraph构建简单聊天机器人

在快速发展的人工智能和大型语言模型(llm)世界中,开发人员不断寻求创建更灵活、更强大、更直观的人工智能代理的方法。 虽然LangChain已经改变了这个领域的游戏规则,允许创建复杂的链和代理,但对代理运行时的更复杂控制…

二叉树的最大深度(遍历思想+分解思想)

Problem: 104. 二叉树的最大深度 文章目录 题目描述思路复杂度Code 题目描述 思路 遍历思想(实则二叉树的先序遍历) 1.欲望求出最大的深度,先可以记录一个变量res,同时记录每次当前节点所在的层数depth 2.在递的过程中,每次递一层&#xff0…

QT+mysql+python 效果:

# This Python file uses the following encoding: utf-8 import sysfrom PySide6.QtWidgets import QApplication, QWidget,QMessageBox from PySide6.QtGui import QStandardItemModel, QStandardItem # 导入需要的类# Important: # 你需要通过以下指令把 form.ui转为ui…

WSL 安装cuDNN

WSL 安装cuDNN 参考文档:https://docs.nvidia.com/deeplearning/cudnn/installation/latest/linux.html#verifying-the-install-on-linux 1. 下载相应包 根据下方下载地址进入下载界面,并选择与自己电脑相对应的平台执行图中的命令 下载地址&#xff1…