在分布式系统中,多个服务实例同时访问共享资源时,如何保证操作的原子性成为关键难题。传统单机锁机制在跨进程、跨服务器的场景下完全失效,这正是分布式锁要解决的核心问题。
以电商秒杀场景为例,当100台服务器同时收到"库存减1"的请求时,如果没有分布式锁协调,很可能出现超卖现象。Redis凭借其高性能、原子操作特性,成为实现分布式锁的首选方案之一。
但实现一个健壮的Redis分布式锁绝非简单的SETNX命令就能搞定。我们需要解决锁的互斥性、死锁预防、锁续期、可重入性等一系列复杂问题。这也是为什么从最基础的实现到Redisson这样的成熟方案之间,存在显著的演进路径。
最朴素的实现方式是组合使用Redis的SETNX和EXPIRE命令:
bash复制SETNX lock_key unique_value # 尝试获取锁
EXPIRE lock_key 10 # 设置过期时间
这种方案存在致命缺陷——两条命令非原子性执行。如果在SETNX成功后、EXPIRE执行前进程崩溃,将导致锁永远无法释放。我在实际生产环境中就遇到过因此引发的服务长时间阻塞。
Redis 2.6.12后支持set命令的扩展参数,可以原子性地完成设置值和过期时间:
bash复制SET lock_key unique_value NX EX 10
这解决了原子性问题,但仍存在以下隐患:
关键提示:必须确保锁的value是全局唯一标识(如UUID),并在删除时验证value匹配,避免误删其他客户端的锁。
Redisson通过"看门狗"机制解决锁过期问题:
java复制// Redisson锁续期核心逻辑
private void scheduleExpirationRenewal() {
if (expirationRenewalMap.putIfAbsent(getEntryName(), new ExpirationEntry()) == null) {
renewExpiration();
}
}
Redisson使用Redis的Hash结构存储锁信息:
java复制// 获取锁的Lua脚本
if (redis.call('exists', KEYS[1]) == 0) then
redis.call('hincrby', KEYS[1], ARGV[2], 1);
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
当需要更高可靠性时,Redisson实现了Redis官方推荐的RedLock算法:
java复制RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
lock.lock();
try {
// 业务逻辑
} finally {
lock.unlock();
}
| 参数 | 默认值 | 生产建议 | 说明 |
|---|---|---|---|
| lockWatchdogTimeout | 30000ms | 根据业务调整 | 看门狗检查间隔 |
| retryInterval | 100ms | 50-200ms | 获取锁重试间隔 |
| retryAttempts | 3 | 根据QPS调整 | 最大重试次数 |
问题1:锁等待时间过长
问题2:出现死锁
问题3:锁被误删
| 维度 | Redis | Zookeeper |
|---|---|---|
| 性能 | 高 | 中 |
| 可靠性 | 依赖持久化 | 高 |
| 实现复杂度 | 中 | 高 |
| 适用场景 | 高频短时操作 | 低频长时操作 |
对于大多数业务场景,我建议直接使用Redisson:
自研实现仅建议在以下情况考虑:
锁粒度控制:锁的key应精确到具体资源,如order_lock:123比全局order_lock更优
超时时间设置:
监控指标:
bash复制# Redis监控命令
redis-cli info stats | grep sync_full
redis-cli slowlog get
降级方案:当Redis不可用时,应有本地限流等备用方案
在实际项目中,我曾遇到一个典型案例:支付系统使用Redisson锁协调分布式记账,初期由于未设置合理的watchdogTimeout,导致长时间GC时锁自动释放,最终通过以下配置解决:
java复制Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://127.0.0.1:7000")
.setLockWatchdogTimeout(60000);
RedissonClient redisson = Redisson.create(config);
分布式锁的正确实现需要深入理解分布式系统的复杂性。经过多个项目的实践验证,我认为Redisson是目前Java生态中最成熟可靠的Redis分布式锁解决方案,其设计思想也值得所有开发者学习借鉴。对于关键业务系统,建议在预发布环境充分测试锁的各种边界条件,确保万无一失。