暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

目前主流的分布式锁的解决方案有哪些?(附源码)

Java领地 2021-03-03
704

概念


分布式锁是控制分布式系统之间同步访问共享资源的一种方式,在分布式系统中,常常需要协调他们的操作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。


实现方案



目前主流的有三种方式

1.基于redis

2. Redisson

3.zookeeper



一、Redis

最常见的一种方案就是使用Redis做分布式锁

使用Redis做分布式锁的思路大概是这样的:在redis中设置一个值表示加了锁,然后释放锁的时候就把这个key删除。

这种方式有几大要点:一定要用SET key value NX PX milliseconds 命令如果不用,先设置了值,再设置过期时间,这个不是原子性操作,有可能

在1.设置过期时间之前宕机,会造成死锁(key永久存在)

2.value要具有唯一性,这个是为了在解锁的时候,需要验证value是和加锁的一致才删除key。

4.这是避免了一种情况:假设A获取了锁,过期时间30s,此时35s之后,锁已经自动释放了,A去释放锁,但是此时可能B获取了锁。A客户端就不能删除B的锁了。 

使用redis做分布式锁的缺点在于:如果采用单机部署模式,会存在单点问题,只要redis故障了。加锁就不行了。


redis分布式锁实现代码参看:https://gitee.com/itgaofee/reids-soa-lock

二、主流分布式锁的解决方案 Redisson

此外,实现Redis的分布式锁,除了自己基于redis client原生api来实现之外,还可以使用开源框架:Redission

Redisson是一个企业级的开源Redis Client,也提供了分布式锁的支持

1.redisson所有指令都通过lua脚本执行,redis支持lua脚本原子性执行

2.redisson设置一个key的默认过期时间为30s,如果某个客户端持有一个锁超过了30s怎么办?

3.redisson中有一个watchdog的概念,翻译过来就是看门狗,它会在你获取锁之后,每隔10秒帮你把key的超时时间设为30s。

这样的话,就算一直持有锁也不会出现key过期了,其他线程获取到锁的问题了。

redisson的“看门狗”逻辑保证了没有死锁发生。

(如果机器宕机了,看门狗也就没了。此时就不会延长key的过期时间,到了30s之后就会自动过期了,其他线程可以获取到锁)


Redission的具体实现代码参看:https://gitee.com/itgaofee/redission-demo

三、zookeeper

常见的分布式锁实现方案里面,除了使用redis来实现之外,使用zookeeper也可以实现分布式锁。

在介绍zookeeper(下文用zk代替)实现分布式锁的机制之前,先粗略介绍一下zk是什么东西: Zookeeper是一种提供配置管理、分布式协同以及命名的中心化服务。

zk的模型是这样的:zk包含一系列的节点,叫做znode,就好像文件系统一样每个znode表示一个目录,然后znode有一些特性:

1.有序节点:假如当前有一个父节点为/lock,我们可以在这个父节点下面创建子节点;

zookeeper提供了一个可选的有序特性,例如我们可以创建子节点“/lock/node-”并且指明有序,那么zookeeper在生成子节点时会根据当前的子节点数量自动添加整数序号

也就是说,如果是第一个创建的子节点,那么生成的子节点为/lock/node-0000000000,下一个节点则为/lock/node-0000000001,依次类推。

 2.临时节点:客户端可以建立一个临时节点,在会话结束或者会话超时后,zookeeper会自动删除该节点。

 3.事件监听:在读取数据时,我们可以同时对节点设置事件监听,当节点数据或结构变化时,zookeeper会通知客户端。当前zookeeper有如下四种事件:

1.节点创建

2.节点删除

3.节点数据修改

4.子节点变更

基于以上的一些zk的特性,我们很容易得出使用zk实现分布式锁的落地方案:

1.使用zk的临时节点和有序节点,每个线程获取锁就是在zk创建一个临时有序的节点,比如在/lock/目录下。

2.创建节点成功后,获取/lock目录下的所有临时节点,再判断当前线程创建的节点是否是所有的节点的序号最小的节点

3.如果当前线程创建的节点是所有节点序号最小的节点,则认为获取锁成功。

4.如果当前线程创建的节点不是所有节点序号最小的节点,则对节点序号的前一个节点添加一个事件监听。



文章转载自Java领地,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论