Java架构-阿里架构师手把手带你实现基于Zookeeper、Redis的分布式锁

在分布式系统中,分布式锁是为了解决多实例之间的同步问题。例如master选举,可以获取分布式锁的就是master,获取失败的就是slave。又或者可以获取锁的实例可以完成特定的操做。程序员

在分布式系统中,分布式锁是为了解决多实例之间的同步问题。例如master选举,可以获取分布式锁的就是master,获取失败的就是slave。又或者可以获取锁的实例可以完成特定的操做。redis

目前比较经常使用的分布式锁实现有两种,基于zookeeper实现和基于redis实现。zookeeper和redis也是生产环境中常常用到的第三方组件。下面我会分析它们的实现原理。算法

小编最近将收集的Java程序员进阶架构师的资料作了一些整理,资料适合1-5年的Java开发者,须要的朋友能够领取 https://w.url.cn/s/AnCuiWo安全

分布式锁实现要求网络

实现一个分布式锁至少要知足下面三点要求:架构

互斥,在任什么时候候同一个锁只能由一个客户端持有。dom

不会死锁,就算持有的客户端异常崩溃也不会影响后续客户端加锁。异步

谁加锁谁解锁,加锁和解锁都必须是同一个客户端。分布式

zookeeper分布式锁性能

在讲解zookeeper的分布式锁以前有两个概念须要明确:

临时节点:生命周期和连接周期一致。例如客户端连接A建立了临时节点NodeA,若是连接A关闭或者网络异常断开,那么NodeA也会跟着消失。

顺序节点:节点名称按照顺序从小到大建立,例如先建立了000000001,那么接着建立的节点就会分配000000002。

zookeeper的分布式锁实现原理就是利用临时顺序节点,大概流程为:

每一个客户端对某个功能加锁时,在zookeeper指定目录下生成一个惟一的临时顺序节点。

全部临时节点中序号最小的节点即为当前锁的持有者。

释放锁时将本身持有的临时节点删除便可。

例如,对于加锁过程,全部的客户端都在/lock目录下面建立临时节点,若是发现本身建立的临时节点是/lock目录中最小的节点,那么就获取锁成功,不然就watch比本身小的节点中的最大节点。

监控比本身小的节点中的最大节点是为了不“惊群”效应,避免一个锁释放把全部等待的客户端唤醒,可是只有一个客户端能获取锁。

对于释放锁,只须要把本身建立的临时顺序节点删除便可。整个过程流程图以下: file

优势:锁安全性高,zookeeper数据不易丢失。用户使用简单。

缺点:性能消耗比较高。由于须要动态产生和删除临时节点,当集群负载比较高时临时节点消失会有时间差(通常在一分钟范围内)。

redis分布式锁

redis的分布式锁实现比zookeeper分布式锁实现复杂,也分为redis单实例和多实例(master-master)实现方式。

须要特别指出的是redis若是是master-slave这种结构部署时,获取和释放锁都只能向master请求,和单实例的实现原理基本同样,不然主从切换时会出现多人拿到同一把锁的状况。

例如:

客户端A在master拿到了锁。

master节点在把A建立的key写入slave以前宕机了。(主从同步是异步操做)

slave变成了master节点。

B也获得了和A还持有的相同的锁,由于slave尚未A持有锁的信息。

redis单实例实现方案

经过下面命令得到锁:

SET resource_name my_random_value NX PX 30000

这个命令的做用是只有这个key不存在时才会设置这个key的值(NX的做用,即not exist),超时时间设置为30000毫秒(PX的做用),这个key的值设置为my_random_value。这个值必须在全部获取锁请求的客户端里面保持惟一。

key值的超时时间,也叫作“锁有效时间”。这是锁的自动释放时间。

这套实现方案在非分布式的、单点的、保证永不宕机的环境是适用的。

redis集群实现方案(Redlock算法)

在分布式版本的算法里咱们假设有N个redis master节点,这些节点彻底独立,不用任何的复制或者分布式协调算法来同步数据。

这里假设N=5,一个客户端获取锁的过程以下:

获取当前以毫秒为单位的时间。

轮询用相同的key在N个节点上面请求锁。(每一个请求的超时时间设置的短一些,为了一个master节点不用时,快速请求下一个master)。

若是在超过一半master节点上面成功获取锁(这里是3个),客户端计算第二步请求锁花费的时间,若是小于锁释放时间,则认为获取锁成功。

若是锁获取成功了,那么如今 锁自动释放时间=最初锁释放时间-请求锁花费的时间

若是获取锁失败了(成功的锁不超过master数量的通常 或者 请求耗时>锁释放时间),那么客户端都会在每一个master节点上面释放锁。

获取锁成功的节点数须要超过master节点数量的一半才认为是获取锁成功的思路应该是借鉴了zookeeper的paxos算法。

还有一个须要指出的点是,当一个客户端获取失败时应该随时延时后再进行重试,避免多个客户端同时重试又同时失败。

优势:性能高

缺点:单实例会有单点问题,多实例主从切换会致使数据丢失,master-master集群模式实现复杂。

看大佬给你讲解基于Zookeeper、Redis的分布式锁

file

file

相关文章
相关标签/搜索