Redisson分布式锁源码-可重入锁的八大机制-上(1)

分布式锁 Redisson 源码剖析

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

分布式锁完整流程图

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第1张图片

了解redisson可重入锁

 可以引入redis demo的maven工程

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第2张图片

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

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第3张图片

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.找哪台机器加锁呢?

 首先我们先看下它是怎么获取一个锁对象的,如下图:

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第4张图片

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

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

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第5张图片

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

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第6张图片

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

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第7张图片

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

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第8张图片

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

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

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第9张图片

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

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第10张图片

看到这里,关于如何通过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的呢,我们继续往下看:

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第11张图片

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

Redisson分布式锁源码-可重入锁的八大机制-上(1)_第12张图片

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

你可能感兴趣的:(redis,redis,面试,数据库)