Redis 系列(九):分布式锁与限流——用 Redis 做并发治理
核心目标掌握分布式锁的正确实现SET NX EX 持有者标识 Lua 原子释放理解锁过期、主从切换的失效边界与 Redlock 争议掌握固定窗口、滑动窗口、令牌桶三种限流算法及其 Redis 实现。前置知识完成 Part 7Lua 原子性——锁释放与令牌桶的地基与 Part 8重建锁的实战用法。验证环境Redis 8.10.0cygwin 移植版127.0.0.1:6379、redis-py 8.1.0、Python 3.11.6、Windows 11。最后复核日期2026-08-07。0. 本篇问题场景锁和限流Redis 的两副面孔同一把SET命令在两个场景里是完全不同的角色分布式锁多个进程抢一个资源下单、发券保证同一时刻只有一个执行限流把请求速率压到阈值内秒杀、防刷保证单位时间只放行 N 个。两者共同的难点正确性藏在边界里——锁的边界是过期与误删限流的边界是窗口与突发。本篇先用实验复现这些边界再给工程结论。1. 分布式锁正确实现的三要素1.1 错误的起点setnxexpire两步经典错误写法是两个独立命令SETNX拿锁再EXPIRE设过期。两步之间进程崩溃锁就永不释放。正确做法是单条原子命令r.set(lock_key,token,nxTrue,ex10)三个要素缺一不可要素作用反例NX不存在才写入互斥用SET直接覆盖会抢别人的锁EX过期兜底防死锁无 TTL持有者崩溃后锁永存唯一 token标识持有者释放时校验无 token 时释放会误删他人锁1.2 实测一错误释放 vs Lua 原子释放# 错误直接 delete——不管锁是不是自己的r.delete(lock_key)# 正确Lua 校验持有者标识后原子删除release_script if redis.call(GET, KEYS[1]) ARGV[1] then return redis.call(DEL, KEYS[1]) else return 0 end 实测第一次获取锁: True 第二次获取锁应失败: None ← 互斥生效 错误释放无校验后锁: None ← 锁没了可能删的是别人的 演示重新加锁后再验证正确释放 正确释放value 匹配: 1 ← 只有持有者能删 释放后锁: None1.3 实测二锁过期的竞态——“A 释放了 B 的锁”完整事故链复现TTL 1 秒A 拿锁token-A, TTL 1s→ A 业务超时 → 锁过期 B 获取锁: TrueB 现在持有token-B A 无校验释放后锁: None ← A 把 B 的锁删了B 的保护失效 演示B 察觉锁丢失后重新加锁 token-B A 带 value 校验释放: 0 ← 校验不通过B 的锁安然无恙 B 的锁仍然在: token-B结论锁的释放必须校验 删除原子完成Lua否则任何一次误删都会让两个进程同时进入临界区——比没有锁更糟。1.4 锁的过期时间怎么定TTL 太短 → 业务没跑完锁就过期另一个进程进来上面的事故太长 → 持有者崩溃后资源被锁住很久。工程解法TTL 业务最长执行时间经验值3-10 倍余量看门狗续期持有者定期如 TTL/3执行 Lua 续期业务结束主动释放——类似 Redisson 的 watchdog续期本身有成本与失败路径最终兜底仍是业务幂等。2. 分布式锁的边界Redlock 争议与正确认知2.1 主从切换丢锁Redis 主从复制是异步的主库SET NX成功返回后复制到从库之前主库宕机 → 哨兵把从库提升为主库 →新主库没有这把锁→ 另一个进程可以拿到同一把锁。进程A: SET lock token-A NX EX → 主库成功 主库宕机锁未复制到从库 哨兵提升从库为新主库无锁记录 进程B: SET lock token-B NX EX → 成功A、B 同时持锁2.2 Redlock 与争议antirez 提出的Redlock向 N 个独立 Redis 实例N5同时申请锁多数≥3成功且耗时 TTL 才算拿到。反对者Martin Kleppmann 等的核心论点锁的互斥依赖时钟TTL 到期依赖各节点时钟一致时钟跳跃会破坏GC 停顿进程拿到锁后 JVM GC/进程暂停暂停时间超过 TTL锁过期后他人进入——Redlock 无法阻止这不是 Redis 的问题是锁 暂停的普遍问题多数场景单实例锁 幂等兜底已足够Redlock 的复杂度与运维成本不划算。工程结论也是本系列立场分布式锁是概率性互斥——过期、主从切换、GC 停顿都可能破坏互斥。正确的架构不是追求绝对安全的锁而是分布式锁减少并发竞争 业务幂等兜底重复执行 监控告警高可用锁场景Redis 主从切换在 Part 10 哨兵/集群后能缓解丢锁但幂等永远是最底层防线。3. 限流三种算法与 Redis 实现3.1 固定窗口最简单deffixed_window(key,limit,window):curr.incr(key)ifcur1:r.expire(key,window)# 第一条命令开启窗口returncurlimit实测3 次/2 秒连续 5 次请求: [True, True, True, False, False] 并发压测限制 5/秒, 50 请求: 放行 5 个缺点窗口边界允许突发——第 1 秒末放 5 个、第 2 秒初又放 5 个2 秒内放了 10 个。3.2 滑动窗口精确到任意窗口用 ZSet 记录每次请求时间戳查询时先清掉窗口外的记录再计数defsliding_window(key,limit,window,member):nowtime.time()*1000pipe.zremrangebyscore(key,0,now-window*1000)# 清理过期pipe.zadd(key,{member:now})pipe.zcard(key)pipe.expire(key,window)_,_,count,_pipe.execute()returncountlimit实测3 次/2 秒连续 5 次请求: [True, True, True, False, False]代价每个请求一条 ZSet 记录内存与 ZSet 大小随 QPS 增长可配合ZREMRANGEBYSCORE定期清理。3.3 令牌桶平滑突发桶容量 突发上限速率 稳定速率。Lua 实现原子维护令牌数 时间戳localtokenstonumber(redis.call(GET,KEYS[1])orcapacity)locallasttonumber(redis.call(GET,KEYS[1]..:ts)ornow)tokensmath.min(capacity,tokens(now-last)*rate)redis.call(SET,KEYS[1],tokens)redis.call(SET,KEYS[1]..:ts,now)iftokens1thenredis.call(SET,KEYS[1],tokens-1)return1elsereturn0end实测容量 5、速率 2/秒突发 8 个请求: [True×5, False×3] ← 桶满 5突发 5 个 等 1 秒后2 令牌: [True, True, False] ← 平滑补充对比算法实现成本突发控制内存固定窗口最低1 个键无边界可翻倍最低滑动窗口中ZSet精确随 QPS 增长令牌桶中Lua平滑容量即突发上限低2 个键4. shop-lab 实战锁 幂等 限流三层4.1 分布式锁封装shop-lab/src/shop_lab/lock.pydefacquire(lock_name,ttl10):keyflock:{lock_name}tokenuuid.uuid4().hexifr.set(key,token,nxTrue,exttl):returnkey,token# 返回锁与持有者标识returnNonedefrelease(lock_key,token):returnr.eval(_RELEASE_SCRIPT,1,lock_key,token)1# Lua 原子释放4.2 限流封装shop-lab/src/shop_lab/ratelimit.py提供fixed_window与token_bucket§3 的实现。秒杀接口组合使用订单幂等acquire(order:{order_no}) → 执行业务 → release 唯一索引兜底 秒杀限流token_bucket(seckill:{sku}, capacity100, rate20)4.3 测试tests/test_lock.py互斥、误删他人锁被拒、上下文管理器、获取失败抛异常与tests/test_ratelimit.py窗口边界、窗口重置、令牌桶突发/重填$ cd redis/shop-lab python -m pytest ......................................... [100%] 41 passed in 33.28s5. 版本与环境差异差异点说明SET NX EX2.6.12 稳定redis-py 8.x 失败返回None非 False锁实现选择单实例锁 幂等兜底是默认Redlock 需要 5 个独立实例仅高安全场景看门狗续期redis-py 无内建 watchdogRedisson 有需要可自实现 Lua 续期限流算法与版本无关INCR/ZADD/Lua 在 6.x 一致6. 测试与验收锁测试必须覆盖互斥、误删他人锁被拒持有者校验、上下文释放、获取失败限流测试用固定窗口 短 sleep 控制时序断言放行/拒绝序列并发验证用线程 统计断言限制 N 放行 ≤ N固定窗口允许边界误差。本篇验收清单能写出正确的加锁SET NX EX token与解锁Lua 校验并解释每一步为什么能复述锁过期 → 他人持锁 → 误删事故链并说出 value 校验的作用能解释主从切换丢锁与 Redlock 争议的核心论点并说出锁 幂等 监控的立场能实现固定窗口、滑动窗口、令牌桶并说出各自边界突发/内存/平滑cd redis/shop-lab python -m pytest41 passed。7. 常见误区“setnxexpire两步没问题”——两步之间崩溃即死锁必须原子 SET§1.1。“释放锁就是 delete”——必须校验持有者否则 A 会删掉 B 的锁§1.3。“Redlock 绝对安全”——它解决主从丢锁但解决不了时钟跳跃与 GC 停顿争议的本质是锁的绝对性不存在§2.2。“固定窗口就够精确了”——窗口边界可放行 2 倍流量§3.1。“限流返回 429 就行”——服务端限流还要配合客户端退避、降级否则重试风暴会放大压力。8. 本篇小结分布式锁与限流本质都是用 Redis 的原子性换并发可控锁SET NX EX获取 Lua 校验释放 幂等兜底边界它是概率性互斥不是数学证明限流固定窗口简单/ 滑动窗口精确/ 令牌桶平滑按突发容忍度选型组合拳锁处理谁来做限流处理能做多快幂等处理做了两次怎么办——三者缺一不可。下一篇进入高可用篇Part 10主从复制与哨兵回答单机挂了怎么办——复制原理、哨兵故障转移与脑裂防护用真实的一主两从三哨兵环境演练一次主库宕机。9. 官方资料SET 命令NX/EX 选项https://redis.io/docs/latest/commands/set/Redlock 原稿antirezhttps://redis.io/docs/latest/develop/use/patterns/distributed-locks/分布式锁争议Kleppmannhttps://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.htmlINCR / ZADD / EVALhttps://redis.io/docs/latest/commands/

相关新闻

Spring Statemachine实现订单状态管理的最佳实践

Spring Statemachine实现订单状态管理的最佳实践

1. 为什么需要状态机? 在开发复杂业务系统时,我们经常遇到需要管理对象状态流转的场景。比如订单从"待支付"到"已支付"再到"已发货",或者工单从"新建"到"处理中"再到"已解决"。…

2026/10/14 5:24:00 阅读更多 →
AI应用Token成本管控实战:从架构优化到监控治理的三层防御体系

AI应用Token成本管控实战:从架构优化到监控治理的三层防御体系

1. 项目概述:当AI的“账本”翻到Token成本这一页 最近和不少企业的技术负责人、产品经理聊天,发现一个挺有意思的现象。大家谈起AI,尤其是大语言模型(LLM),已经从最初的“哇,好厉害”的惊叹&…

2026/10/10 23:11:50 阅读更多 →
从拼错一个单词到命中正确业务数据,深入理解 SAP HANA 与 ABAP CDS 的 Fuzzy Search

从拼错一个单词到命中正确业务数据,深入理解 SAP HANA 与 ABAP CDS 的 Fuzzy Search

在 SAP Fiori Elements 的 List Report 里输入一段产品名称,搜索框里的内容明明少了一个字母,后台却依旧能够把正确产品找出来。这个体验看起来很普通,但如果沿着请求一路追到 ABAP CDS、SADL 和 SAP HANA,会发现它与传统的 LIKE 查询完全不是一类东西。 这里工作的核心能…

2026/10/13 2:17:29 阅读更多 →

最新新闻

VC++ FTP服务器与客户端完整源码解析:从协议到断点续传实战

VC++ FTP服务器与客户端完整源码解析:从协议到断点续传实战

简介:一套面向VC/MFC与网络通信初学者的FTP客户端与服务器完整示例工程,基于VC6.0调试通过。工程同时提供控制台版本的FTP服务器和MFC界面客户端,源码头文件结构清晰,关键功能均以类接口形式开放,便于在此基础上扩展成…

2026/10/14 5:24:12 阅读更多 →
不做Delta Rule的线性注意力:CyFA结构化累积机制解析与实测

不做Delta Rule的线性注意力:CyFA结构化累积机制解析与实测

1. 从"Delta Rule依赖症"说起:为什么大家默认线性注意力必须做增量更新过去一年,线性注意力这条技术路线几乎被一种共识笼罩:想让模型在长序列上既快又准,就得在状态更新里塞进某种"增量学习"的机制。GDN、KD…

2026/10/14 5:24:12 阅读更多 →
AIGC检测率78%怎么办?2026年教育学专业论文降痕实录

AIGC检测率78%怎么办?2026年教育学专业论文降痕实录

答辩前一周,我把教育学硕士论文初稿扔进AIGC检测系统,屏幕上跳出来的数字是78%。那一刻脑子是懵的——导师前一天刚在群里发通知,检测结果超过30%的一律退回重写。盯着那份标红的报告看了半小时,我才接受一个事实:文献…

2026/10/14 5:24:12 阅读更多 →
自然排序原理与多语言实现:告别文件排序错乱

自然排序原理与多语言实现:告别文件排序错乱

做文件批量导出时,你大概率见过这种场面:同一个目录下明明有 File 1、File 2、File 10,排序结果却是 File 10、File 1、File 2?这种反直觉的顺序,正是缺失自然排序(Natural Sort Order)造成的。…

2026/10/14 5:24:12 阅读更多 →
自然排序详解:解决文件名中数字排序混乱问题

自然排序详解:解决文件名中数字排序混乱问题

1. 问题根源:为什么 File 10 会排到 File 2 前面?1.1 从一次真实的文件整理崩溃说起先说个我上周刚踩过的坑。整理一个素材库,里面是几百个按时间序列导出的截图:File 1.png、File 2.png……一直到 File 120.png。在某个同步盘里打…

2026/10/14 5:24:12 阅读更多 →
2026企业文档协作解决方案与实施指南

2026企业文档协作解决方案与实施指南

1. 企业文档协作的痛点与需求解析在2026年的数字化办公环境中,跨部门文档协作已成为企业运营的基础需求。根据我们团队对327家中大型企业的调研,89%的组织存在"信息孤岛"现象——市场部的方案需要重新排版才能给技术团队参考,财务数…

2026/10/14 5:23:12 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →