面试中如何回答分布式锁的实现

实现分布式锁的方法主要有四种:

  • 数据库唯一索引
  • Redis的SETNX指令
  • Redis实现的RedLock算法
  • ZooKeeper的临时有序节点

第一种是通过数据库唯一索引,通过往数据库中插入唯一索引表示获取到锁,删除该唯一索引表示释放该锁。唯一索引可以保证当前数据库中该索引是唯一的。那么就可以使用这个唯一索引来判断数据是否处于锁定状态。但是数据库唯一索引没法设置过期时间,一旦解锁失败其它进程就没法再获取锁了。另外这种方式实现的锁是不可重入的,也就是已经获得该锁的进程也必须重新获取该锁。

因此,就有了第二种方式,通过Redis的SETNX(set if not exist) 命令实现,使用setnx指令往redis数据库中插入一个键值对,如果key已经存在则插入失败,表示获取锁失败,插入成功表示成功获取锁。setnx指令和数据库唯一索引类似,可以保证数据库中同时只存在一个Key的键值对,那么这个Key的键值对就可以用来判断数据是否处于锁定状态。与数据库唯一索引不同的是,redis可以为键值对设置过期时间,这样就可以避免出现数据库中唯一索引释放锁失败的问题。

然而,Redis的setnx方式是在单例Redis上实现的分布式锁,一旦这个Redis数据库崩溃,既出现单点故障,分布式锁的服务就无法使用了。为了解决这个问题,Redis的RedLock算法和Zookeeper实现的分布式锁被提出来。

首先我们先来讲一下Redis实现的RedLock算法。RedLock算法使用了多个Redis实例来实现分布式锁,这样就可以保证单点发生故障的时候依然可用。RedLock算法尝试从N个相互独立的Redis实例中获取锁,当客户端获取锁消耗的时间小于锁的过期时间,并且从(N/2+1)实例上获取了锁,说明这个客户端获取到锁。否则,则需要到每个实例上将获取到的锁释放掉。

采用ZooKeeper实现的分布式锁主要使用的是Zookeeper中的临时有序节点。首先创建一个锁目录/lock,然后客户端需要获取锁的时候,就在锁目录/lock下创建临时且有序的子节点。之后客户端获取锁目录/lock下的子节点列表,判断自己创建的子节点是不是当前子节点列表的最小节点,如果是就表示获取到锁。否则设置一个监听器监听自己的前一个节点,获取子节点的变更通知后重复该步骤直至获取到锁。执行完业务代码后会删除掉对应的子节点表示释放锁。

你可能感兴趣的:(面试,分布式,锁)