zoukankan      html  css  js  c++  java
  • 分布式锁原理介绍

    分布式服务中,如果各个服务节点需要竞争资源,不能像单机多线程应用一样使用线程锁,需要由一套分布式锁机制保证节点对资源的访问。通常分布式锁以单独的服务方式实现,目前比较常用的分布式锁实现有三种:zookeeper实现、redis实现和memcache实现。后两者本质上相同。

    一个需要用到分布式锁的典型场景是,分布式服务的各个节点注册到用于服务发现的服务器,注册后的节点需要是有序的。此时就需要有锁来保证各个节点按先后顺序注册。

    下面分别介绍三种实现方式的原理。

    一、zookeeper
    1、实现原理
    基于zookeeper临时顺序节点实现分布式锁,其大致思想为:
    (a)每个客户端对某个功能加锁时,在zookeeper上的与该功能对应的指定节点的目录下,生成一个唯一的临时顺序节点;
    (b)所有临时顺序节点中序号最小的,即为当前持有锁的节点;
    (c)释放锁时,将自己注册的这个临时顺序节点删除即可。

    以上实现方法,可以在客户端监听注册节点目录的变化,当发生节点删除时通知各个客户端检查是否自己持有了锁。
    如果集群规模很大,这样做可能引起羊群效应,此时可以优化为客户端监听注册节点目录下,比自己节点小的节点变化。当比自己小的节点都删除了,那么自己就持有了锁。
    --具体看 https://blog.csdn.net/xiaoliuliu2050/article/details/51226237

    2、优点
    锁安全性高,zookeeper数据不易丢失

    3、缺点
    性能开销比较高。因为其需要动态产生、删除临时顺序节点,还需要监听节点变化来实现锁功能。

    4、开源实现
    curator开源库中提供了分布式锁的实现,python库Kazoo中也可直接通过kazoo.recipe中的lock.Lock,调用acquire方法实现。
    menagerie基于Zookeeper实现了java.util.concurrent包的一个分布式版本。

    二、redis分布式锁
    1、实现原理
    利用redis中的set命令来实现分布式锁。
     
    从 Redis 2.6.12 版本开始,set可以使用下列参数:
    SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]
     
      EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
      PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
      NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
      XX :只在键已经存在时,才对键进行设置操作。

    返回值:
      SET 在设置操作成功完成时,才返回 OK 。
      如果设置了 NX 或者 XX ,但因为条件没达到而造成设置操作未执行,那么命令返回空批量回复(NULL Bulk Reply)。

    命令:
    > SET key value EX ttl NX

    大致思想是:
    (a)SET lock currentTime+expireTime EX 600 NX,使用set设置lock值,并设置过期时间为600秒,如果成功,则获取锁;
    (b)获取锁后,如果该节点掉线,则到过期时间ock值自动失效;
    (c)释放锁时,使用del删除lock键值;

    使用redis单机来做分布式锁服务,可能会出现单点问题,导致服务可用性差,因此在服务稳定性要求高的场合,官方建议使用redis集群(例如5台,成功请求锁超过3台就认为获取锁),来实现redis分布式锁。详见RedLock。

    2、优点
    性能高,redis可持久化,也能保证数据不易丢失;
    redis集群方式提高稳定性。

    3、缺点
    使用redis主从切换时可能丢失部分数据。

    4、开源实现
    python版本的开源实现:python-redis-lock。


    三、memcached分布式锁
    1、实现原理
    利用memcached的add函数实现分布式锁。
    add和set的区别在于:如果多线程并发set,则每个set都会成功,但最后存储的值以最后的set的线程为准。而add的话则相反,add会添加第一个到达的值,并返回true,后续的添加则都会返回false。利用该点即可很轻松地实现分布式锁。

    2、优点
    因为是全内存存储,并发高效。

    3、缺点
    (1)memcached采用列入LRU置换策略,所以如果内存不够,可能导致缓存中的锁信息丢失。
    (2)memcached无法持久化,一旦重启,将导致信息丢失。

    4、开源实现
    待查。
     
     
     
    参考
    http://surlymo.iteye.com/blog/2082684
    http://www.cnblogs.com/moonandstar08/p/5705619.html

    zookeeper实现方式
    http://graduter.iteye.com/blog/2024190
    http://surlymo.iteye.com/blog/2082684
    http://blog.csdn.net/xiaoliuliu2050/article/details/51226237

    redis实现方式
    https://redis.io/topics/distlock
    http://blog.csdn.net/daiyudong2020/article/details/51760648
    http://www.weizijun.cn/2016/03/17/聊一聊分布式锁的设计/
    http://blog.csdn.net/u013970991/article/details/52722680
  • 相关阅读:
    HDU 2433 Travel (最短路,BFS,变形)
    HDU 2544 最短路 (最短路,spfa)
    HDU 2063 过山车 (最大匹配,匈牙利算法)
    HDU 1150 Machine Schedule (最小覆盖,匈牙利算法)
    290 Word Pattern 单词模式
    289 Game of Life 生命的游戏
    287 Find the Duplicate Number 寻找重复数
    283 Move Zeroes 移动零
    282 Expression Add Operators 给表达式添加运算符
    279 Perfect Squares 完美平方数
  • 原文地址:https://www.cnblogs.com/aoyihuashao/p/9012632.html
Copyright © 2011-2022 走看看