Zookeeper 分布式锁

Zookeeper 分布式锁,第1张

Zookeeper 分布式锁

在分布式场景中,采用传统的锁并不能解决跨进程并发的问题,所以需要引入一个分布式锁,来解决多个节点之间的访问控制

一、Zookeeper如何解决分布式锁

基于Zookeeper的两种特性来实现分布式锁:

  • 第一种,使用唯一节点特性实现分布式锁
  • 第二种,使用有序节点实现分布式锁

二、使用唯一节点特性实现分布式锁

多个应用程序去抢占锁资源时,只需要在指定节点上创建一个 /Lock 节点,由于Zookeeper中节点的唯一性特性,使得只会有一个用户成功创建 /Lock 节点,剩
下没有创建成功的用户表示竞争锁失败。

问题:惊群效应

“惊群效应”,简单来说就是如果存在许多的客户端在等待获取锁,当成功获取到锁的进程释放该节点后,所有处于等待状态的客户端都会被唤醒(等待的方式自然是使用Watcher机制来监听/lock节点的删除事件),这个时候zookeeper在短时间内发送大量子节点变更事件给所有待获取锁的客户端,然后实际情况是只会有一个客户端获得锁。如果在集群规模比较大的情况下,会对zookeeper服务器的性能产生比较的影响。

三:使用有序节点实现分布式锁

因此为了解决惊群效应,可以采用Zookeeper的有序节点特性来实现分布式锁。

每个客户端都往指定的节点下注册一个临时有序节点,越早创建的节点,节点的顺序编
号就越小,那么我们可以判断子节点中最小的节点设置为获得锁。如果自己的节点不是所有子节点中最小的,意味着还没有获得锁。

不同于第一种方式性在于,每个节点只需要监听比自己小的前一个节点,当比自己小的节点删除以后,客户端会收到watcher事件,此时再次判断自己的节点是不是所有子节点中最小的,如果是则获得锁,否则就不断重复这个过程,这样就不会导致羊群效应,因为每个客户端只需要监控前一个节点。

有序节点实现分布式锁的流程

四:Curator实现分布式锁

curator对于锁这块做了一些封装,curator提供了InterProcessMutex 这样一个api。

具体的使用方法如下:

1、引入pom

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.2.0</version>
</dependency>

2、CuratorConfig

@Configuration
public class CuratorConfig {
@Bean
public CuratorFramework curatorFramework(){
CuratorFramework curatorFramework=CuratorFrameworkFactory
.builder()
.connectString("127.0.0.1:2181")
.sessionTimeoutMs(15000)
.connectionTimeoutMs(20000)
.retryPolicy(new ExponentialBackoffRetry(1000,10))
.build();
curatorFramework.start();
return curatorFramework;
}
}
 

3、 Controller,使用锁机制

@Scope(scopeName = "prototype")
@RestController
@RequestMapping("/goods-stock")
public class GoodsStockController {
@Autowired
IGoodsStockService goodsStockService;
@Autowired
CuratorFramework curatorFramework;
@GetMapping("{goodsNo}")
public String purchase(@PathVariable("goodsNo")Integer goodsNo) throws
Exception {
QueryWrapper<GoodsStock> queryWrapper=new QueryWrapper<>();
queryWrapper.eq("goods_no",goodsNo);
InterProcessMutex lock=new
InterProcessMutex(curatorFramework,"/Lock");
try {
lock.acquire(); //抢占锁(阻塞)
GoodsStock goodsStock=goodsStockService.getOne(queryWrapper);
Thread.sleep(new Random().nextInt(1000));
if(goodsStock==null){
return "指定商品不存在";
}
if(goodsStock.getStock().intValue()<1){
return "库存不够";
}
goodsStock.setStock(goodsStock.getStock() - 1);
boolean res = goodsStockService.updateById(goodsStock);
if (res) {
return "抢购书籍:" + goodsNo + "成功";
}
return "抢购失败";
}finally {
lock.release(); //释放锁
}
}
}

注:前面已经理解的Zookeeper实现分布式锁的原理,以及基于Curator完成了分布式锁的使用, Curator就是基于代码实现了这一过程。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/759733.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-01
下一篇 2022-05-01

发表评论

登录后才能评论

评论列表(0条)

保存