分布式锁是分布式系统中协调多节点访问共享资源的经典解决方案。它的核心价值在于解决"多节点并发操作同一资源时如何保证数据一致性"这一根本问题。想象一下电商系统中多个用户同时抢购同一件商品,或者金融系统中多个交易线程同时处理同一账户余额的场景,没有分布式锁的约束就会导致超卖、重复扣款等严重问题。
在单机环境下,我们可以用Java的synchronized关键字或ReentrantLock轻松实现线程互斥。但在分布式系统中,由于网络延迟、节点故障等因素的存在,实现一个可靠的分布式锁变得异常复杂。CAP理论告诉我们,分布式系统无法同时满足一致性、可用性和分区容错性,而分布式锁正是牺牲部分可用性来换取强一致性的典型实践。
分布式锁需要满足三个基本特性:
最早的Redis分布式锁实现非常简单:
bash复制SETNX lock_key unique_value
EXPIRE lock_key 10
这种实现存在明显缺陷:SETNX和EXPIRE是两个独立操作,如果客户端在SETNX后崩溃,会导致锁永远无法释放。改进方案是使用Redis 2.6.12后支持的SET扩展参数:
bash复制SET lock_key unique_value NX PX 10000
释放锁时常见的错误是直接删除key:
bash复制DEL lock_key
这会导致其他客户端可能误删不属于自己的锁。正确的做法是使用Lua脚本保证原子性:
lua复制if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
当业务操作耗时超过锁过期时间时,会出现锁提前释放的问题。Redisson通过"看门狗"机制解决这个问题:获取锁成功后启动一个后台线程,定期(默认10秒一次)检查客户端是否还持有锁,如果是则延长锁的生存时间。
Redis作者提出的Redlock算法试图解决单点故障问题,基本流程如下:
分布式系统专家Martin Kleppmann指出Redlock存在几个关键问题:
Antirez回应称分布式锁本就无法做到完美,Redlock提供的是足够好的安全性。实际生产中,Redlock适合对一致性要求不是极端严格的场景。对于银行等金融系统,更推荐使用Zookeeper或etcd实现分布式锁。
yaml复制# Redisson配置示例
singleServerConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
subscriptionsPerConnection: 5
connectionMinimumIdleSize: 10
connectionPoolSize: 64
即使使用分布式锁,业务层仍需做好防护:
code复制// 锁竞争激烈
WARN org.redisson.RedissonLock - Thread 123 cannot acquire lock after 30000ms
// 看门狗续期失败
ERROR org.redisson.RedissonLock - Unable to update lock 456 expiration
// Redis连接问题
io.netty.channel.ConnectTimeoutException: connection timed out
使用Redisson的MultiLock:
java复制RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock multiLock = redisson.getMultiLock(lock1, lock2);
multiLock.lock();
try {
// 操作多个资源
} finally {
multiLock.unlock();
}
使用JMeter模拟不同并发下的锁性能:
code复制Thread Group
Number of Threads: 100
Ramp-Up Period: 10
Loop Count: 100
优点:
缺点:
优点:
缺点:
基于唯一索引或乐观锁:
sql复制-- 悲观锁实现
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
适用场景:
结合Redis和Zookeeper优势:
通过以下方式减少锁依赖:
将分布式锁能力下沉到Service Mesh层:
在实际生产环境中,我建议根据业务特点选择合适方案。对于大多数互联网应用,Redis分布式锁配合适当的业务防护已经足够。关键是要充分理解分布式锁的局限性,避免将其视为银弹。