Redis 实现分布式锁的核心是利用 SET NX EX 命令(原子性地实现“不存在则设置+过期时间”),确保同一时刻只有一个客户端获得锁,再配合 Lua 脚本保证释放锁的原子性。
1. 核心原理:加锁(获取锁)
通过 SET key value NX EX expireTime 命令实现,该命令是原子操作,能避免“检查-设置”的竞态问题。
NX(Not Exist):仅当 key 不存在时才设置成功,确保只有一个客户端拿到锁。
EX(Expire):为 key 设置过期时间(如 5 秒),避免客户端崩溃后锁永久无法释放。
value:建议使用 唯一随机值(如 UUID),确保释放锁时只能删除自己加的锁,避免误删他人的锁。
示例命令(Redis CLI): SET lock:order UUID-123 NX EX 5 - 执行成功(拿到锁):返回 OK。 - 执行失败(锁已存在):返回 nil。
2. 关键步骤:释放锁(避免误删)
释放锁需先判断“当前锁的 value 是否为自己的随机值”,再删除 key,这两步必须原子执行,否则会出现“客户端 A 删了客户端 B 的锁”的问题。
解决方案:用 Lua 脚本执行判断+删除,Redis 会将脚本作为整体原子执行。
Lua 脚本示例:
-- 1. 判断锁的 value 是否等于传入的随机值(确保是自己的锁)
-- 2. 若相等则删除锁,返回 1;否则返回 0
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
KEYS[1]:锁的 key(如 lock:order)
ARGV[1]:加锁时的随机值(如 UUID-123)
3. 进阶优化:解决“锁过期”问题
若客户端拿到锁后,业务执行时间超过锁的过期时间,锁会自动释放,可能导致多个客户端同时持有锁。
解决方案:为锁添加 “续约机制”(即“看门狗”):
客户端拿到锁后,启动一个后台线程(如定时任务)。
线程每隔 过期时间的 1/3(如锁过期 5 秒,则每隔 1.5 秒)检查一次:若当前客户端仍持有锁,则延长锁的过期时间至 5 秒。
当业务执行完成或客户端崩溃,线程停止,锁不再续约,到期后自动释放。
4. 常见方案:基于 Redisson 简化实现
手动实现上述逻辑较复杂,实际项目中常用 Redis 客户端 Redisson(支持 Java、Python 等),它已封装好分布式锁的完整逻辑(加锁、续约、释放锁),开箱即用。
Java 示例(Redisson):
// 1. 获取 Redisson 客户端
RedissonClient redisson = Redisson.create(config);
// 2. 获取分布式锁(key 为 lock:order)
RLock lock = redisson.getLock("lock:order");
try {
// 3. 加锁(默认 30 秒过期,自动启动看门狗续约)
lock.lock();
// 4. 执行核心业务(如创建订单)
doBusiness();
} finally {
// 5. 释放锁(自动判断是否为自己的锁,避免误删)
lock.unlock();
}
5. redis使用场景
Redis 分布式锁适用于 并发量中等、对锁可靠性要求非极致严苛,但追求高性能与低延迟 的分布式场景,核心用于解决跨服务/跨节点的资源竞争问题,典型使用场景如下:
1. 防止接口重复请求/幂等性保障
当多个客户端(或服务)可能重复调用同一接口(如用户重复提交订单、重复支付)时,用 Redis 分布式锁确保“同一业务标识下,仅一次请求能执行核心逻辑”。
- 示例:用户提交订单时,以“用户ID+订单唯一标识”为锁 key,获取锁成功才执行“创建订单”逻辑;未获取到锁则直接返回“请求处理中”或“订单已存在”,避免生成重复订单。
2. 控制分布式任务的并发执行
当多个服务节点同时监听并执行同一类任务(如定时任务、消息消费)时,用 Redis 分布式锁避免“同一任务被多节点重复执行”,确保任务唯一执行。
- 示例:分布式定时任务(如每日凌晨同步用户数据),以“任务名称+日期”为锁 key,仅抢到锁的服务节点执行同步逻辑,其他节点跳过,避免重复同步导致数据冗余或冲突。
3. 限制共享资源的并发访问
当多个服务需要操作同一共享资源(如修改数据库同一条记录、操作分布式缓存中的同一 key、调用第三方有限资源接口)时,用 Redis 分布式锁控制“同一时间仅一个服务能操作资源”。
示例1:多服务修改数据库中“商品库存”,以“商品ID”为锁 key,抢到锁的服务才能执行“库存减1”操作,避免超卖。
示例2:调用第三方支付接口(有每秒调用次数限制),以“接口名称”为锁 key,控制同一时间仅一个请求调用接口,避免触发限流。
4. 分布式系统中的“临界区”保护
在分布式架构中,若存在“多节点需串行执行的代码块”(即临界区,如初始化全局配置、更新分布式计数器),用 Redis 分布式锁确保“临界区逻辑仅一个节点执行”,避免数据不一致。
- 示例:分布式系统启动时初始化全局配置到缓存,以“config:init”为锁 key,仅第一个启动的节点执行初始化,其他节点直接读取缓存,避免重复初始化覆盖数据。
5. 秒杀/抢购场景的并发控制
秒杀、抢购场景下,大量请求同时争抢有限商品,需用 Redis 分布式锁结合其高性能特性,控制“同一商品的下单逻辑串行执行”,配合库存预扣减,缓解数据库压力并避免超卖。
注意:该场景需优化锁粒度(如按商品ID分锁,而非全局锁),并结合 Redis 原子操作(如 DECR 预扣减库存)提升性能,避免锁成为瓶颈。
不适合的场景
需明确 Redis 分布式锁的局限性,以下场景不建议使用:
金融级强一致性场景(如银行转账、账务核算):需绝对避免“锁丢失”“并发持有锁”,建议用 ZooKeeper/etcd 分布式锁。
业务执行时间远超锁过期时间的场景:若业务逻辑(如大数据计算)耗时数分钟,“看门狗”续约机制仍有失效风险,需重新评估锁方案。
总结
Redis 分布式锁的核心优势是 高性能、低延迟、部署成本低,因此在互联网业务中(如电商、社交、内容平台)的“非金融级并发控制”场景中应用广泛,是平衡“可靠性”与“性能”的优选方案。