分布式中间件:基于 Redis 实现分布式锁

news2025/3/23 9:14:30

分布式中间件:基于 Redis 实现分布式锁

一、背景引入

在当今的互联网应用中,分布式系统变得越来越常见。在分布式环境下,多个服务实例可能会同时对共享资源进行读写操作,这就很容易引发数据不一致等问题。比如电商系统中的库存扣减,如果多个订单处理服务同时对同一商品的库存进行操作,就可能导致超卖现象。为了解决这类问题,分布式锁应运而生。分布式锁能够保证在分布式系统中,同一时刻只有一个服务实例可以对共享资源进行操作,从而确保数据的一致性和完整性。

Redis 作为一款高性能的开源内存数据库,具有丰富的数据结构和原子操作特性,成为了实现分布式锁的理想选择。接下来,我们将深入探讨如何基于 Redis 实现分布式锁。

二、Redis 实现分布式锁的原理

(一)基本原理

Redis 实现分布式锁主要是利用了其原子性操作。Redis 提供了 SET 命令,该命令可以原子性地设置一个键值对,并且可以同时设置过期时间。当多个客户端同时尝试获取锁时,只有一个客户端能够成功设置该键值对,从而获得锁。

(二)具体命令

使用 SET key value NX PX timeout 命令,其中:

  • key:表示锁的名称,通常是一个具有业务含义的字符串,例如 product:1:lock 表示对商品 ID 为 1 的资源加锁。
  • value:可以是一个唯一的标识,用于区分不同的客户端,防止误解锁。例如,可以使用 UUID 作为 value。
  • NX:表示只有当键不存在时才进行设置操作,如果键已经存在,则设置失败,这保证了同一时刻只有一个客户端能获得锁。
  • PX timeout:设置键的过期时间,单位为毫秒。这是为了防止持有锁的客户端出现异常(如崩溃)而导致锁无法释放,造成死锁。

三、代码实现

(一)Java 代码示例

import redis.clients.jedis.Jedis;
import java.util.UUID;

public class RedisDistributedLock {
    private static final String LOCK_KEY = "my_distributed_lock";
    private static final int LOCK_EXPIRE_TIME = 5000; // 锁的过期时间,单位:毫秒
    private Jedis jedis;

    public RedisDistributedLock() {
        this.jedis = new Jedis("localhost", 6379);
    }

    public String acquireLock() {
        String requestId = UUID.randomUUID().toString();
        String result = jedis.set(LOCK_KEY, requestId, "NX", "PX", LOCK_EXPIRE_TIME);
        if ("OK".equals(result)) {
            return requestId;
        }
        return null;
    }

    public boolean releaseLock(String requestId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, 1, LOCK_KEY, requestId);
        return "1".equals(result.toString());
    }

    public void close() {
        jedis.close();
    }
}

(二)代码解释

  • acquireLock 方法:生成一个唯一的 requestId,然后使用 SET 命令尝试获取锁。如果返回 OK,表示成功获取锁,返回该 requestId;否则返回 null
  • releaseLock 方法:使用 Lua 脚本确保释放锁的操作是原子性的。首先检查当前锁的 value 是否与传入的 requestId 相等,如果相等则删除该键,释放锁,并返回 1;否则返回 0。
  • close 方法:关闭 Redis 连接。

(三)使用示例

public class Main {
    public static void main(String[] args) {
        RedisDistributedLock lock = new RedisDistributedLock();
        String requestId = lock.acquireLock();
        if (requestId != null) {
            try {
                System.out.println("成功获取锁,开始执行临界区代码");
                // 模拟临界区代码执行
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.releaseLock(requestId);
                System.out.println("成功释放锁");
            }
        } else {
            System.out.println("获取锁失败");
        }
        lock.close();
    }
}

四、Redis 分布式锁的优缺点

(一)优点

  1. 高性能:Redis 是基于内存的数据库,读写速度非常快,能够满足高并发场景下的锁操作需求。
  2. 原子操作:Redis 提供了原子操作,如 SET 命令和 Lua 脚本,保证了锁的获取和释放操作的原子性,避免了并发问题。
  3. 可扩展性:Redis 可以通过集群或主从复制等方式实现高可用性和可扩展性,满足大规模分布式系统的需求。

(二)缺点

  1. 单点故障:如果 Redis 节点出现故障,可能会导致锁服务不可用。虽然可以通过集群或主从复制来解决,但仍然存在一定的风险。
  2. 时钟漂移:Redis 的锁超时机制依赖于系统时钟,如果不同节点的时钟存在漂移,可能会导致锁提前或延迟释放。
  3. 锁释放问题:如果客户端在持有锁期间崩溃,锁可能无法正常释放,需要依赖锁超时机制来解决。

五、应用场景

  1. 分布式系统中的数据一致性:在多个服务同时访问和修改共享数据时,使用分布式锁可以保证数据的一致性。例如,多个订单处理服务对同一商品的库存进行操作时,使用分布式锁可以避免超卖现象。
  2. 任务调度:在分布式任务调度系统中,使用分布式锁可以保证同一个任务在同一时间只被一个节点执行。例如,定时清理缓存的任务,避免多个节点同时执行导致数据不一致。
  3. 资源限流:在多个客户端同时访问有限资源时,使用分布式锁可以限制同一时间的访问数量。例如,限制同一时间对某个接口的并发访问数量。

六、总结

基于 Redis 实现分布式锁是一种简单、高效的解决方案,能够满足大多数分布式系统的需求。通过合理设置锁的过期时间和使用原子操作,可以保证锁的正确性和可靠性。但同时也需要注意 Redis 的单点故障、时钟漂移等问题,在实际应用中需要根据具体场景进行优化和改进。希望本文能帮助你更好地理解和应用基于 Redis 的分布式锁。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【设计模式】三十二、策略模式

系列文章|源码 https://github.com/tyronczt/design-mode-learn 文章目录 系列文章|源码一、模式定义与核心思想二、模式结构与Java实现1. 核心角色2. Java代码示例 三、策略模式的五大核心优势四、适用场景五、与其他模式的对比六、最佳实践建议总结 🚀进阶版【更…

Cyberchef实用功能之-json line格式文件美化和查询

本文将介绍一下如何使用cyberchef对json line格式数据进行美化方便阅读,以及json line格式数据的批量查询操作。 之前的文章介绍了json格式数据的美化和查询,即Cyberchef实用功能之-json解析美化和转换,Cyberchef实用功能之-批量提取json数据…

计算机基础:编码03,根据十进制数,求其原码

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏,故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 (一)WIn32 专栏导航 上一篇:计算机基础:编码02,有符号数编码&#xf…

FaryGui文字shader修改,弧线排列

因项目要求,希望将文字进行标题那样的弧线排列,如下图: 对FaryGUI的文字Shader进行了一些修改,基本达到要求,shader设置如下: shader代码如下: // Upgrade NOTE: replaced _Object2World with unity_ObjectToWorld // Upgrade NOTE: replaced mul(UNITY_MATRIX_MVP,*) with Un…

C++ string的模拟实现

Hello!!大家早上中午晚上好,昨天复习了string的使用,今天来模拟实现一下string!!! 一、string的框架搭建 1.1首先我们需要一个string的头文件用来做变量、函数、类等声明;再需要一个test文件来做测试,还需…

使用LangChain实现基于LLM和RAG的PDF问答系统

目录 前言一.大语言模型(LLM)1. 什么是LLM?2. LLM 的能力与特点 二、增强检索生成(RAG)三. 什么是 LangChain?1. LangChain 的核心功能2. LangChain 的优势3. LangChain 的应用场景4. 总结 四.使用 LangChain 实现基于 PDF 的问答系统 前言 本文将介绍 …

C++实现rabbitmq生产者消费者

RabbitMQ是一个开源的消息队列系统,它实现了高级消息队列协议(AMQP), 特点 可靠性:通过持久化、镜像队列等机制保证消息不丢失,确保消息可靠传递。灵活的路由:提供多种路由方式,如…

在VMware上部署【Ubuntu】

镜像下载 国内各镜像站点均可下载Ubuntu镜像,下面例举清华网站 清华镜像站点:清华大学开源软件镜像站 | Tsinghua Open Source Mirror 具体下载步骤如下: 创建虚拟机 准备:在其他空间大的盘中创建存储虚拟机的目录&#xff0c…

又双叒叕Scrapy爬虫相关的面试题及详细解答

Scrapy是Python开发的一个快速、高层次的网络爬虫框架,专注于高效抓取网页并提取结构化数据。其核心设计基于异步处理机制,适合大规模数据采集任务。 文章目录 基础概念1. Scrapy框架的核心组件有哪些?架构与流程2. 描述Scrapy的工作流程核心组件详解3. 如何自定义Item Pipe…

使用STM32CubeMX+DMA+空闲中断实现串口接收和发送数据(STM32G070CBT6)

1.STM32CubeMX配置 (1)配置SYS (2)配置RCC (3)配置串口,此处我用的是串口4,其他串口也是一样的 (4)配置DMA,将串口4的TX和RX添加到DMA中 &#…

【视觉提示学习】3.21论文随想

. . Frontiers of Information Technology & Electronic Engineering. 2024, 25(1): 42-63 https://doi.org/10.1631/FITEE.2300389 中文综述,根据里面的架构,把视觉提示学习分成两类,一类是单模态提示学习(以vit为代表&…

(一)丶Windows安装RabbitMQ可能会遇到的问题

一丶可能会忘了配置ERLang的环境变量 二丶执行命令时报错 第一步 rabbitmq-plugins enable rabbitmq_management 第二部 rabbitmqctl status 三丶修改.erlang.cookie 文件 1.找到C盘目下的.erlang.cookie文件 C:\Users\admin\.erlang.cookie C:\Windows\System32\config\sys…

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、核心特性与优势 多…

springboot整合mybatis-plus【详细版】

目录 一,简介 1. 什么是mybatis-plus2.mybatis-plus特点 二,搭建基本环境 1. 导入基本依赖:2. 编写配置文件3. 创建实体类4. 编写controller层5. 编写service接口6. 编写service层7. 编写mapper层 三,基本知识介绍 1. 基本注解 T…

Qt之MVC架构MVD

什么是MVC架构: MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controll…

深度解析学术论文成果评估(Artifact Evaluation):从历史到现状

深度解析学术论文成果评估(Artifact Evaluation):从历史到现状 引言 在计算机科学和工程领域的学术研究中,可重复性和可验证性越来越受到重视。随着实验性研究的复杂性不断增加,确保研究成果可以被其他研究者验证和构建变得尤为重要。这一需…

二分查找上下界问题的思考

背景 最近在做力扣hot100中的二分查找题目时,发现很多题目都用到了二分查找的变种问题,即二分查找上下界问题,例如以下题目: 35. 搜索插入位置 74. 搜索二维矩阵 34. 在排序数组中查找元素的第一个和最后一个位置 它们不同于查找…

关于FastAPI框架的面试题及答案解析

FastAPl是一个现代、快速(高性能)的Web框架,用于构建API,基于Python3.7+的类型提示功能。它由Python开发者SebastianRamirez创建,并且使用了Starlette作为其核心组件以及Pydantic进行数据验证。 文章目录 基础篇1. FastAPI的核心优势是什么?2. 如何定义一个GET请求路由?…

HashMap添加元素的流程图

文章目录 JDK7 vs JDK8 的 HashMap 结构变化Java8 中哈希表的红黑树优化机制HashMap 添加元素的完整流程解析1. 计算 key 的哈希值并确定索引2. 检查该索引位置是否已有元素3. 处理哈希冲突4. 判断当前存储结构(链表还是红黑树)5. 判断链表长度是否超过 …

面向医药仓储场景下的药品分拣控制策略方法 研究(大纲)

面向医药仓储场景下的药品分拣控制策略方法研究 基于多机器人协同与智能调度的分拣系统设计 第一章 绪论 1.1 研究背景与意义 医药仓储自动化需求: 人工分拣效率低、出错率高(如药品批次混淆、过期风险)温控药品(如疫苗、生物制…