02_redis分布式锁原理

news2025/5/27 18:10:14

文章目录

    • 一、redis如何实现分布式锁
      • 1. 使用 SETNX 命令
      • 2. 设置过期时间
      • 3. 释放锁
      • 4. 注意事项
      • 5. 示例代码
    • 二、Java中分布式锁如何设置超时时间
      • 1. Redis分布式锁
      • 2. 基于Zookeeper的分布式锁
      • 3. 基于数据库的分布式锁
      • 注意事项

一、redis如何实现分布式锁

Redis 实现分布式锁是一种常见且高效的方式。以下是关于 Redis 实现分布式锁的一些关键点和步骤:

1. 使用 SETNX 命令

Redis 提供了一个非常方便的命令 SETNX(SET if Not eXists),它可以在指定的 key 不存在时,为 key 设置一个值。这个命令天然地适合用作分布式锁的占位符。

  • 命令格式SETNX key value
  • 返回值:如果 key 不存在,设置 key 的值为 value,返回 1。如果 key 已存在,不做任何操作,返回 0。

2. 设置过期时间

为了防止由于异常情况导致锁无法释放,我们通常需要给锁设置一个过期时间。这可以通过 EXPIRE 命令来实现,或者更优雅地使用 SET 命令的扩展参数。

  • 命令格式EXPIRE key secondsSET key value EX seconds(后者同时设置值和过期时间)

3. 释放锁

释放锁的操作相对简单,只需要删除对应的 key 即可。但是,这里需要注意一个细节:只有当锁的持有者(即设置锁的进程)才能释放锁。因此,在删除锁之前,我们需要检查锁的值是否匹配。

  • 命令格式DEL keyLUA 脚本(为了确保原子性,通常使用 LUA 脚本来检查并删除锁)

4. 注意事项

  • 时钟漂移:在分布式系统中,不同机器的时钟可能存在漂移。因此,设置过期时间时需要考虑这一点,避免由于时钟漂移导致的锁提前释放或过期未释放。
  • 可重入性:如果同一个进程需要多次获取同一个锁,那么锁应该是可重入的。Redis 本身不支持可重入锁,但可以通过在应用层实现一个计数器来解决这个问题。
  • 锁续期:为了避免锁因为操作时间过长而过期,可以在持有锁期间定期续期。这同样需要通过 LUA 脚本来确保原子性。
  • 死锁检测:虽然 Redis 分布式锁本身不会直接导致死锁(因为有过期时间),但应用层仍然需要处理可能出现的死锁情况。例如,可以设置一个监控线程来检测长时间未释放的锁,并进行相应的处理。

5. 示例代码

以下是一个简单的使用 Redis 实现分布式锁的 Java 示例代码(基于 Jedis 库):

import redis.clients.jedis.Jedis;

public class RedisDistributedLock {

    private Jedis jedis;
    private String lockKey;
    private String lockValue;
    private int expireTime;

    public RedisDistributedLock(Jedis jedis, String lockKey, String lockValue, int expireTime) {
        this.jedis = jedis;
        this.lockKey = lockKey;
        this.lockValue = lockValue;
        this.expireTime = expireTime;
    }

    public boolean tryLock() {
        String result = jedis.set(lockKey, lockValue, "NX", "EX", expireTime);
        return "OK".equals(result);
    }

    public void unlock() {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "return redis.call('del', KEYS[1]) " +
                        "else " +
                        "return 0 " +
                        "end";
        jedis.eval(script, 1, lockKey, lockValue);
    }
}

在这个示例中,tryLock 方法尝试获取锁,如果成功则返回 true,否则返回 falseunlock 方法使用 LUA 脚本来确保只有锁的持有者才能释放锁。

二、Java中分布式锁如何设置超时时间

在Java中实现分布式锁时,设置超时时间是非常重要的,因为它可以防止锁被永远持有(例如,由于客户端崩溃或网络问题导致的锁无法释放)。不同的分布式锁实现方式可能有不同的方法来设置超时时间。以下是一些常见的分布式锁实现及其超时时间设置方法:

1. Redis分布式锁

当使用Redis实现分布式锁时,通常会使用SET命令结合NX(仅当键不存在时设置)和PX(设置键的过期时间,以毫秒为单位)选项来确保原子性和超时控制。

String lockKey = "myLock";
String lockValue = UUID.randomUUID().toString(); // 使用唯一值作为锁的值,以便后续释放锁时验证
int lockExpireTime = 5000; // 锁的超时时间,单位为毫秒

Jedis jedis = new Jedis("localhost");
try {
    String result = jedis.set(lockKey, lockValue, "NX", "PX", lockExpireTime);
    if ("OK".equals(result)) {
        // 成功获取锁,执行临界区代码
    } else {
        // 获取锁失败,可能已经被其他客户端持有
    }
} finally {
    jedis.close();
}

在这个例子中,PX 5000设置了锁的超时时间为5000毫秒(5秒)。

2. 基于Zookeeper的分布式锁

Zookeeper也常用于实现分布式锁。在使用Zookeeper时,可以通过创建临时有序节点来实现锁的功能,并设置节点的超时时间(即会话超时)。

CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
try {
    InterProcessMutex lock = new InterProcessMutex(client, "/my_lock");
    try {
        if (lock.acquire(5, TimeUnit.SECONDS)) { // 设置超时时间为5秒
            try {
                // 成功获取锁,执行临界区代码
            } finally {
                lock.release();
            }
        } else {
            // 获取锁失败
        }
    } catch (Exception e) {
        // 处理异常
    }
} finally {
    client.close();
}

在这个例子中,lock.acquire(5, TimeUnit.SECONDS)设置了尝试获取锁的超时时间为5秒。

3. 基于数据库的分布式锁

虽然不太常见,但也可以使用数据库来实现分布式锁。通常,这涉及到在数据库中创建一个锁表,并通过SQL语句来检查、设置和释放锁。超时时间可以通过在数据库中设置锁的过期时间来实现。

注意事项

  • 超时时间的设置:超时时间应该足够长,以确保在正常情况下能够完成任务,但也不能太长,以避免锁被长时间持有而浪费资源。
  • 锁的释放:在释放锁时,需要确保只有持有锁的客户端才能释放锁(例如,通过比较锁的值)。
  • 异常处理:在获取锁和释放锁的过程中,需要妥善处理异常,以避免由于异常导致锁无法被正确释放。
  • 分布式环境的复杂性:在分布式环境中,由于网络延迟、节点故障等原因,实现可靠的分布式锁可能比较复杂。因此,在选择分布式锁实现时,需要仔细考虑其可靠性和性能。

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

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

相关文章

简单血条于小怪攻击模板

创建一个2d正方形(9-Sliced)命名为Player,在Player下面新建一个画布(Canvas)命名为PlayerHealthUI,在画布下面新建一个滑动条(Slider)命名为HealthBar 把PlayerHealthUI脚本挂载到Pl…

代码随想录算法训练营第四十六四十七天

卡码网题目: 110. 字符串接龙105. 有向图的完全联通106. 岛屿的周长107. 寻找存在的路径 其他: 今日总结 往期打卡 110. 字符串接龙 跳转: 110. 字符串接龙 学习: 代码随想录公开讲解 问题: 字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序…

华硕FL8000U加装16G+32G=48G内存条

华硕FL8000U加装16G32G48G内存条 一、华硕FL8000U加装内存条endl 一、华硕FL8000U加装内存条 相关视频链接: https://www.bilibili.com/video/BV1gw4dePED8/ endl

勇闯Chromium—— Chromium的多进程架构

问题 构建一个永不崩溃或挂起的渲染引擎几乎是不可能的,构建一个绝对安全的渲染引擎也几乎是不可能的。 从某种程度上来说,2006 年左右的网络浏览器状态与过去单用户、协作式多任务操作系统的状况类似。正如在这样的操作系统中,一个行为不端的应用程序可能导致整个系统崩溃…

软件质量保证与测试实验

课程  软件质量保证与测试 目的&#xff1a;练习软件测试中白盒测试方法 内容&#xff1a; 测试如下程序段&#xff1a; #include <stdio.h>int main() {int i 1, n1 0, n2 0;float sum 0.0;float average;float score[100];printf("请输入分…

历年华东师范大学保研上机真题

2025华东师范大学保研上机真题 2024华东师范大学保研上机真题 2023华东师范大学保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/school?classification1 简单一位数代数式计算 题目描述 给一个小学生都会算的1位数与1位数运算的代数式&#xff0c;请你求出这个表…

在机器学习中,L2正则化为什么能够缓过拟合?为何正则化等机制能够使一个“过度拟合训练集”的模型展现出更优的泛化性能?正则化

在现代机器学习的发展历程中&#xff0c;过拟合&#xff08;Overfitting&#xff09;始终是亟需克服的重要挑战。其表现如同在训练数据上构建过度复杂的映射函数&#xff0c;虽能实现近乎完美的拟合&#xff0c;但其泛化能力却显著受限&#xff0c;导致模型在测试集或实际应用中…

k8s部署ELK补充篇:kubernetes-event-exporter收集Kubernetes集群中的事件

k8s部署ELK补充篇&#xff1a;kubernetes-event-exporter收集Kubernetes集群中的事件 文章目录 k8s部署ELK补充篇&#xff1a;kubernetes-event-exporter收集Kubernetes集群中的事件一、kubernetes-event-exporter简介二、kubernetes-event-exporter实战部署1. 创建Namespace&a…

C++性能相关的部分内容

C性能相关的部分内容 与底层硬件紧密结合 大端存储和小端存储&#xff08;硬件概念&#xff09; C在不同硬件上运行的结果可能不同 比如&#xff1a;输入01234567&#xff0c;对于大端存储的硬件会先在较大地址上先进行存储&#xff0c;而对于小端存储的硬件会先在较小地址上…

AI进行提问、改写、生图、联网搜索资料,嘎嘎方便!

极客侧边栏-AI板块 目前插件内已接入DeepSeek-R1满血版、Qwen3满血版 、豆包/智谱最新发布的推理模型以及各种顶尖AI大模型&#xff0c;并且目前全都可以免费不限次数使用&#xff0c;秒回不卡顿&#xff0c;联网效果超好&#xff01; 相比于市面上很多AI产品&#xff0c;极客…

GStreamer开发笔记(四):ubuntu搭建GStreamer基础开发环境以及基础Demo

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/147714800 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、O…

2021年认证杯SPSSPRO杯数学建模A题(第二阶段)医学图像的配准全过程文档及程序

2021年认证杯SPSSPRO杯数学建模 A题 医学图像的配准 原题再现&#xff1a; 图像的配准是图像处理领域中的一个典型问题和技术难点&#xff0c;其目的在于比较或融合同一对象在不同条件下获取的图像。例如为了更好地综合多种信息来辨识不同组织或病变&#xff0c;医生可能使用…

CV中常用Backbone-3:Clip/SAM原理以及代码操作

前面已经介绍了简单的视觉编码器&#xff0c;这里主要介绍多模态中使用比较多的两种backbone&#xff1a;1、Clip&#xff1b;2、SAM。对于这两个backbone简单介绍基本原理&#xff0c;主要是讨论使用这个backbone。 1、CV中常用Backbone-2&#xff1a;ConvNeXt模型详解 2、CV中…

RPC 协议详解、案例分析与应用场景

一、RPC 协议原理详解 RPC 协议的核心目标是让开发者像调用本地函数一样调用远程服务&#xff0c;其实现过程涉及多个关键组件与流程。 &#xff08;一&#xff09;核心组件 客户端&#xff08;Client&#xff09;&#xff1a;发起远程过程调用的一方&#xff0c;它并不关心调…

dify-plugin-daemon的.env配置文件

源码位置&#xff1a;dify-plugin-daemon\.env 本文使用dify-plugin-daemon v0.1.0版本&#xff0c;主要总结了dify-plugin-daemon\.env配置文件。为了本地调试方便&#xff0c;采用本地运行时环境WSL2Ubuntu22.04方式运行dify-plugin-daemon服务。 一.服务器基本配置 服务器…

(九)PMSM驱动控制学习---无感控制之高阶滑膜观测器

在之前的文章中&#xff0c;我们介绍了永磁同步电机无感控制中的滑模观测器&#xff0c;但是同时我们也认识到了他的缺点&#xff1a;因符号函数带来的高频切换分量&#xff0c;使用低通滤波器引发相位延迟&#xff1b;在本篇文章&#xff0c;我们将会介绍高阶滑模观测器的无感…

Devicenet主转Profinet网关助力改造焊接机器人系统智能升级

某汽车零部件焊接车间原有6台焊接机器人&#xff08;采用Devicenet协议&#xff09;需与新增的西门子S7-1200 PLC&#xff08;Profinet协议&#xff09;组网。若更换所有机器人控制器或上位机系统&#xff0c;成本过高且停产周期长。 《解决方案》 工程师选择稳联技术转换网关…

《STL--list的使用及其底层实现》

引言&#xff1a; 上次我们学习了容器vector的使用及其底层实现&#xff0c;今天我们再来学习一个容器list&#xff0c; 这里的list可以参考我们之前实现的单链表&#xff0c;但是这里的list是双向循环带头链表&#xff0c;下面我们就开始list的学习了。 一&#xff1a;list的…

python的pip怎么配置的国内镜像

以下是配置pip国内镜像源的详细方法&#xff1a; 常用国内镜像源列表 清华大学&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple阿里云&#xff1a;https://mirrors.aliyun.com/pypi/simple中科大&#xff1a;https://pypi.mirrors.ustc.edu.cn/simple华为云&#xff1…

PCB 通孔是电容性的,但不一定是电容器

哼&#xff1f;……这是什么意思&#xff1f;…… 多年来&#xff0c;流行的观点是 PCB 通孔本质上是电容性的&#xff0c;因此可以用集总电容器进行建模。虽然当信号的上升时间大于或等于过孔不连续性延迟的 3 倍时&#xff0c;这可能是正确的&#xff0c;但我将向您展示为什…