setnx为什么不是高可用的分布式锁实现

15 分钟阅读 928 字 + 1811 词
image-20241118152151191
用setnx实现分布式锁的问题:
(1)业务超时解锁,导致并发问题。业务执行时间超过锁超时时间
(2)redis主从切换临界点问题。主从切换后,A持有的锁还没有同步到新的主节点时,B可在新主节点获取分布式锁
(3)redis集群脑裂,导致出现多个主节点。
高可用的分布式锁是分布式系统中协调资源访问的关键组件,其设计需兼顾容错性、一致性和性能。以下是常见的实现方案及其特点:

1. 基于 Redis 的分布式锁
方案
  • 单节点 Redis :使用 SET key value NX PX timeout 命令实现锁的互斥性和自动超时释放。
  • RedLock 算法 :在多个独立 Redis 节点上同时申请锁,半数以上节点成功时视为获取锁,避免单点故障。
优点
  • 性能高,适用于高并发场景。
  • RedLock 通过多节点部署提升可用性。
缺点
  • RedLock 存在争议(如时钟漂移、GC 停顿可能导致锁失效)。
  • 单节点 Redis 存在单点故障风险。
工具

2. 基于 ZooKeeper 的分布式锁
方案
  • 利用 临时顺序节点(Ephemeral Sequential Nodes) 实现锁:
    1. 客户端在锁路径下创建临时顺序节点。
    2. 判断自己是否为最小序号节点,若是则获取锁。
    3. 非最小节点监听前序节点的删除事件( Watcher 机制 )。
优点
  • 强一致性保障,避免锁冲突。
  • 临时节点自动删除,防止死锁。
  • 适合对一致性要求高的场景。
缺点
  • 写性能低于 Redis。
  • 频繁的 Watcher 通知可能带来性能开销。
工具
  • Curator (ZooKeeper 客户端库,提供现成的锁实现)。

3. 基于 etcd 的分布式锁
方案
  • 利用 etcd 的 Lease(租约) Revision 机制:
    1. 客户端创建带 Lease 的键值对(Lease 自动过期)。
    2. 通过事务(Transaction)比较 Revision 号,确保锁的互斥性。
优点
  • 基于 Raft 协议,强一致性高可用。
  • Lease 机制自动释放锁,避免死锁。
缺点
  • 性能略低于 Redis,但高于 ZooKeeper。
工具
  • etcd 官方客户端库(如 etcdv3 )。

4. 基于数据库的分布式锁
方案
  • 唯一索引/乐观锁 :通过数据库的唯一约束或版本号实现锁竞争。
  • 专用表结构 :例如记录锁名称、持有者、超时时间等字段。
优点
  • 实现简单,无需额外组件。
缺点
  • 性能差(数据库连接开销大)。
  • 需处理锁超时和死锁问题。
  • 高可用依赖数据库主从同步(可能引入延迟)。

5. 基于 Consul 的分布式锁
方案
  • 利用 Session 机制
    1. 创建 Session 并与键关联。
    2. Session 失效时自动释放锁。
优点
  • 内置服务发现和健康检查,适合微服务架构。
  • 支持 ACL 增强安全性。
缺点
  • 性能低于 Redis 和 etcd。

6. 云厂商托管服务
  • AWS DynamoDB Lock Client :基于 DynamoDB 的托管锁服务。
  • 阿里云 Distributed Lock :集成于阿里云产品中。
  • Google Cloud Memorystore (Redis) :托管 Redis 服务实现锁。
优点
  • 免运维,高可用性由云厂商保障。
  • 开箱即用。
缺点
  • 绑定特定云环境,可能产生成本。

选择建议
  1. 强一致性场景 :选 ZooKeeper 或 etcd。
  2. 高性能场景 :选 Redis(需评估 RedLock 风险)。
  3. 云原生环境 :优先使用托管服务(如 AWS/Aliyun)。
  4. 简单场景 :数据库锁(适用于低频访问)。

注意事项
  • 锁自动释放 :通过超时机制(TTL)避免死锁。
  • 可重入性 :需记录锁持有者(如线程/进程 ID)及重入次数。
  • 公平性 :ZooKeeper 的临时顺序节点天然支持公平锁。
  • 网络分区(脑裂) :需结合业务容忍度选择 CP 或 AP 模型。

以上方案各有优劣,需结合业务场景的 一致性需求 性能要求 运维成本 综合选择。