<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 分布式鎖源碼 09:RedLock 紅鎖的故事

          共 3733字,需瀏覽 8分鐘

           ·

          2021-07-07 13:18

          前言

          RedLock 紅鎖,是分布式鎖中必須要了解的一個(gè)概念。

          所以本文會先介紹什么是 RedLock,當(dāng)大家對 RedLock 有一個(gè)基本的了解。然后再看 Redisson 中是如何實(shí)現(xiàn) RedLock 的。

          在文章開頭先說明 Redisson RedLock 建議不要使用!?。?/strong>

          1

          什么是 RedLock?

          RedLock[1],這塊可以從網(wǎng)上搜到很多資料,本文也簡單介紹下,當(dāng)做掃盲。

          單實(shí)例加鎖

          SET resource_name my_random_value NX PX 30000

          對于單實(shí)例 Redis 只需要使用這個(gè)命令即可。

          • NX:僅在不存在 key 的時(shí)候才能被執(zhí)行成功;
          • PX:失效時(shí)間,傳入 30000,就是 30s 后自動釋放鎖;
          • my_random_value:就是隨機(jī)值,可以是線程號之類的。主要是為了更安全的釋放鎖,釋放鎖的時(shí)候使用腳本告訴 Redis: 只有 key 存在并且存儲的值和我指定的值一樣才能刪除成功。

          可以通過以下 Lua 腳本實(shí)現(xiàn)鎖釋放:

          if redis.call("get",KEYS[1]) == ARGV[1then
              return redis.call("del",KEYS[1])
          else
              return 0
          end

          為什么要設(shè)置隨機(jī)值?

          主要是為了防止鎖被其他客戶端刪除。有這么一種情況:

          1. 客戶端 A 獲得了鎖,還沒有執(zhí)行結(jié)束,但是鎖超時(shí)自動釋放了;
          2. 客戶端 B 此時(shí)過來,是可以獲得鎖的,加鎖成功;
          3. 此時(shí),客戶端 A 執(zhí)行結(jié)束了,要去釋放鎖,如果不對比隨機(jī)值,就會把客戶端 B 的鎖給釋放了。

          當(dāng)然前面看過 Redisson 的處理,這個(gè) my_random_value 存放的是 UUID:ThreadId 組合成的一個(gè)類似 931573de-903e-42fd-baa7-428ebb7eda80:1 的字符串。

          當(dāng)鎖遇到故障轉(zhuǎn)移

          單實(shí)例肯定不是很可靠吧?加鎖成功之后,結(jié)果 Redis 服務(wù)宕機(jī)了,這不就涼涼~

          這時(shí)候會提出來將 Redis 主從部署。即使是主從,也是存在巧合的!

          主從結(jié)構(gòu)中存在明顯的競態(tài):

          1. 客戶端 A 從 master 獲取到鎖
          2. 在 master 將鎖同步到 slave 之前,master 宕掉了。
          3. slave 節(jié)點(diǎn)被晉級為 master 節(jié)點(diǎn)
          4. 客戶端 B 取得了同一個(gè)資源被客戶端 A 已經(jīng)獲取到的另外一個(gè)鎖。安全失效!

          有時(shí)候程序就是這么巧,比如說正好一個(gè)節(jié)點(diǎn)掛掉的時(shí)候,多個(gè)客戶端同時(shí)取到了鎖。如果你可以接受這種小概率錯(cuò)誤,那用這個(gè)基于復(fù)制的方案就完全沒有問題。

          那我使用集群呢?

          如果還記得前面的內(nèi)容,應(yīng)該是知道對集群進(jìn)行加鎖的時(shí)候,其實(shí)是通過 CRC16 的 hash 函數(shù)來對 key 進(jìn)行取模,將結(jié)果路由到預(yù)先分配過 slot 的相應(yīng)節(jié)點(diǎn)上。

          發(fā)現(xiàn)其實(shí)還是發(fā)到單個(gè)節(jié)點(diǎn)上的!

          RedLock 概念

          這時(shí)候 Redis 作者提出了 RedLock 的概念

          總結(jié)一下就是對集群的每個(gè)節(jié)點(diǎn)進(jìn)行加鎖,如果大多數(shù)(N/2+1)加鎖成功了,則認(rèn)為獲取鎖成功。

          RedLock 的問題

          看著 RedLock 好像是解決問題了:

          1. 客戶端 A 鎖住了集群的大多數(shù)(一半以上);
          2. 客戶端 B 也要鎖住大多數(shù);
          3. 這里肯定會沖突,所以 客戶端 B 加鎖失敗。

          那實(shí)際解決問題了么?

          推薦大家閱讀兩篇文章:

          • Martin Kleppmann:How to do distributed locking[2]

          • Salvatore(Redis 作者):Is Redlock safe?[3]

          最終,兩方各持己見,沒有得出結(jié)論。

          鑒于本文主要是分析 Redisson 的 RedLock,就不做額外贅述,感興趣的小伙伴可以自己閱讀。

          2

          Redisson 中 RedLock 源碼

          這里會簡要分析一下 Redisson 中 RedLock 的源碼,然后會介紹為什么文章開頭不建議大家使用 Redisson 的 RedLock。

          使用方式

          乍一看,感覺和聯(lián)鎖 MultiLock 的使用方式很像啊!

          實(shí)際上就是很像,RedissonRedLock 完全是 RedissonMultiLock 的子類嘛!

          只不過是重寫 failedLocksLimit 方法。

          在 MultiLock 中,要所有的鎖都鎖成功才可以。

          在 RedLock 中,要一半以上的鎖成功。

          剩余部分源碼都和 MultiLock 一樣,就不在重復(fù)描述了。

          Redisson 中 RedLock 的問題

          • 加鎖 key 的問題

          閱讀源碼之前,有一個(gè)很大的疑問,我加鎖 lock1、lock2、lock3,但是 RedissonRedLock 是如何保證這三個(gè) key 是在歸屬于 Redis 集群中不同的 master 呢?

          因?yàn)榘凑?RedLock 的理論,是需要在半數(shù)以上的 master 節(jié)點(diǎn)加鎖成功。

          閱讀完源碼之后,發(fā)現(xiàn) RedissonRedLock 完全是 RedissonMultiLock 的子類,只是重寫了 failedLocksLimit 方法,保證半數(shù)以上加鎖成功即可。

          所以這三個(gè) key,是需要用戶來保證分散在不同的節(jié)點(diǎn)上的。

          https://github.com/redisson/redisson/issues/2436

          在 Redisson 的 issues 也有同樣的小伙伴提出這個(gè)問題,相關(guān)開發(fā)者給出的回復(fù)是用戶來保證 key 分散在不同的 master 上。

          https://github.com/redisson/redisson/issues/2127

          更有小伙伴提出使用 5 個(gè)客戶端。

          那我使用 5 個(gè)單節(jié)點(diǎn)的客戶端,然后再使用紅鎖,聽著好像是可以的,并且 RedissonRedLock 可以這樣使用。

          但是那和 Redis 集群還有啥關(guān)系啊!

          所以依然沒有解決我的問題,還是需要用戶自己來“手工定位鎖”。

          手工定位鎖,這個(gè)…… 我考慮了下,還是不用 RedLock 吧!

          當(dāng)然 DarrenJiang1990 同學(xué)應(yīng)該是懷著打破砂鍋問到底的心情,又來了一篇 issue。

          https://github.com/redisson/redisson/issues/2437

          意思就是:不要關(guān)閉我的 issues,在 #2436 中說可以“手工定位鎖”,但是我要怎么手工定位鎖。

          后來這個(gè) issue 在 10 月才回復(fù)。

          • RedissonRedLock 被棄用

          是的,沒有看錯(cuò),現(xiàn)在 RedissonRedLock 已經(jīng)被啟用了。

          如果是看的英文文檔,就會發(fā)現(xiàn):

          而中文文檔,應(yīng)該是沒有及時(shí)更新。

          來看看更新記錄:

          再找一找 issue:

          https://github.com/redisson/redisson/issues/2669

          Redisson 的開發(fā)者認(rèn)為 Redis 的紅鎖也存在爭議(前文介紹的那個(gè)爭議),但是為了保證可用性,RLock 對象執(zhí)行的每個(gè) Redis 命令執(zhí)行都通過 Redis 3.0 中引入的 WAIT 命令進(jìn)行同步。

          WAIT 命令會阻塞當(dāng)前客戶端,直到所有以前的寫命令都成功的傳輸并被指定數(shù)量的副本確認(rèn)。如果達(dá)到以毫秒為單位指定的超時(shí),則即使尚未達(dá)到指定數(shù)量的副本,該命令也會返回。WAIT 命令同步復(fù)制也并不能保證強(qiáng)一致性,不過在主節(jié)點(diǎn)宕機(jī)之后,只不過會盡可能的選擇最佳的副本(slaves)

          源碼在這一部分。

          看源碼,同時(shí)發(fā)送了一個(gè) WAIT 1 1000 到 Redis。

          3

          結(jié)論

          Redisson RedLock 是基于聯(lián)鎖 MultiLock 實(shí)現(xiàn)的,但是使用過程中需要自己判斷 key 落在哪個(gè)節(jié)點(diǎn)上,對使用者不是很友好。

          Redisson RedLock 已經(jīng)被棄用,直接使用普通的加鎖即可,會基于 wait 機(jī)制將鎖同步到從節(jié)點(diǎn),但是也并不能保證一致性。僅僅是最大限度的保證一致性。

          引用鏈接:

          [1]

          RedLock: http://redis.cn/topics/distlock.html

          [2]

          Martin Kleppmann:How to do distributed locking: https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html

          [3]

          Salvatore:Is Redlock safe?: http://antirez.com/news/101


          - <End /> -




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



          瀏覽 52
          點(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>
                  黄色毛片一区二区 | 成人免费视频网站 | 豆花视频在线播放 | 久久亚洲AV成人无码国产精品 | 影音先锋夜夜亚洲 |