Python Web项目中怎么做分布式锁防并发冲突_使用redis-py实现SETNX与Lua原子脚本

轻明同学_3372

轻明同学_3372

2026-04-12

800人浏览

原创

直接用 setnx 不够安全,因其无法原子性完成设置值、过期时间和防误删三件事,易导致死锁或锁被误删;需结合 set ... nx ex 和 lua 脚本校验锁归属来保障安全性。

python web项目中怎么做分布式锁防并发冲突_使用redis-py实现setnx与lua原子脚本

为什么直接用 SETNX 不够安全?

因为 SETNX 只能保证“设置键不存在时才写入”,但无法同时完成“设置值 + 设置过期时间 + 防误删”三件事。常见错误是先 SETNX 成功,再用 EXPIRE 设过期——如果进程在中间崩溃,锁就永远不释放,变成死锁。

更隐蔽的问题是:多个客户端都以为自己持锁成功,结果同时执行临界区逻辑。典型表现是数据库重复插入、库存扣减为负、任务被重复调度。

  • Redis 2.6.12+ 支持 SET key value EX seconds NX 命令,可原子完成“存在性判断 + 写入 + 过期”,但依然没解决“谁删谁的锁”问题
  • 若客户端A持有锁,超时后自动释放,此时客户端B获取到锁;而A还在执行,结束后却执行了 DEL,把B的锁给删了
  • 所以必须让“校验锁归属 + 删除”也原子化,只能靠 Lua 脚本

用 redis-py 实现带校验的 Lua 分布式锁

核心思路:加锁时写入唯一标识(如 UUID 或进程 ID),解锁时只允许该标识删除自己的锁。Lua 脚本在 Redis 端执行,天然原子。

示例脚本(保存为 unlock.lua):

Python Use Agent
Python Use Agent

智能执行Python任务,自动生成、执行代码并反馈结果,无需额外配置,兼容旧命令。

下载
if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end

Python 中调用方式:

  • 加锁:用 set(name, value, ex=30, nx=True),其中 value 是随机字符串(推荐 uuid.uuid4().hex)
  • 解锁:预载 Lua 脚本,传入 key 和相同 value:unlock_script(keys=[lock_key], args=[lock_value])
  • 务必检查返回值:加锁返回 True/False,解锁返回 1 表示删除成功,0 表示锁已被改或不存在

锁的超时时间怎么设才合理?

设太短:业务还没执行完锁就过期,其他客户端趁虚而入;设太长:出错后恢复慢,影响系统吞吐。这不是拍脑袋决定的,得结合实际。

  • 先压测单次临界操作耗时,取 P99 值,再乘以 1.5~2 倍作为基础超时(比如 P99 是 800ms,初设为 2s)
  • 如果业务中可能阻塞(如调第三方 API、大文件 IO),必须显式做超时控制,并在超时前主动续锁(GETSET 或 PEXPIRE)——但续锁本身也有竞态,生产环境建议用 Redlock 或成熟库如 redis-lock
  • Redis 主从异步复制下,主节点写入锁后宕机,从节点升主,原锁可能丢失。严格场景需考虑 Redlock,但多数 Web 场景用单实例 + 合理超时已足够

哪些地方最容易漏掉导致锁失效?

不是写了 SETNX 就算用了分布式锁,很多细节一漏,等于没锁。

  • 没校验 set() 返回值:redis.set(..., nx=True) 失败返回 None,不判断就直接进业务逻辑,相当于没锁
  • 解锁不用 Lua,而是简单 DEL:这是最常见误用,会导致锁被误删
  • 锁 key 没带业务上下文:比如全用 "order_lock",不同订单互相干扰。应拼接业务 ID,如 f"order_lock:{order_id}"
  • 异常路径没解锁:try/except 里忘了 finally 或没捕获所有异常类型(比如 KeyboardInterrupt、SystemExit),锁会残留

真正难的从来不是写几行 Lua,而是把锁的生命周期和业务流程对齐——超时、重试、清理、监控,缺一不可。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1651

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4124

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1669

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

23857

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2927

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2947

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1143

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2283

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程