1. 分布式锁概述
1.1 什么是分布式锁?
分布式锁是一种在分布式系统中实现资源互斥访问的机制,确保多个进程或线程在访问共享资源时不会发生冲突。其核心特性包括:
-
互斥性:同一时刻只有一个客户端能持有锁。
-
无死锁:即使持有锁的客户端崩溃,锁最终也会被释放。
-
容错性:部分节点故障不影响锁的正常使用。
1.2 为什么需要分布式锁?
在分布式系统中,传统的单机锁(如Java的synchronized
或ReentrantLock
)无法跨JVM生效。例如:
-
电商库存扣减:防止超卖。
-
订单处理:避免重复下单。
-
定时任务调度:确保任务仅执行一次。
2. 分布式锁的实现方案
2.1 基于数据库的实现
2.1.1 乐观锁(CAS)
UPDATE inventory SET stock = stock - 1
WHERE product_id = 100 AND stock >= 1;
缺点:高并发下大量失败重试。
2.1.2 悲观锁(SELECT FOR UPDATE)
@Transactional
public void deductStock(Long productId) {
Inventory inventory = em.createQuery(
"SELECT i FROM Inventory i WHERE i.productId = :pid FOR UPDATE",
Inventory.class)
.setParameter("pid", productId)
.getSingleResult();
inventory.setStock(inventory.getStock() - 1);
}
缺点:数据库性能瓶颈。
2.2 基于Redis的实现
2.2.1 基础版(SETNX + EXPIRE)
public boolean tryLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
return "OK".equals(result);
}
问题:非原子性操作可能导致死锁。
2.2.2 增强版(Lua脚本)
if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then
return redis.call('pexpire', KEYS[1], ARGV[2])
else
return 0
end
优点:保证原子性。
2.3 基于ZooKeeper的实现
public class ZkDistributedLock {
private final InterProcessMutex mutex;
public boolean tryLock(long time, TimeUnit unit) {
return mutex.acquire(time, unit);
}
}
特点:基于临时顺序节点,强一致但性能较低。
3. Redisson高级特性解析
3.1 看门狗机制
// 自动续期(默认30秒,每10秒续一次)
RLock lock = redisson.getLock("myLock");
lock.lock(); // 无需指定超时时间
源码逻辑:
-
启动守护线程定期检查锁状态。
-
若客户端仍活跃,重置锁过期时间。
3.2 红锁(RedLock)算法
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
redLock.lock();
流程:
-
向N个独立Redis节点申请锁。
-
当多数节点(N/2+1)获取成功时,认为加锁成功。
4. 性能优化方案
4.1 锁分段技术
// 将库存ID哈希到16个分段
public RLock getSegmentLock(Long productId) {
int segment = productId.hashCode() & 0xF;
return redisson.getLock("stock_lock_" + segment);
}
效果:并发能力提升16倍。
4.2 热点数据优化
4.2.1 本地缓存+版本号
@Cacheable(value = "inventory", key = "#productId")
public Inventory getInventory(Long productId) {
return inventoryRepo.findById(productId);
}
4.2.2 熔断降级
@HystrixCommand(fallbackMethod = "fallbackDeduct")
public void deductStock(Long productId) {
// 尝试获取分布式锁
}
5. 生产环境监控
5.1 关键指标
指标名称 | 计算方式 | 报警阈值 |
---|---|---|
锁等待时间 | 获取锁结束时间-开始时间 | P99 > 500ms |
锁持有时间 | 释放锁时间-获取锁时间 | 平均值 > 1s |
锁竞争失败率 | 失败次数/总尝试次数 | > 20% |
5.2 Prometheus配置
- job_name: 'distributed_lock'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['lock-service:8080']
6. 选型建议
6.1 方案对比
方案 | 一致性 | 性能 | 实现复杂度 | 适用场景 |
---|---|---|---|---|
Redis SETNX | 最终 | 高 | 低 | 允许短暂不一致 |
Redisson | 强 | 中高 | 中 | 金融交易 |
ZooKeeper | 强 | 低 | 高 | 配置管理 |
数据库行锁 | 强 | 最低 | 低 | 低并发事务 |
6.2 决策树
7. 未来演进
7.1 协程支持
suspend fun acquireLock() {
while (!tryLock()) {
delay(10) // 非阻塞挂起
}
}
7.2 自动弹性扩缩
# 根据QPS动态调整锁分段数
def adjust_segments(current_qps):
return max(16, math.ceil(current_qps / 1000))
附录:扩展阅读