栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

分布式锁 Redisson 源码剖析(1)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

分布式锁 Redisson 源码剖析(1)

分布式锁 Redisson 源码剖析
先从Redis可重入锁最简单的Demo入手,一步一图分析Redis可重入锁底层的源码,在边看源码的过程中、边画出Redis可重入锁的
核心流程图。
通过这张核心的流程图,我们可以看到一个企业级的、基于Redis分布式锁的方案是怎样的形成的,在开始分享前,
 大家先思考下如下常见的面试题:
 1、客户端线程在底层是如何实现加锁的?
 2、客户端线程是如何维持加锁的?
分布式锁完整流程图

了解redisson可重入锁
 可以引入redis demo的maven工程

如下Demo中Redis的环境采用三主三从的方式搭建一套Redis-Cluster集群环境(搭建Redis-Cluster集群的步骤这里省略,我们重点关注源码层面),Demo代码示例如下:

public class Application {

        public static void main(String[] args) throws Exception {
        //1.配置Redis-Cluster集群节点的ip和port
                Config config = new Config();
        //redis-cluster集群的ip和port
                config.useClusterServers()
                    .addNodeAddress("redis://192.168.43.159:7001")
                    .addNodeAddress("redis://192.168.43.159:7002")
                    .addNodeAddress("redis://192.168.43.159:7003")
                    .addNodeAddress("redis://192.168.43.114:7001")
                    .addNodeAddress("redis://192.168.43.114:7002")
                    .addNodeAddress("redis://192.168.43.114:7003");
        //2.通过以上配置创建Redisson的客户端
                RedissonClient redisson = Redisson.create(config);
        //3.测试Redisson可重入锁的加锁、释放锁等功能
                testRedissonSimpleLock(redisson);   
        }
        
        private static void testRedissonSimpleLock(RedissonClient redisson) throws InterruptedException {
                //1.获取key为"anyLock"的锁对象
        RLock lock = redisson.getLock("anyLock");
        
        //2.1:加锁
        lock.lock();
        //2.2:加锁时,设置尝试获取锁超时时间30s、锁超时自动释放的时间10s
                //lock.tryLock(30, 10, TimeUnit.MILLISECONDS);
       
                Thread.sleep(10 * 1000);
        
        //3.释放锁
                lock.unlock();
        }
}

demo比较简单,加锁释放锁,但是底层是如果实现加锁这一语义
1.如何位置加锁?
2.如何实现尝试获取锁超时的控制?
3.锁超时又是如何自动释放锁的呢?
4.释放锁的语义又是如何实现的?

1.找哪台机器加锁呢?
 首先我们先看下它是怎么获取一个锁对象的,如下图:

RLock对象表示一个锁对象,这里表示我们要对key为anyLock加锁,先获取一个锁对象。
首先我们可以先猜下,既然是要加锁,具体体现到Redis底层命令上肯定就是最朴素的set key value的方式啊,我们先不管它里面的其他各种复杂机制,
第一个问题肯定就是要在Redis-Cluster集群中、那么多的master节点中选择一个master节点来加锁即执行命令
此时肯定会是在redisson.getLock方法中、针对"anyLock"这个key就选择好了要对哪个master节点上加锁,然后下一步的lock.lock直接就往那台master节点上执行redis命令加锁就行了。

那下一步肯定要到redisson.getLock(“anyLock”)中的getLock方法中看下,如下图所示:

暂时我们并没有发现有锁定master节点相关的逻辑,但是通过上图我们却发现了这里redisson.getLock方法最终获取到的锁对象竟然是RedissonLock,而对Redisson的构造中只不过是各种变量的设置而已。

既然不在第一步中锁定master节点,就继续看下lock.lock()方法,如下图所示

通过对lock.lock()方法的层层追踪,来到lockInterruptibly方法中,发现这里面还算有点东西,其中发现tryAcquire方法,顾名思义、有点像要获取什么东西的意思

层层追踪后可以看到底层逻辑是通过lua脚本的方式来实现的。

当然我们看到的lua脚本只是一大串长字符串,它只不过是作为方法evalWriteAsync方法的一个参数而已,所以下一步肯定要到evalWriteAsync方法中看下了方法内部的逻辑是怎样的:

这里的getNodeSource,好像就是获取源节点、目标master的意思

看到这里,关于如何通过key锁定Redis-Cluster集群中、某一个master节点的事几乎真相大白了。

了解过一点Redis-Cluster集群基础知识应该都知道,Redis-Cluster集群中的数据分布式是通过一个一个hash slot方式来实现的,Redis-Cluster集群总共16384个hash slot,它们都会被均匀分布到所有master节点上,这里计算出key的hash slot之后,就可以通过hash slot去看一看哪个master上有这个hash slot,如果哪个master上有个这个hash slot,那么这个key当然就会落到该master节点上,执行加锁指令当然就在该master上执行。

但是这里依然还是有层问题 ,那就是具体是怎么通过key来计算出对应的hash slot的呢,我们继续往下看:

看到这里算是彻底明白了,首先会通过key计算出CRC16值,然后CRC16值对16384进行取模,进而得到hash slot,如下图所示:

Redisson客户端是如何通过key锁定Redis-Cluster集群中具体的哪个master节点,那么下一步我们就要进入正式的主题了,即可重入锁的各种加锁、释放锁等等逻辑

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/331917.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号