<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Redisson 分布式鎖源碼 01:可重入鎖加鎖

          共 2678字,需瀏覽 6分鐘

           ·

          2021-06-27 00:12

          前言

          相信小伙伴都是使用分布式服務(wù),那一定繞不開分布式服務(wù)中數(shù)據(jù)并發(fā)更新問題!

          單系統(tǒng)很容易想到 Java 的各種鎖,像 synchronize、ReentrantLock 等等等,那分布式系統(tǒng)如何處理?

          當(dāng)然是使用分布式鎖。

          如果小伙伴不知道什么是分布式鎖,那推薦看看石杉老師的突擊課或者在網(wǎng)上搜一搜相關(guān)資料。

          當(dāng)使用 Redis 作為分布式鎖時(shí),當(dāng)前使用較多的框架就是 Redisson。

          當(dāng)然 Redisson 也不僅僅只能當(dāng)做鎖來使用,也有很多其他的功能,小伙伴們可以看一看官方文檔,自己多動手實(shí)踐一下。

          下面就開始記錄 Redisson 的相關(guān)筆記!錯(cuò)誤之處,歡迎指正。????

          1

          環(huán)境配置

          • 本地環(huán)境搭建的偽集群:
          • redisson 3.15.6

          不同版本可能會有所不同,但是核心思想不會發(fā)生太大變化,如果變化很大,希望可以留言。

          <dependency>
              <groupId>org.redisson</groupId>
              <artifactId>redisson</artifactId>
              <version>3.15.6</version>
          </dependency>
          • 項(xiàng)目準(zhǔn)備

          一個(gè)簡單的 maven 項(xiàng)目,只需要一個(gè) Main 方法即可。

          2

          可重入鎖加鎖

          在 lock.lock() 斷點(diǎn),作為源碼入口。

          默認(rèn)加鎖,什么參數(shù)也沒有傳遞。但是這里會設(shè)置 leaseTime = -1。這個(gè) leaseTime 的含義是加鎖的時(shí)間

          剩下的一路挺進(jìn)即可。

          在調(diào)用 tryAcquire 方法之前,多了一個(gè)參數(shù) threadId,是當(dāng)前線程的 id,long 型正數(shù)。

          異步加鎖

          直接來到 tryAcquireAsync 異步加鎖方法。

          tryAcquireAsync

          前面已經(jīng)說了 leaseTime 是 -1,所以這里會走到下面的方法中。

          至此幾個(gè)參數(shù)已經(jīng)清楚:

          1. waitTime:-1;
          2. internalLockLeaseTime:使用默認(rèn)時(shí)間 30000 毫秒;
          3. TimeUnit.MILLISECONDS:單位毫秒;
          4. threadId:線程 id;
          5. RedisCommands.EVAL_LONG:eval。

          Redis eval 命令的相關(guān)文檔可以閱讀:https://redis.io/commands/eval

          加鎖邏輯

          真正的加鎖,其實(shí)就是這么一段 lua 腳本。

          先說明一下 lua 腳本的參數(shù)信息:

          1. KEYS[1]:getRawName(),加鎖的 key ,比如 anyLock;
          2. ARGV[1]:unit.toMillis(leaseTime),鎖的毫秒時(shí)間,比如 30000;
          3. ARGV[2]:getLockName(threadId),是 UUID 和線程 id 拼接起來的字符串,比如 931573de-903e-42fd-baa7-428ebb7eda80:1。

          因?yàn)槭褂玫氖?lua 腳本,可以保證這一塊 lua 腳本的原子性

          首次加鎖分析:

          1. exists 命令判斷 redis anyLock 是否存在;
          2. 不存在,使用 hincrby 命令,創(chuàng)建 anyLock 數(shù)據(jù);
          3. 對 anyLock 設(shè)置過期時(shí)間。

          加鎖后 Redis 內(nèi)的數(shù)據(jù)格式是:

          關(guān)于 Redis 的 Hash 數(shù)據(jù)結(jié)構(gòu)可以閱讀:https://redis.io/topics/data-types#hashes

          抽象一點(diǎn)可以理解為 anyLock 下面掛著一個(gè) K-V 結(jié)構(gòu)的數(shù)據(jù):

          "anyLock":{
              "f400aad5-4b1f-4246-a81e-80c2717c3afb:1":"1"
          }

          執(zhí)行腳本

          后續(xù)的內(nèi)容就是進(jìn)行請求執(zhí)行 lua 腳本,唯一需要注意的地方就是有個(gè)哈希槽路由。

          這塊代碼是在 CommandAsyncService#evalWriteAsync 方法處調(diào)用的,是為了獲取一個(gè) NodeSource。

          當(dāng)然這個(gè) NodeSource 里面只存放了一個(gè) slot(哈希槽值)。

          這個(gè) slot 值是對加鎖的 key 使用 CRC16 算法計(jì)算出來的。

          // MAX_SLOT 默認(rèn) 16384
          int result = CRC16.crc16(key.getBytes()) % MAX_SLOT;

          這塊計(jì)算一個(gè) slot 到底有什么用呢?

          繼續(xù)追蹤!

          BaseRedisBatchExecutor#addBatchCommandData 在這里會從 source 里面獲取到 solt,然后獲得 MasterSlaveEntry。

          大概可以理解為這里是獲取到這個(gè) Redis key 對應(yīng)的節(jié)點(diǎn)。

          可重入

          既然是可重入鎖,這塊是支持可重入的,來看下可重入是如何保證的。

          1. exists 命令判斷 redis key field 是否存在;
          2. 存在 則通過 hincrby 命令對 key 的 field 對應(yīng) value 自增;
          3. 為當(dāng)前 redis key 設(shè)置過期時(shí)間。

          加鎖互斥

          上面已經(jīng)驗(yàn)證了兩種情況:

          1. redis key 不存在;
          2. redis key 和 key 的 field 存在。

          剩下的情況就是 key 存在的情況下,但是 field 不存在。

          要知道 key 的 field 放的是 UUID:ThreadId,說明加鎖的不是當(dāng)前線程。這時(shí)候直接返回當(dāng)前鎖的剩余時(shí)間。

          3

          總結(jié)

          本文主要介紹了 Redisson 可重入鎖的加鎖、鎖重入、鎖互斥邏輯。

          核心重點(diǎn)在 lua 腳本。同時(shí)需要理解 Redis 的 Hash 數(shù)據(jù)結(jié)構(gòu)。

          同時(shí)需要記住,在未指定加鎖時(shí)間時(shí),默認(rèn)使用的是 30s。

          最后,一張圖介紹本文加鎖邏輯。

          - <End /> -




          歷史文章 | 相關(guān)推薦




          瀏覽 35
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操中国老女人逼视频 | 一级黄色大片 | 大鸡巴网免费视频在线 | 亚洲插逼视频 | 国产一级黄片在线播放 |