分布式技术专题-分布式锁实现原理(3)分布式场景下的分布式锁原理分析(总结篇)

181 阅读3分钟

「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。

分布式锁的前提介绍

因为分布式系统之间是不同进程的,单机版的锁无法满足要求。所以我们可以借助中间件Redis的setnx()命令实现分布式锁。setnx()命令只会对不存在的key设值,返回1代表获取锁成功。

分布式锁的基础要点

分布式锁的特性是排他、避免死锁、高可用。

分布式锁的实现原理

分布式锁的实现可以通过数据库的乐观锁(通过版本号)或者悲观锁(通过for update)、Redis的setnx()命令、Zookeeper(在某个持久节点添加临时有序节点,判断当前节点是否是序列中最小的节点,如果不是则监听比当前节点还要小的节点。如果是,获取锁成功。当被监听的节点释放了锁(也就是被删除),会通知当前节点。然后当前节点再尝试获取锁,如此反复)。

Zookeeper的分布式锁原理

  • Zookeeper(在某个持久节点添加临时有序节点,判断当前节点是否是序列中最小的节点,如果不是则监听比当前节点还要小的节点。如果是,获取锁成功。
  • 当被监听的节点释放了锁(也就是被删除),会通知当前节点。然后当前节点再尝试获取锁,如此反复)

Redis的分布式锁原理

  • Redis对存在的key设值,会返回0代表获取锁失败。这里的value是System.currentTimeMillis() (获取锁的时间)+锁持有的时间。

  • 这里设置锁持有的时间是200ms,实际业务执行的时间远比这200ms要多的多,持有锁的客户端应该检查锁是否过期,保证锁在释放之前不会过期。因为客户端故障的情况可能是很复杂的。

分布式案例分析
  • 比如现在有A,B俩个客户端。A客户端获取了锁,执行业务中做了骚操作导致阻塞了很久,时间应该远远超过200ms,当A客户端从阻塞状态下恢复继续执行业务代码时,A客户端持有的锁由于过期已经被其他客户端占有。这时候A客户端执行释放锁的操作,那么有可能释放掉其他客户端的锁。

  • 这里设置的客户端等待锁的时间是200ms。这里通过轮询的方式去让客户端获取锁。如果客户端在200ms之内没有锁的话,直接返回false。实际场景要设置合适的客户端等待锁的时间,避免消耗CPU资源。

数据库的分布式锁原理

如果获取锁的逻辑只有这三行代码的话,会造成死循环,明显不符合分布式锁的特性。 我们知道分布式锁的特性是排他、避免死锁、高可用。分布式锁的实现可以通过数据库的乐观锁(通过版本号)或者悲观锁(通过for update),高可用:支持master-master、master-slave模式,master-master模式是一个作为主负责读写,另外一个作为standby提供灾备,maser-slave是一个作为主提供写操作,其他几个节点作为读操作,支持读写分离。

对于节点主备失效检测和切换,可以采用HA软件,当然也可以从更细粒度定制的角度,采用zookeeper作为集群的协调服务。