• 分布式锁原理介绍


    分布式服务中,如果各个服务节点需要竞争资源,不能像单机多线程应用一样使用线程锁,需要由一套分布式锁机制保证节点对资源的访问。通常分布式锁以单独的服务方式实现,目前比较常用的分布式锁实现有三种: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
  • 相关阅读:
    第3、4、5讲
    .NetCore使用EF5操作Oracle,解决列自增序列绑定不生效的问题
    ASP.NET Core 之 Identity 入门(一)
    ORACLE NLS_DATE_FORMAT设置
    ORA12514遇到了怎么排查问题出在哪
    Oracle特殊字符查询语句
    ORA00821: Specified value of sga_target 3072M is too small, needs to be at least 12896M
    如何定位哪些SQL产生了大量的Redo日志
    Oracle定位对阻塞的对象或锁信息
    Oracle Undo和Redo的关系,区别及相关查询
  • 原文地址:https://www.cnblogs.com/aoyihuashao/p/9012632.html
Copyright © 2020-2023  润新知