上一篇
场景引入:
半夜12点,你的秒杀系统突然报警——10台服务器同时抢购同一件商品,库存竟然变成了-100!😱 检查代码发现:if (库存>0) { 扣减库存 }
这个逻辑在分布式环境下被多个进程同时执行,瞬间击穿了防线...
别慌!今天我们就用 Redis锁 + Lua脚本 这对黄金组合,彻底解决这类分布式原子操作难题!
在单机时代,我们用synchronized
或ReentrantLock
就能保证线程安全,但在分布式系统中:
这时候就需要一个全局可见的锁服务,而Redis凭借高性能和丰富的数据结构成为首选。
# 加锁(如果key不存在则设置成功) SETNX lock:order_123 1 # 设置过期时间防止死锁 EXPIRE lock:order_123 30
问题来了:
SET lock:order_123 1 NX PX 30000 # 原子性设置锁+过期时间
解决了原子性问题,但锁误删依然存在。
Redis的单线程模型保证了Lua脚本的原子执行——就像数据库的事务一样!
-- 加锁脚本(参数:锁key, 客户端ID, 过期时间) local key = KEYS[1] local clientId = ARGV[1] local expire = ARGV[2] if redis.call('SETNX', key, clientId) == 1 then redis.call('PEXPIRE', key, expire) return 1 else return 0 end
-- 解锁脚本(确保只有锁持有者能删除) local key = KEYS[1] local clientId = ARGV[1] if redis.call('GET', key) == clientId then return redis.call('DEL', key) else return 0 end
优势:
✅ 加锁和设置过期时间原子完成
✅ 解锁时校验客户端唯一标识(可用UUID)
✅ 脚本执行期间其他命令必须等待
def acquire_lock(): while timeout_not_reached: if redis.eval(加锁脚本) == 1: return True time.sleep(50ms) # 避免疯狂重试 raise LockTimeout()
对于长任务,启动一个后台线程定期延长锁过期时间:
if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) end
秒杀库存扣减
local stock = tonumber(redis.call('GET', 'stock')) if stock > 0 then redis.call('DECR', 'stock') return "SUCCESS" end
防止重复订单
if redis.call('SETNX', 'order:'..orderId, 1) == 1 then redis.call('EXPIRE', 'order:'..orderId, 3600) -- 处理订单逻辑 end
全局配置更新
-- 保证配置更新期间其他服务读取到一致状态 if redis.call('SETNX', 'config_lock', 1) == 1 then redis.call('MSET', 'config1', newValue1, 'config2', newValue2) end
2025-07技术动态:Redis 7.4新增了
SET
命令的EXAT
参数,支持绝对时间戳过期,比PX
更精确!
分布式锁就像十字路口的红绿灯🚦,而Lua脚本则是那个绝对权威的交警,掌握这套组合拳,你就能在分布式世界里安全、高效地控制共享资源!下次遇到并发问题,不妨大喊一声:"Lua,给我锁它!" 🔐
(完)
本文由 濯子 于2025-07-30发表在【云服务器提供商】,文中图片由(濯子)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://up.7tqx.com/wenda/486595.html
发表评论