基于 ZooKeeper 的分布式锁

基于配置中心的分布式锁

这里以 ZooKeeper 为例,ZooKeeper 基于树形数据存储结构实现分布式锁,来解决多个进程同时访问同一临界资源时,数据的一致性问题。ZooKeeper 的树形数据存储结构主要由 4 种节点构成:

  • 持久节点。这是默认的节点类型,一直存在于 ZooKeeper 中。
  • 持久顺序节点。也就是说,在创建节点时,ZooKeeper 根据节点创建的时间顺序对节点 进行编号。
  • 临时节点。与持久节点不同,当客户端与 ZooKeeper 断开连接后,该进程创建的临时节 点就会被删除。
  • 临时顺序节点,就是按时间顺序编号的临时节点。

根据它们的特征,ZooKeeper 基于临时顺序节点实现了分布锁。还是以电商售卖吹风机的场景为例。假设用户 A、B、C 同时在 11 月 11 日的零点整提交 了购买吹风机的请求,ZooKeeper 会采用如下方法来实现分布式锁:

  • 在与该方法对应的持久节点 shared_lock 的目录下,为每个进程创建一个临时顺序节 点。如下图所示,吹风机就是一个拥有 shared_lock 的目录,当有人买吹风机时,会为 他创建一个临时顺序节点。
  • 每个进程获取 shared_lock 目录下的所有临时节点列表,注册子节点变更的 Watcher,并监听节点。
  • 每个节点确定自己的编号是否是 shared_lock 下所有子节点中最小的,若最小,则获得 锁。例如,用户 A 的订单最先到服务器,因此创建了编号为 1 的临时顺序节点 LockNode1。该节点的编号是持久节点目录下最小的,因此获取到分布式锁,可以访 问临界资源,从而可以购买吹风机。
  • 若本进程对应的临时节点编号不是最小的,则分为两种情况:a. 本进程为读请求,如果比自己序号小的节点中有写请求,则等待; b. 本进程为写请求,如果比自己序号小的节点中有读请求,则等待。

例如,用户 B 也想要买吹风机,但在他之前,用户 C 想看看吹风机的库存量。因此,用户 B 只能等用户 A 买完吹风机、用户 C 查询完库存量后,才能购买吹风机。