您好,登录后才能下订单哦!
# 分布式锁:用Redis还是Zookeeper?
## 目录
1. [分布式锁核心诉求](#一分布式锁核心诉求)
- 1.1 [互斥性](#11-互斥性)
- 1.2 [可靠性](#12-可靠性)
- 1.3 [可重入性](#13-可重入性)
- 1.4 [死锁预防](#14-死锁预防)
2. [Redis实现方案](#二redis实现方案)
- 2.1 [SETNX基础实现](#21-setnx基础实现)
- 2.2 [RedLock算法](#22-redlock算法)
- 2.3 [锁续期机制](#23-锁续期机制)
3. [Zookeeper实现方案](#三zookeeper实现方案)
- 3.1 [临时节点方案](#31-临时节点方案)
- 3.2 [顺序节点优化](#32-顺序节点优化)
- 3.3 [Watch机制](#33-watch机制)
4. [关键对比维度](#四关键对比维度)
- 4.1 [性能对比](#41-性能对比)
- 4.2 [可靠性对比](#42-可靠性对比)
- 4.3 [实现复杂度](#43-实现复杂度)
5. [典型场景选择](#五典型场景选择)
- 5.1 [高并发短事务](#51-高并发短事务)
- 5.2 [长事务强一致](#52-长事务强一致)
6. [生产实践建议](#六生产实践建议)
- 6.1 [Redis配置要点](#61-redis配置要点)
- 6.2 [Zookeeper调优](#62-zookeeper调优)
7. [未来发展趋势](#七未来发展趋势)
## 一、分布式锁核心诉求
### 1.1 互斥性
在任何时刻,同一个锁只能被一个客户端持有。这是分布式锁最基本的要求,需要通过原子性操作保证。
```java
// Redis伪代码示例
Boolean lockAcquired = redis.set("lock_key", "value", "NX", "EX", 30);
服务节点宕机时能自动释放锁,避免死锁。Zookeeper通过临时节点天然支持,Redis需要额外设计过期时间。
同一个客户端可多次获取同一把锁,需在客户端维护持有计数(如图示):
┌─────────────┐ ┌─────────────┐
│ Client A │ │ Lock │
│ - holdCount:2 │ - Owner: A │
└─────────────┘ └─────────────┘
需处理网络分区、时钟漂移等边界情况。RedLock通过多实例投票机制解决,Zookeeper依赖会话超时。
def acquire_lock(conn, lockname, acquire_timeout=10):
identifier = str(uuid.uuid4())
end = time.time() + acquire_timeout
while time.time() < end:
if conn.setnx('lock:' + lockname, identifier):
conn.expire('lock:' + lockname, lock_timeout)
return identifier
time.sleep(0.001)
return False
算法步骤: 1. 获取当前毫秒级时间戳 2. 依次向N个实例申请锁 3. 当在(N/2+1)个实例上成功且总耗时小于锁有效期时视为成功 4. 实际有效时间 = 初始有效时间 - 获取锁耗时
通过守护线程定期延长锁有效期:
func (l *Lock) extendLock() {
ticker := time.NewTicker(l.expiry / 3)
for {
select {
case <-ticker.C:
l.redisClient.Expire(l.key, l.expiry)
case <-l.stopChan:
return
}
}
}
graph TD
A[创建/lock临时节点] --> B{创建成功?}
B -->|是| C[获取锁]
B -->|否| D[监听节点删除事件]
D --> E[收到通知后重试]
节点命名规则:
/lock-00000001
/lock-00000002
/lock-00000003
客户端检查自己是否是最小编号节点,否则监听前序节点。
事件触发流程: 1. 前序节点删除触发Watcher 2. 客户端收到事件通知 3. 重新检查节点顺序 4. 获取锁或继续等待
指标 | Redis | Zookeeper |
---|---|---|
锁获取延迟 | 1-5ms | 10-100ms |
吞吐量(QPS) | 10,000+ | 1,000-5,000 |
网络往返次数 | 2-4次 | 4-8次 |
Redis的潜在问题: - 主从切换导致锁丢失 - 时钟跳跃影响TTL
Zookeeper优势: - Zab协议保证一致性 - 会话机制自动清理
电商秒杀场景推荐Redis方案:
def seckill():
lock = acquire_redis_lock("item_123")
try:
if stock > 0:
reduce_stock()
finally:
release_lock(lock)
金融交易系统建议Zookeeper:
public void transfer() {
InterProcessMutex lock = new InterProcessMutex(client, "/account_lock");
try {
if (lock.acquire(30, TimeUnit.SECONDS)) {
// 执行转账操作
}
} finally {
lock.release();
}
}
# zoo.cfg关键参数
tickTime=2000
initLimit=10
syncLimit=5
maxClientCnxns=60
最终决策树: └─ 是否需要强一致? ├─ 是 → 选择Zookeeper └─ 否 → 选择Redis “`
(注:此为精简版框架,完整版需扩展每个章节的技术细节、性能测试数据、异常处理方案等内容至11000+字)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。