分布式锁redis、zookeeper实现思路

其实秒杀类场景最主要的是执行秒杀操作要单线程的,提到单线程,肯定会想到synchronized关键字,但是他有两个致命缺点:1、无法做到细粒度控制,2、只适合单点不适用集群。所以大多数项目只能采用分布式锁的实现方式,分布式锁主要有基于缓存如redis、基于zookeeper、基于数据库的实现。

下面分别介绍基于redis和zookeeper的分布式锁实现。

首先来介绍redis分布式锁的实现:

redis有两个命令:

1、SETNS key value:这个命令是当key不存在的时候,SETNS相当于SET,将key value 插入,返回1,当key存在,则什么都不做,返回0。

2、GETSET key value:获取key的value 并将新的value插入进去,相当于先get再set。

redis的key可以是商品ID之类的,value就是用当前时间+超时时间的一个时间戳,好了,二话不说上代码

 

代码中33行就用到了redis的SETNS的特性去加锁,为了避免出现死锁,加了38行来判断锁是否过期。41行的代码解释一下,假设有两个线程同时进入了lock方法,并且都进入了40行,此时第一个进程执行40行代码后获取到了原来的value值并且set进去了自己的value值,然后执行41行,oldvalue与redisValue相等,则获取锁,第二个进程执行40行,这个时候他拿出来的值是第一个进程set进去的值,所以他的oldValue就和redisValue不相等了,所以获取不到锁。

接下来就是基于zookeeper的分布式锁了

zookeeper节点有四种类型:

PERSISTENT  持久节点

PERSISTENT_SEQUENTIAL  持久顺序节点

EPHEMERAL  临时节点

EPHEMERAL_SEQUENTIAL   临时顺序节点

zookeeper分布式锁的原理其实很简单,首先zookeeper创建个PERSISTENT持久节点,然后每个要获得锁的线程都会在这个节点下创建个临时顺序节点,然后规定节点最小的那个获得锁,所以每个线程首先都会判断自己是不是节点序号最小的那个,如果是则获取锁,如果不是则监听比自己小的上一个节点,如果上一个节点不存在了,然后会再一次判断自己是不是序号最小的那个节点,是则获得锁,不是重复上述动作。

这里什么要创建临时顺序节点呢,因为要避免羊群效应,所谓羊群效应就是每个节点挂掉,所有节点都去监听,然后做出反映,这样会给服务器带来巨大压力,所以有了临时顺序节点,当一个节点挂掉只有监听这个节点的才会做出反映。

还是上代码演示zookeeper的分布式锁。

首先我在客户端首先创建了个持久节点lock

这里定义了一个锁的接口,很简单,一个加锁方法,一个解锁

 

定义一个抽象类实现Lock接口,这里指定zookeeper的host和port,并且实例化一个zkClient

 

这个抽象类实现了lock方法,首先尝试着去加锁,如果不成功就去等待锁,然后再重复,下面就是tryLock和waitForLock的实现

tryLock这里就是创建临时顺序节点然后判断是否是第一个,如果不是就把前一个节点赋给beforePath

 
 

waitForLock,这里先是new了一个节点监听器,监听上一个节点。

 

作者:catalina_
链接:https://www.jianshu.com/p/2d22df6eccf8
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

猜你喜欢

转载自www.cnblogs.com/huzefeng/p/11164247.html