# 分布式锁:用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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。