Redis 分布式锁是分布式系统中协调多进程/服务对共享资源访问的核心机制。以下从基础概念到高级实现进行全面剖析。
一、基础实现原理
1. 最简实现(SETNX 命令)
# 加锁
SET resource_name my_random_value NX PX 30000
# 解锁(Lua脚本保证原子性)
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
关键要素:
NX
:仅当key不存在时设置(原子性保证)PX 30000
:30秒自动过期(防死锁)my_random_value
:唯一客户端标识(防误删)
2. 实现演进对比
版本 |
方案 |
问题 |
v1.0 |
SETNX + EXPIRE |
非原子操作可能死锁 |
v2.0 |
SET NX PX |
无法解决误删锁问题 |
v3.0 |
唯一值 + Lua解锁 |
基本满足需求 |
v4.0 |
Redlock算法 |
解决单点问题 |
二、Redis 单实例实现详解
1. 完整加锁流程
sequenceDiagram
participant Client
participant Redis
Client->>Redis: SET lock:order UUID123 NX PX 30000
alt 锁空闲
Redis-->>Client: OK
Client->>Client: 启动看门狗线程
else 锁占用
Redis-->>Client: nil
Client->>Redis: BLPOP lock:order:notify 30
Redis--xClient: 等待通知或超时
end
2. 看门狗机制(续期)
def watchdog(lock_key, client_id, ttl):
while True:
time.sleep(ttl / 3) # 每10秒续期一次
if not redis.call(
"EVAL",
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('pexpire', KEYS[1], ARGV[2]) " +
"else return 0 end",
1, lock_key, client_id, ttl
):
break # 续期失败退出
3. 解锁通知优化
lua
-- 解锁时发布通知
redis.publish("lock:order:notify", "released")
-- 客户端订阅
SUBSCRIBE lock:order:notify
三、Redlock 集群算法
1. 算法流程
- 获取当前毫秒级时间戳 T1
- 依次向 N 个 Redis 节点请求加锁(相同TTL)
- 计算获取锁耗时 = 当前时间 T2 - T1
- 当且仅当满足:
-
- 获得多数节点(N/2 + 1)认可
- 总耗时 < 锁TTL
- 锁有效时间 = 初始TTL - 获取锁耗时
2. 节点故障处理
graph TD
A[客户端] --> B[Redis Master1]
A --> C[Redis Master2]
A --> D[Redis Master3]
B -->|响应超时| E[标记节点不可用]
C -->|成功获取| F[锁计数+1]
D -->|成功获取| F
3. 关键参数配置
参数 |
建议值 |
说明 |
节点数 |
5 |
允许2个节点故障 |
重试延迟 |
50-200ms |
随机化避免冲突 |
锁TTL |
10-30s |
业务完成时间+缓冲 |
四、生产级问题解决方案
1. 时钟漂移问题
场景:
- 节点间时钟不同步导致TTL计算错误
解决方案:
python
# 使用单调时钟而非系统时钟
start_time = get_monotonic_time()
elapsed = get_monotonic_time() - start_time
remaining_ttl = initial_ttl - elapsed
2. GC停顿导致锁失效
应对策略:
- 设置保守TTL(业务最大耗时×2)
- 添加JVM监控告警
- 关键业务禁用GC(如ZGC)
3. 客户端长时间阻塞
优化方案:
java
// 非阻塞尝试
boolean locked = tryLock(5, TimeUnit.SECONDS);
// 异步获取
RFuture<Boolean> future = lock.tryLockAsync();
五、各语言实现对比
语言 |
推荐库 |
特性 |
Java |
Redisson |
支持看门狗、多种锁类型 |
Go |
redsync |
实现Redlock算法 |
Python |
redis-py |
基础锁实现 |
Node.js |
node-redlock |
TypeScript支持 |
六、性能优化方案
1. 锁分段技术
python
def get_segment_lock(resource_id):
segment = resource_id % 16 # 分为16段
return f"lock:{resource_type}:{segment}"
# 使用示例
lock = get_segment_lock(order_id)
2. 读写锁分离
redis
# 写锁
SET rwlock:order WRITE <client_id> NX PX 10000
# 读锁计数器
INCR rwlock:order:read_count
3. 热点锁优化
策略 |
实施方法 |
适用场景 |
本地缓存 |
先获取本地锁再尝试分布式锁 |
极高并发 |
令牌桶 |
控制获取锁的速率 |
突发流量 |
乐观锁 |
CAS机制更新资源 |
冲突较少 |
七、监控与告警指标
1. 关键监控项
bash
# Redis监控
redis-cli info stats | grep lock
redis-cli slowlog get # 查看锁命令耗时
# 客户端监控
lock_acquire_time_seconds_bucket{le="0.1"} 0.95 # 99%锁获取<100ms
lock_hold_time_seconds_sum / lock_hold_time_seconds_count # 平均持有时间
2. 告警规则示例
yaml
# Prometheus规则
- alert: HighLockContention
expr: rate(redis_commands_total{cmd="SET",arg0~="lock:*"}[1m]) > 100
for: 5m
labels:
severity: warning
annotations:
summary: "High lock contention detected"
八、选型决策指南
mermaid
graph TD
A[需要强一致性?] -->|是| B[Redlock+5节点]
A -->|否| C[单Redis+看门狗]
B --> D[业务容忍延迟?]
D -->|是| E[同步确认]
D -->|否| F[异步确认]
C --> G[需要自动续期?]
G -->|是| H[Redisson]
G -->|否| I[基础SETNX]
通过深入理解这些原理和实现细节,可以构建出既安全又高效的Redis分布式锁方案。建议根据实际业务场景的CAP需求进行技术选型和参数调优。
Redisson分布式锁深度解析:原理与实现机制 参见上一篇