深入解析 Redis 实现分布式锁的最佳实践

前言

在分布式系统中,多个进程或线程可能会同时访问同一个共享资源,这就可能导致数据不一致的问题。为了保证数据的一致性,我们通常需要使用分布式锁。Redis 作为高性能的内存数据库,提供了一种简单高效的方式来实现分布式锁。本文将深入探讨如何使用 Redis 来实现分布式锁,并介绍一些优化技巧和最佳实践。

 

 

---

 

一、为什么需要分布式锁?

 

在单机环境下,我们可以使用 synchronized、Lock 等方式来控制并发访问。但在分布式系统中,多个服务可能同时操作数据库或缓存,传统的线程锁无法跨多个实例工作,这时候就需要用分布式锁来保证资源的互斥访问。

 

应用场景包括:

 

防止并发订单超卖

 

控制定时任务的并发执行

 

限制用户重复提交请求

 

 

 

---

 

二、使用 Redis 实现分布式锁

 

1. 基础实现

 

最简单的方式是使用 Redis 的 SETNX 命令(SET if Not eXists)。

 

SETNX lock_key value

 

但是,仅使用 SETNX 存在问题:

 

如果程序崩溃,锁可能不会释放

 

不能设置锁的自动过期时间

 

 

因此,我们需要改进实现方式:

 

SET lock_key value NX PX 5000 # 设置过期时间 5 秒

 

解释:

 

NX:只有 key 不存在时才创建

 

PX 5000:设置过期时间为 5000 毫秒(5 秒)

 

 

这样可以确保锁在进程意外退出时不会永远存在。

 

 

---

 

2. 释放锁

 

要释放锁,我们不能直接 DEL,因为如果锁过期后被其他线程重新获取,DEL 可能会误删新的锁。因此,正确的方式是使用 Lua 脚本:

 

if redis.call("GET", KEYS[1]) == ARGV[1] then

    return redis.call("DEL", KEYS[1])

else

    return 0

end

 

Python 代码示例(使用 redis-py):

 

import redis

 

client = redis.StrictRedis(host='localhost', port=6379, decode_responses=True)

lock_key = "lock:resource"

lock_value = "unique-id"

 

# 释放锁

lua_script = """

if redis.call("GET", KEYS[1]) == ARGV[1] then

    return redis.call("DEL", KEYS[1])

else

    return 0

end

"""

client.eval(lua_script, 1, lock_key, lock_value)

 

这样可以确保只有持有锁的进程才可以释放它。

 

 

---

 

三、改进方案:RedLock 算法

 

尽管 SETNX 结合过期时间能解决基本问题,但仍然存在网络分区等问题。因此,Redis 官方推荐 RedLock 算法:

 

核心思想:

 

1. 在多个独立的 Redis 实例上尝试加锁

 

 

2. 只有在大多数节点成功获取锁,才算加锁成功

 

 

3. 计算锁的有效时间,防止时间偏移影响锁的有效性

 

 

4. 释放锁时依次删除所有 Redis 实例上的锁

 

 

 

实现示例(Python):

 

from redis import Redis

from redis_lock import RedLock

 

lock = RedLock("resource_name", connection_list=[

    Redis(host='redis1.example.com', port=6379),

    Redis(host='redis2.example.com', port=6379),

    Redis(host='redis3.example.com', port=6379)

])

 

if lock.acquire():

    try:

        print("成功获取分布式锁")

        # 执行业务逻辑

    finally:

        lock.release()

else:

    print("获取锁失败")

 

RedLock 适用于高可靠性场景,但由于需要多个 Redis 节点,部署成本更高,适用于分布式集群环境。

 

 

---

 

四、总结

 

基础锁: 使用 SETNX + 过期时间

 

释放锁: 使用 Lua 脚本确保安全性

 

高可用方案: 采用 RedLock 算法提高可靠性

 

 

在实际项目中,选择适合的锁方案可以有效提高系统的稳定性和并发控制能力。希望本文能帮助你更好地理解 Redis 分布式锁的实现方式!

 

如果你有更好的想法,欢迎留言交流!

 

 

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

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

相关文章

数据库练习2

目录 1.向heros表中新增一列信息,添加一些约束,并尝试查询一些信息 2.课堂代码练习 插入语句 INSERT INTO 删除语句DELETE和TRUNCATE 更新语句UPDATE和replace 查询语句SELECT 条件查询 查询排序 聚合函数 分组查询 3.题目如下 一、单表查询 …

w266农产品直卖平台的设计与实现

🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…

2025新版懒人精灵零基础安装调试+lua基础+UI设计交互+常用方法封装+项目实战+项目打包安装板块-视频教程(初学者必修课)

2025新版懒人精灵零基础安装调试lua基础UI设计交互常用方法封装项目实战项目打包安装板块-视频教程(初学者必修课): 1.懒人精灵核心API基础和lua基础视频教程:https://www.bilibili.com/video/BV1Vm9kYJEfM/ 温馨提示:所有视频请用电脑浏览…

CCF-CSP认证 202206-2寻宝!大冒险!

题目描述 思路 有一张绿化图和藏宝图,其中绿化图很大(二维数组在限定的空间内无法存储),而藏宝图是绿化图中的一部分,对于绿化图和藏宝图,左下角的坐标为(0, 0),右上角的坐标是(L, L)、(S, S)&…

Qt下集成大华网络相机SDK示例开发

文章目录 前言一、下载并集成大华网络相机SDK二、示例实现功能三、示例完整代码四、下载链接总结 前言 近期在Qt环境下进行大华网络相机的使用,发现官网下载的SDK中提供的示例没有Qt的demo,通过学习其提供的MFC示例代码,我在这里也实现了一个…

[学习笔记] 部署Docker搭建靶场

前言 我们需要部署Docker来搭建靶场题目,他可以提供一个隔离的环境,方便在不同的机器上部署,接下来,我会记录我的操作过程,简单的部署一道题目 Docker安装 不推荐在物理机上部署,可能会遇到一些问题&…

网络华为HCIA+HCIP IPv6

目录 IPv4现状 IPv6基本报头 IPv6扩展报头 IPv6地址 IPv6地址缩写规范 ​编辑 IPv6地址分配 IPv6单播地址分配 IPv6单播地址接口标识 IPv6常见单播地址 - GUA (2 / 3 开头) IPv6常见单播地址 - ULA IPv6常见单播地址 - LLA IPv6组播地…

可视化动态表单动态表单界的天花板--Formily(阿里开源)

文章目录 1、Formily表单介绍2、安装依赖2.1、安装内核库2.2、 安装 UI 桥接库2.3、Formily 支持多种 UI 组件生态: 3、表单设计器3.1、核心理念3.2、安装3.3、示例源码 4、场景案例-登录注册4.1、Markup Schema 案例4.2、JSON Schema 案例4.3、纯 JSX 案例 1、Form…

C++::多态

目录 一.多态的概念 二.多态的定义及实现 二.1多态的构成条件 二.2虚函数 1.虚函数的写法 2.虚函数的重写/覆盖 3.协变 二.3析构函数的重写 二.4override和final关键字 ​编辑二.5重载/重写/隐藏的对比 三.多态的运行原理(一部分) 四.多态的常…

Mistral AI发布开源多模态模型Mistral Small 3.1:240亿参数实现超越GPT-4o Mini的性能

法国人工智能初创公司Mistral AI于2025年3月正式推出新一代开源模型Mistral Small 3.1 ,该模型凭借240亿参数的轻量级设计,在多项基准测试中表现优异,甚至超越了Google的Gemma 3和OpenAI的GPT-4o Mini等主流专有模型。 1、核心特性与优势 多…

从零开发数据可视化

一、可视化模版展示 二、知识及素材准备 div css 布局flex布局Less原生js jquery 的使用rem适配echarts基础 相关js、images、font百度网盘下载链接: 通过百度网盘分享的文件:素材1 链接: https://pan.baidu.com/s/1vmZHbhykcvfLzzQT5USr8w?pwdwjx9…

WSL git文件异常 所有文件均显示已修改

如图,文件中没有任何修改,但是都显示多了一个^M 原因:是因为在Windows系统中git clone的文件夹,在WSL中会显示冲突。 解决方案:删掉之前在windows下git clone的文件夹, 然后在WSL中重新git clone

基于STM32进行FFT滤波并计算插值DA输出

文章目录 一、前言背景二、项目构思1. 确定FFT点数、采样率、采样点数2. 双缓存设计 三、代码实现1. STM32CubeMX配置和HAL库初始化2. 核心代码 四、效果展示和后话五、项目联想与扩展1. 倍频2. 降频3. 插值3.1 线性插值3.2 样条插值 一、前言背景 STM32 对 AD 采样信号进行快…

ENSP学习day9

ACL访问控制列表实验 ACL(Access Control List,访问控制列表)是一种用于控制用户或系统对资源(如文件、文件夹、网络等)访问权限的机制。通过ACL,系统管理员可以定义哪些用户或系统可以访问特定资源&#x…

Ubuntu22.04通过DKMS包安装Intel WiFi系列适配器(网卡驱动)

下载驱动包 访问 backport-iwlwifi-dkmshttps://launchpad.net/ubuntu/source/backport-iwlwifi-dkms 网站,找到适用于Ubuntu 22.04的update版本(如backport-iwlwifi-dkms_xxxx_all.deb),下载至本地。 安装驱动 在下载目录中执行以…

c#难点整理2

1.对象池的使用 就是先定义一系列的对象&#xff0c;用一个&#xff0c;调一个。 public class ObjectPool<T> where T : new(){private Queue<T> pool; // 用于存储对象的队列private int maxSize; // 对象池的最大容量// 构造函数public ObjectPool(int maxSi…

音频录制小妙招-自制工具-借助浏览器录一段单声道16000采样率wav格式音频

先看效果 1、打开页面 2、点击开始录音&#xff0c;弹出权限提示&#xff0c;点击“仅这次访问时允许” 3、录完后&#xff0c;点击停止 4、文件自动下载到默认目录 上代码 js 部分 document.addEventListener(DOMContentLoaded, () > {const startBtn document.getEleme…

C++:背包问题习题

1. 货币系统 1371. 货币系统 - AcWing题库 给定 V 种货币&#xff08;单位&#xff1a;元&#xff09;&#xff0c;每种货币使用的次数不限。 不同种类的货币&#xff0c;面值可能是相同的。 现在&#xff0c;要你用这 V 种货币凑出 N 元钱&#xff0c;请问共有多少种不同的…

Python设计模式 - 适配器模式

定义 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它用于将一个类的接口转换为客户端所期待的另一个接口。 注&#xff1a;在适配器模式定义中所提及的接口是指广义的接口&#xff0c;它可以表示一个方法或者一组方法的集合。 结构 …