Redis(66)Redis如何实现分布式锁?

作者:Victor356日期:2025/10/17

Redis 提供了多种方法来实现分布式锁,确保多个进程或机器能够协调地访问共享资源。以下是详细的实现步骤和代码示例。

1. 基于 SET 命令的分布式锁

获取锁

获取锁的核心是使用 SET 命令,并带上 NXEX 选项:

  • NX(Not eXists): 仅当键不存在时才设置键。
  • EX(EXpire): 设置键的过期时间,防止死锁。
1# 获取锁示例
2SET mylock <lock_value> NX EX 10
3

Lua 脚本实现

为了更加原子化,可以使用 Lua 脚本:

1-- 获取锁的 Lua 脚本
2local lock_key = KEYS[1]
3local lock_value = ARGV[1]
4local ttl = tonumber(ARGV[2])
5
6if redis.call("SETNX", lock_key, lock_value) == 1 then
7    redis.call("EXPIRE", lock_key, ttl)
8    return 1
9else
10    return 0
11end
12

Redis 命令:

1redis-cli EVAL "local lock_key = KEYS[1]; local lock_value = ARGV[1]; local ttl = tonumber(ARGV[2]); if redis.call('SETNX', lock_key, lock_value) == 1 then redis.call('EXPIRE', lock_key, ttl); return 1; else return 0; end" 1 mylock lock_value 10
2

释放锁

释放锁时需要先检查当前锁是否是自己持有的,然后再删除锁:

1-- 释放锁的 Lua 脚本
2local lock_key = KEYS[1]
3local lock_value = ARGV[1]
4
5if redis.call("GET", lock_key) == lock_value then
6    redis.call("DEL", lock_key)
7    return 1
8else
9    return 0
10end
11

Redis 命令:

1redis-cli EVAL "local lock_key = KEYS[1]; local lock_value = ARGV[1]; if redis.call('GET', lock_key) == lock_value then redis.call('DEL', lock_key); return 1; else return 0; end" 1 mylock lock_value
2

2. 基于 Redlock 算法的分布式锁

Redlock 是 Redis 作者提出的一种更加健壮的分布式锁算法,旨在在多个 Redis 实例上实现锁的获取和释放。

获取锁

  1. 获取当前时间。
  2. 依次尝试在多个 Redis 实例上获取锁。
  3. 如果在大部分实例上成功获取锁,并且时间小于有效期,则获取锁成功。
1-- 基于 Redlock 算法的 Lua 脚本
2local lock_key = KEYS[1]
3local lock_value = ARGV[1]
4local ttl = tonumber(ARGV[2])
5
6local start_time = redis.call('TIME')
7local success_count = 0
8local majority = math.floor(#redis_instances / 2) + 1
9
10for _, redis_instance in ipairs(redis_instances) do
11    if redis_instance.call("SET", lock_key, lock_value, "NX", "PX", ttl) then
12        success_count = success_count + 1
13    end
14end
15
16local elapsed_time = (redis.call('TIME')[1] - start_time[1]) * 1000 + (redis.call('TIME')[2] - start_time[2]) / 1000
17
18if success_count >= majority and elapsed_time < ttl then
19    return 1
20else
21    for _, redis_instance in ipairs(redis_instances) do
22        redis_instance.call("DEL", lock_key)
23    end
24    return 0
25end
26

释放锁

释放锁时需要在所有实例上依次删除锁:

1-- 基于 Redlock 算法的 Lua 脚本
2local lock_key = KEYS[1]
3local lock_value = ARGV[1]
4
5for _, redis_instance in ipairs(redis_instances) do
6    if redis_instance.call("GET", lock_key) == lock_value then
7        redis_instance.call("DEL", lock_key)
8    end
9end
10
11return 1
12

3. 使用 Redisson 实现分布式锁

Redisson 是一个基于 Redis 的 Java 客户端,可以方便地进行分布式锁的管理。以下是使用 Redisson 实现分布式锁的示例:

添加 Maven 依赖

1<dependency>
2    <groupId>org.redisson</groupId>
3    <artifactId>redisson</artifactId>
4    <version>3.16.1</version>
5</dependency>
6

使用 Redisson 获取和释放锁

1import org.redisson.Redisson;
2import org.redisson.api.RLock;
3import org.redisson.api.RedissonClient;
4import org.redisson.config.Config;
5
6import java.util.concurrent.TimeUnit;
7
8public class DistributedLockExample {
9
10    public static void main(String[] args) {
11        // 配置 Redis 服务器
12        Config config = new Config();
13        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
14
15        // 创建 Redisson 客户端
16        RedissonClient redisson = Redisson.create(config);
17
18        // 获取锁
19        RLock lock = redisson.getLock("myLock");
20        try {
21            // 尝试加锁,等待时间 100ms,锁定时间 10s
22            boolean isLocked = lock.tryLock(100, 10000, TimeUnit.MILLISECONDS);
23            if (isLocked) {
24                try {
25                    // 执行需要锁保护的代码
26                    System.out.println("Lock acquired!");
27                    // 加锁后的操作
28                } finally {
29                    // 释放锁
30                    lock.unlock();
31                }
32            } else {
33                System.out.println("Unable to acquire lock");
34            }
35        } catch (InterruptedException e) {
36            e.printStackTrace();
37        } finally {
38            // 关闭 Redisson 客户端
39            redisson.shutdown();
40        }
41    }
42}
43

总结

通过合理使用 Redis 提供的 SETNX 命令、Lua 脚本、Redlock 算法以及 Redisson 客户端,可以有效地实现分布式锁。这些方法各有优缺点,开发者可以根据具体的应用场景选择最合适的方案来确保分布式系统中的数据一致性和并发控制。


Redis(66)Redis如何实现分布式锁?》 是转载文章,点击查看原文


相关推荐


告别异常继承树:从 NopException 的设计看“组合”模式如何重塑错误处理
canonical_entropy2025/10/16

在软件开发中,异常处理是一个不可或缺的环节。长久以来,经典的面向对象思想教导我们,为不同类型的错误建立一个庞大的继承树是一种优雅的方案。例如,定义一个基础的 AppException,然后派生出 BusinessException、SystemException 等。这种基于**继承(Inheritance)**的设计模式直观且经典。时至今日,这种思想在许多开发者心中依然根深蒂固,被认为是“正统”的 OO 设计。 然而,当系统走向分布式、服务化,并需要应对复杂的国际化、多租户、定制化需求时,这个


libevent输出缓存区的数据
我梦之62025/10/14

在网络开发中,当需要在不干扰客户端正常接收数据的前提下,验证服务端输出缓冲区中待发送数据的存在性、完整性或格式正确性(如排查客户端收不到数据的故障、确认发送数据是否符合协议规范),或监控缓冲区数据堆积情况时,会用到这段基于 libevent 库的代码。 其核心功能是对客户端连接的输出缓冲区(evbuffer)进行 “非破坏性读取”—— 先通过bufferevent_get_output获取与客户端client2关联的输出缓冲区指针,再用evbuffer_get_length获取缓冲区中待发送数据


设计模式-策略模式
紫菜紫薯紫甘蓝2025/10/13

设计模式-策略模式 策略模式,英文全称是 Strategy Design Pattern。它是这样定义的:Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. 翻译成中文就是:定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略


npm workspace 深度解析:与 pnpm workspace 和 Lerna 的全面对比
子兮曰2025/10/11

1. 前言:Monorepo 时代的到来 随着前端项目的复杂度不断提升,单体仓库(Monorepo)架构逐渐成为主流。Monorepo 允许我们在一个代码仓库中管理多个相关的包,带来了代码共享、统一依赖管理、简化 CI/CD 等诸多优势。然而,多包管理也带来了新的挑战:如何高效地管理跨包依赖、如何避免重复安装、如何简化构建流程等。 Workspace 解决方案应运而生,它为我们提供了一种优雅的方式来管理多包项目。目前主流的解决方案包括 npm workspace、pnpm workspace 和


面试真实经历某节跳动大厂Java和算法问答以及答案总结(一)
360_go_php2025/10/10

Java面试问题与解答 常见的GC回收器 - Serial GC: 适合单线程环境,暂停时间较长。 - Parallel GC: 多线程垃圾回收,适合多核处理器,停顿时间较短。 - CMS (Concurrent Mark-Sweep): 适合响应时间要求高的应用,通过多线程并发清除垃圾。 - G1 GC: 适用于大内存系统,目标是尽量减少GC停顿时间,分区回收。​编辑 SpringMVC的请求过程 - 流程: 用户发起请求 → 前端控制器(DispatcherServlet)接收请求


JAVA算法练习题day34
QiZhang6032025/10/8

43.验证二叉搜索树 要知道二叉搜索树的中序遍历结果是升序序列 # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution(o


v你真的会记笔记吗?AI的答案可能让你意外
万少 VIP.5 如鱼得水2025/10/7

这段时间我在准备一个行业调查,调研资料几乎全来自视频会议、线上讲座和播客。 内容是很丰富,但问题也随之而来:一个小时的视频回放,想找个观点得快进倒退十几次,遇到灵感还得赶紧切出去做笔记,效率低到崩溃。 看不完,根本看不完…… 正好我朋友是一个AI发烧友,他就推荐我用了一个专注做AI笔记的工具。 坦白讲,最开始我没抱太大期待,心想不就是转写嘛。但真用了两周后,我发现它完全改变了我的学习和工作流。 这个工具叫Ai好记: 网址:aihaoji.com/zh?utm_sour… 输入口令【万少】可以


Android Jetpack 核心组件实战:ViewModel + LiveData + DataBinding 详解
马 孔 多 在下雨2025/10/5

Android Jetpack 核心组件实战:ViewModel + LiveData + DataBinding 详解 在 Android 开发中,我们经常会遇到屏幕旋转数据丢失、UI 与逻辑耦合紧密、数据更新无法自动同步 UI 等问题。Google 推出的 Jetpack 架构组件可以很好地解决这些问题,本文将对 ViewModel、LiveData 和 DataBinding 三个核心组件进行讲解,从基础概念到实战案例,完整讲解这三个组件的使用方法与联动逻辑。 一、ViewModel:


从 “Hello AI” 到企业级应用:Spring AI 如何重塑 Java 生态的 AI 开发
草莓熊Lotso2025/10/4

🔥个人主页:@草莓熊Lotso 🎬作者简介:C++研发方向学习者 📖个人专栏: 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》 ⭐️人生格言:生活是默默的坚持,毅力是永久的享受。 前言:当大模型浪潮席卷软件开发领域时,Java 开发者常常面临一个困境:一边是 PyTorch、LangChain 等 Python 生态的 AI 工具链蓬勃发展,一边是企业现有系统中大量的 Spring 技术栈难以快速接入 AI 能力。而 Spring AI 的出现


Vue3 中的双向链表依赖管理详解与示例
excel2025/10/3

在 Vue3 的响应式系统中,双向链表是一个非常重要的数据结构。相比 Vue2 使用数组来存放依赖,Vue3 选择链表的原因在于效率更高,尤其是在频繁收集和清理依赖时,链表可以显著优化性能。本文将通过讲解和示例代码,帮助你理解这一点。 为什么要用双向链表 在响应式依赖收集过程中,Vue 需要完成两件事: 收集依赖:当访问响应式数据时,要记录当前副作用函数(effect)。 清理依赖:当副作用函数重新运行或失效时,需要把它从依赖集合里移除。 如果依赖集合使用数组: 删除某个依赖需要遍历整个

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0