原创 冷饭新炒:理解Redisson中分布式锁的实现

发布时间:2021-08-03 00:19:53 浏览 968 来源:猿笔记 作者:Throwable

    1本文要分析的`R(ed)Lock`实现。下面会从基本原理、源码分析和基于`Jedis`仿实现等内容进行展开。本文分析的`Redisson`源码是`2020-01`左右`Redisson`项目的`main`分支源码。对应版本是`3.14.1`,`redlock`的基本原理其实就"光明正大地"展示在`Redis`官网的首页文档中(具体链接是。在许多环境中不同进程必须以互斥方式使用共享资源进行操作时:此试图提供一种更规范的算法来实现Redis的分布式锁,它实现了`DLM`(猜测是`DistributedLockManager`的缩写。


    #主题列表:juejin,github,smartblue,cyanosis,channing-cyan,fancy,hydrogen,condensed-night-purple,greenwillow,v-green,vue-pro,healer-readable,mk-cute,jzman,geek-black,awesome-green,qklhk-chocolate

    #投稿主题:

    theme:smartblue

    highlight:

    ##前提

    在很早很早之前,写过一篇文章介绍过`Redis`中的`redlock`的实现,但是在生产环境中,笔者所负责的项目使用的分布式锁组件一直是`Redisson`。`Redisson`是具备多种内存数据网格特性的基于`Java`编写的`Redis`客户端框架(`RedisJavaClientwithfeaturesofIn-MemoryDataGrid`),基于`Redis`的基本数据类型扩展出很多种实现的高级数据结构,具体见其官方的简介图:

    本文要分析的“r (ed)锁”的实现只是一个小模块,可以根据需要选择其他高级特性。以下将从基本原理、源代码分析和基于Jedis的模仿实现三个方面进行。本文分析的“redison”源代码是“redison”项目在‘2020-01’前后的主要‘分支’源代码,对应的版本是‘3 . 14 . 1’。

    # #基础

    Redis官网首页文档中实际显示的是‘red lock’的基本原理(具体链接是

    在许多环境中,当不同的进程必须以互斥的方式操作共享资源时,分布式锁是一种非常有用的原语。这一尝试为实现Redis的分布式锁提供了一种更标准的算法。我们提出了一个算法叫做Redlock,实现了` dlm '(猜测是` DistributedLockManager '的缩写,分布式锁管理器),我们认为比普通的单实例方法更安全。

    算法的三个核心特性(三个最低保证):

    -`Safetyproperty `(安全):互斥。确保在任何给定时间只有一个客户端可以持有锁

    -`livenessopertya '(活动` a '):无死锁。即使曾经锁定资源的客户端崩溃或网络分区异常,也要确保总是能够成功获取锁

    -` LivinessPropertyB '(活动` b '):容错。只要大多数Redis节点处于正常运行状态,客户端就可以获取和释放锁

    文件中还指出,目前的算法对于故障转移的实现还有明显的竞争条件(应该描述Redis’主从架构下的问题):

    -客户端“a”获取Redis主节点中的锁(假设锁定的资源是“x”)

    -在`Redis`主节点把`KEY`同步到`Redis`从节点之前,`Redis`主节点崩溃

    -`Redis '从节点因故障提升为主节点

    -此时客户端` b '成功获取了资源` x '的锁,但问题是资源` x '的锁之前已经被客户端` a '获取,导致并发问题。

    该算法的实现非常简单,单个Redis实例下的锁定命令如下:

    shellSET$resource_name$random_valueNXPX$ttl

    这里,` Nx '和` PX '是` SET '命令的增强参数。从' 2.6.12 '版本的' Redis '开始,' SET '命令就提供了可选的复合运算符:

    -`EX `:以秒为单位设置超时

    -`PX `:以毫秒为单位设置超时

    -` NX `:`如果不存在'的缩写。只有当' KEY '不存在时才会设置' K-V ',成功返回' 1 ',否则返回' 0 '

    -` xx `:` if exist '的缩写。只有当' KEY '存在时才会设置' K-V ',设置成功后返回' 1 ',否则返回' 0 '

    单个Redis实例下的解锁命令如下:

    shell#KEYS[1]=$resource_name#ARGV[1]=$random_valueifredis.call("get",KEYS[1])==ARGV[1]thenreturnredis.call("del",KEYS[1])elsereturn0end

    ##使用Redisson中的RLock

    使用`RLock`要先实例化`Redisson`,`Redisson`已经适配了`Redis`的哨兵、集群、普通主从和单机模式,因为笔者本地只安装了单机`Redis`,所以这里使用单机模式配置进行演示。实例化`RedissonClient`:

    java

    staticRedissonClientREDISSON;

    @BeforeClass

    publicstaticvoidbeforeClass()throwsException{

    Configconfig=newConfig();

    //单机

    config.useSingleServer()

    .setTimeout(10000)

    .setAddress("

    REDISSON=Redisson.create(config);

    ////主从

    //config.useMasterSlaveServers()

    //.setMasterAddress("主节点连接地址")

    //.setSlaveAddresses(Sets.newHashSet("从节点连接地址"));

    //REDISSON=Redisson.create(config);

    ////哨兵

    //config.useSentinelServers()

    //.setMasterName("Master名称")

    //.addSentinelAddress(newString[]{"哨兵连接地址\

作者信息

Throwable [等级:3] 公众号: Throwable
发布了 72 篇专栏 · 获得点赞 2100 · 获得阅读 133823

相关推荐 更多