码迷,mamicode.com
首页 > 其他好文 > 详细

Zookeeper实现分布式锁

时间:2019-07-16 22:49:58      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:断网   机器   方案   ali   应该   strong   try   就是   red   

1.什么是分布式锁

         为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程调度,而这种分布式协调技术的核心就是分布式锁

2.分布式锁应该具备的条件

  • 一个方法在同一时间只能被一个机器的一个线程执行。 
  • 高可用的获取锁与释放锁。
  • 高性能的获取锁与释放锁。
  • 具备可重入特性。
  • 具有锁失效机制,防止死锁。
  • 具备非阻塞特性,即没有获取锁将直接返回获取锁失败。    

3.redis实现分布式锁

       分布式锁实现的三个核心要素:加锁、解锁、锁超时。

     (1)加锁

              以双11秒杀商品为例讨论。小明对商品A进行购买操作,此时小明会使用 setnx(prodId,threadId) 命令,来对商品加锁。若此时执行命令之后返回 1 ,则说明小明加锁成功。小红在同一时间做相同操作,返回 0 ,则说明小红加锁失败。

     (2)解锁

              小明购买完商品之后要立即释放锁,提供给包括小红在内的其他购买者使用,小明此时执行del(prodId)命令,将锁释放。

     (3)锁超时

              如果小明在购买的过程中,突然网断了,获取了锁,但是没有释放锁,那之后的购买者只有等待。所以为了解决这种 死锁 的问题,小明在加锁时,必须执行 expire(prodId,30) 给锁设置一个超时时间,来保证即使没有显示的释放锁,这把锁在一定时间之后也能自动释放。

  伪代码如下:

if(setnx(prodId,threadId) == 1){
    expire(prodId,30)
    try {
        do something ......
    } finally {
        del(prodId)
    }
}

  

4.以上伪代码中存在三个致命问题

   (1) setnx 和 expire 的非原子性

        setnx 与 expire 是分两步进行操作的,如果执行完setnx操作之后,还没执行 expire 命令设置超时时间,网络断掉,此时造成死锁。

        出现这个问题的根本原因在于setnx与expire是分两步进行的,如果这两个操作时原子性的,将很好的避免这种问题,所以redis提供了解决方案:在加锁的同时,设置超时时间。

set(prodId,threadId,30

   (2) 误删操作

        小明在购买商品加锁时设置的锁超时时间时30s,但是30s之后小明仍然没有购买完成,此时redis自动释放锁,小红获得了锁,在小红购物的过程中,小明购买完成,需要删除锁,误将小红的锁删除。

        为了避免这个问题,在加锁时,小明需要将自己的线程Id当作参数传进去。

String threadId = Thread.currentThread().getId()
set(key,threadId ,30

       在解锁时先判断是不是自己的锁,如果是自己的锁,再进行删除锁的操作。

if(threadId .equals(redisClient.get(key))){
    del(key)
}

  (3)同一时间两个线程访问同一资源

         上述情况会出现同一时间两个线程访问同一资源的情况。为了尽量避免这种情况,我们可以给获得锁的线程去开启一个守护进程,当到达超时时间时,如果还没有进行完自己的操作,守护进程,给该进程加部分时间,当该线程处理完自己的任务之后,会显示的关闭掉守护进程。如果没有处理完成,断网了,守护进程会自动终止,到达超时时间时,该线程就将锁释放了。     

5.Zookeeper如何实现分布式锁

   (1)四种Zonde节点

  • 持久节点       

   默认的节点类型。创建节点的客户端与Zookeeper断开连接之后,该节点依旧存在。

  • 持久顺序节点

   在创建节点时,zookeeper会根据创建的时间将节点进行排序。

  • 临时节点

   和持久节点想相反。当创建节点的客户端与zookeeper断开连接之后,临时节点会被删除。

  • 临时顺序节点

   当创建节点时,zookeeper会根据节点的创建时间的先后顺序进行排序,当创建节点的客户端与Zookeeper断开连接之后,临时节点会被删除。

 

   (2)zookeeper 分布式锁原理

           zookeeper实现分布式锁就是应用了临时顺序节点,具体流程如下:

            ① 100名客户在极短的时间内去访问商品服务,进行购买商品的操作。

            ② 获取锁

                 zookeeper创建100个临时顺序节点,这些节点按照请求的先后顺序进行排序。排名第一的 req1 优先获取锁,排名第二 req2 的向只比他靠前一名的 req1 注册Watcher,排名第三的 req3 向 req2 注册Watcher,依次类推。

            ③ 释放锁

        ?正常执行完释放锁

            当 req1 执行完成之后,zookeper会删除该节点,排名第二的 req2 获得锁,依次类推。            

        ?客户端崩溃释放锁

           当排名第一的用户在购买时断网,因为zookeeper为其创建的是临时顺序节点,此时排名第一的用户获得的锁也将释放。排名第二的用户获得锁。

 

6.redis与zookeeper的分布式锁比较         

分布式锁 优点 缺点
zookeeper

1.有封装好的框架,容易实现

2.有等待锁的队列,大大提高抢锁效率

 

添加和删除节点性能较低
redis set与del命令性能高 实现复杂,没有等待队列,容易出现羊群效应

 

 

 

Zookeeper实现分布式锁

标签:断网   机器   方案   ali   应该   strong   try   就是   red   

原文地址:https://www.cnblogs.com/zhouzhile/p/11197958.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!