亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Redis分布式鎖存在的問題(推薦)

 更新時間:2022年12月12日 08:44:43   作者:小黑說Java  
有很多基于Redis實現(xiàn)的分布式鎖方案或者庫,但是有些庫并沒有解決分布式環(huán)境下的一些問題陷阱,這篇文章主要介紹了Redis分布式鎖存在的問題,需要的朋友可以參考下

在很多場景中,我們?yōu)榱吮WC數(shù)據(jù)的最終一致性,需要很多的技術(shù)方案來支持,比如分布式事務(wù)、分布式鎖等。

有很多基于Redis實現(xiàn)的分布式鎖方案或者庫,但是有些庫并沒有解決分布式環(huán)境下的一些問題陷阱。

分布式鎖的特點

分布式鎖應(yīng)該具備以下屬性:

  • 互斥 在同一時刻只有一個客戶端可以持有鎖;這是分布式鎖的基本屬性。
  • 無死鎖 每個鎖請求都可以最終獲得鎖;即使是持有鎖的客戶端也會崩潰或遇到異常。 不同的實現(xiàn)

不同的實現(xiàn)

許多分布式鎖實現(xiàn)都是基于分布式共識算法(Paxos、Raft、ZAB、Pacifica)的,比如基于Paxos的Chubby、基于ZAB的Zookeeper等,以及基于Raft的Consul。Redis的作者還提出了一種分布式鎖,名為RedLock。

在接下來的章節(jié)中,我將展示如何基于Redis一步步實現(xiàn)分布式鎖,并且在每一步中,我都試圖解決分布式環(huán)境中可能發(fā)生的一個問題。

場景一:單實例Redis

為了簡單起見,假設(shè)我們有兩個客戶端和一個Redis實例。一個簡單的實現(xiàn)應(yīng)該是:

boolean tryAcquire(String lockName, long leaseTime, OperationCallBack operationCallBack) {
   // 加鎖
  boolean getLockSuccessfully = getLock(lockName, leaseTime);
  if (getLockSuccessfully) {
      try {
          operationCallBack.doOperation();
      } finally {
          releaseLock(lockName);
      }
      return true;
  } else {
      return false;
  }
}

boolean getLock(String lockName, long expirationTimeMillis) {
	// 給當(dāng)前線程創(chuàng)建一個唯一的lockValue
  String lockValue = createUniqueLockValue();
  try {
	  // 如果lockName沒有加鎖,則將lockName作為key保存到redis中,并指定過期時間
      String response = storeLockInRedis(lockName, lockValue, expirationTimeMillis);
      return response.equalsIgnoreCase("OK");
  } catch (Exception exception) {
      releaseLock(lockName);
      throw exception;
  }
}

void releaseLock(String lockName) {
  String lockValue = createUniqueLockValue();
  // 移除鎖lockName,如果鎖的值是lockValue
  removeLockFromRedis(lockName, lockValue);
}

這種方式有什么問題呢?

**假如客戶端1請求服務(wù)端獲取一個鎖,并指定了鎖超時時間,如果服務(wù)器響應(yīng)的時間大于鎖的超時時間,客戶端1拿到的則是一個過期的鎖,這時客戶端2同時可以獲取該鎖進(jìn)行業(yè)務(wù)操作。**這打破了分布式鎖應(yīng)該具備的相互排斥原則。

為了解決這個問題,我們應(yīng)該給redis客戶端設(shè)置一個請求超時時間timeout,這個時間應(yīng)該小于鎖的超時時間。

當(dāng)時這還不能完全解決這個問題,假設(shè)Redis服務(wù)器因為掉電重啟,則會有其他的問題,我們接下來看第二個場景。

場景二:單實例Redis的單點故障

如果你對Redis的數(shù)據(jù)持久化方案有所了解,那一定知道Redis有兩種方式做數(shù)據(jù)持久化。

RDB(Redis Database):按指定的時間間隔將Redis的數(shù)據(jù)快照保存到磁盤。

AOF(Append-Only File):將服務(wù)器接收到的寫操作指令記錄下來,這些操作指令在服務(wù)重啟時可以重新執(zhí)行來恢復(fù)原始數(shù)據(jù)。

默認(rèn)情況下,只會開啟RDB模式,會按照如下方式配置:

save 900 1 

save 300 10 

save 60 10000

例如,第一行表示在900秒(15min)內(nèi)如果有一次寫操作,就將數(shù)據(jù)同步到數(shù)據(jù)文件。

所以在最壞的情況下,將一個加鎖數(shù)據(jù)保存需要15分鐘,如果在加鎖成功時Redis服務(wù)掉電重啟,則無法恢復(fù)內(nèi)存中的加鎖數(shù)據(jù),其它客戶端同樣可以獲取到相同的鎖

為了解決這個問題,我們必須使用fsync=always選項來啟用AOF,然后在Redis中設(shè)置鍵。

注意,啟用這個選項對Redis的性能有一定的影響,但我們需要這個選項以保持強一致性。

場景三:主從復(fù)制

在這個配置中,我們有一個或多個實例(通常稱為從實例或副本),它們是主實例的精確副本。

默認(rèn)情況下,Redis中的復(fù)制是異步的;這意味著主服務(wù)器不會等待命令被副本處理完畢再返回給客戶端。

問題是在復(fù)制發(fā)生之前,主服務(wù)器可能出現(xiàn)故障,并發(fā)生故障轉(zhuǎn)移;在此之后,如果另一個客戶端請求獲得鎖,它將成功!或者假設(shè)存在一個臨時的網(wǎng)絡(luò)問題,因此其中一個副本沒有接收到命令,網(wǎng)絡(luò)變得穩(wěn)定,故障轉(zhuǎn)移很快發(fā)生;沒有接收到命令的節(jié)點成為主節(jié)點。

最終,該鎖將從所有實例中刪除!下圖說明了這種情況:

作為解決方案,有一個等待命令,等待指定數(shù)量的確認(rèn)副本并返回副本的數(shù)量,承認(rèn)之前的寫命令發(fā)送等待命令,兩個的情況下達(dá)到指定數(shù)量的副本或者超時。

例如,如果我們有兩個副本,下面的命令最多等待1秒(1000毫秒)來從兩個副本獲得確認(rèn)并返回:

WAIT  2  1000

到目前為止,一切順利,但還有另一個問題;副本可能會丟失寫入(由于錯誤的環(huán)境)。例如,一個副本在保存操作完成之前失敗,同時主節(jié)點也失敗,故障轉(zhuǎn)移操作選擇重新啟動的副本作為新的主節(jié)點。在與新主服務(wù)器同步后,所有副本和新主服務(wù)器都沒有舊主服務(wù)器中的密鑰!

為了使所有的從服務(wù)器和主服務(wù)器完全一致,我們應(yīng)該在獲得鎖之前為所有Redis實例啟用fsync=always的AOF。

注意:在這種方法中,我們?yōu)榱藦娨恢滦远茐牧丝捎眯裕珹OF會有一定的性能損耗。

場景四:自動刷新的鎖

在這個場景中,只要客戶端是活的并且連接是正常的,就可以持有獲取的鎖。

我們需要一種機制來在鎖到期之前刷新鎖。我們還應(yīng)該考慮不能刷新鎖的情況;在這種情況下,必須立即退出。

此外,當(dāng)鎖的持有者釋放鎖時,其他客戶端應(yīng)該能夠等待獲得鎖并進(jìn)入臨界區(qū):

小結(jié)

我這里通過四個小場景,引出了四個問題,并給出相應(yīng)的解決辦法,但有一些重要的問題還沒有解決我想在這里指出來,希望在以后使用分布式鎖時作為參考。

不同節(jié)點之間的時鐘漂移問題;獲取鎖之后客戶端出現(xiàn)長線程的暫停或者進(jìn)程暫停;一個客戶端可能要等待很長時間才能獲得鎖,而與此同時,另一個客戶端會立即獲得鎖;非公平鎖。

許多三方庫使用Redis提供分布式鎖的服務(wù),我們應(yīng)該去了解它們是如何工作的以及可能發(fā)生的問題,在它們的正確性和性能之間做出權(quán)衡。

到此這篇關(guān)于Redis分布式鎖存在的問題的文章就介紹到這了,更多相關(guān)Redis分布式鎖存在的問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • redis實現(xiàn)簡單隊列

    redis實現(xiàn)簡單隊列

    這篇文章主要為大家詳細(xì)介紹了redis實現(xiàn)簡單隊列的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 如何使用注解方式實現(xiàn)?Redis?分布式鎖

    如何使用注解方式實現(xiàn)?Redis?分布式鎖

    這篇文章主要介紹了如何使用注解方式實現(xiàn)Redis分布式鎖,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,教大家如何優(yōu)雅的使用Redis分布式鎖,感興趣的小伙伴可以參考一下
    2022-07-07
  • ?Redis 串行生成順序編碼的方法實現(xiàn)

    ?Redis 串行生成順序編碼的方法實現(xiàn)

    本文主要介紹了?Redis 串行生成順序編碼的方法實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • redis使用不當(dāng)導(dǎo)致應(yīng)用卡死bug的過程解析

    redis使用不當(dāng)導(dǎo)致應(yīng)用卡死bug的過程解析

    本文主要記一次找因redis使用不當(dāng)導(dǎo)致應(yīng)用卡死bug的過程,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • Redis有序集合類型的常用命令小結(jié)

    Redis有序集合類型的常用命令小結(jié)

    這篇文章先是給大家簡單介紹了一下有序集合類型,然后詳細(xì)整理了關(guān)于Redis有序集合類型的常用命令,通過整理的這些命令相信會給大家的工作或?qū)W習(xí)帶來一定的幫助,有需要的朋友們下面來一起看看吧。
    2016-09-09
  • 詳解Redis復(fù)制原理

    詳解Redis復(fù)制原理

    與大多數(shù)db一樣,Redis也提供了復(fù)制機制,以滿足故障恢復(fù)和負(fù)載均衡等需求。復(fù)制也是Redis高可用的基礎(chǔ),哨兵和集群都是建立在復(fù)制基礎(chǔ)上實現(xiàn)高可用的。復(fù)制不僅提高了整個系統(tǒng)的容錯能力,還可以水平擴展,通過增加多個Redis只讀從實例來減輕主實例的壓力。
    2021-06-06
  • 基于Redis無序集合如何實現(xiàn)禁止多端登錄功能

    基于Redis無序集合如何實現(xiàn)禁止多端登錄功能

    這篇文章主要給你大家介紹了關(guān)于基于Redis無序集合如何實現(xiàn)禁止多端登錄功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • YII2框架手動安裝Redis擴展的過程

    YII2框架手動安裝Redis擴展的過程

    這篇文章主要介紹了YII2框架手動安裝Redis擴展的過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • mac下設(shè)置redis開機啟動方法步驟

    mac下設(shè)置redis開機啟動方法步驟

    這篇文章主要介紹了mac下設(shè)置redis開機啟動,本文詳細(xì)的給出了操作步驟,需要的朋友可以參考下
    2015-07-07
  • Redis做數(shù)據(jù)持久化的解決方案及底層原理

    Redis做數(shù)據(jù)持久化的解決方案及底層原理

    Redis有兩種方式來實現(xiàn)數(shù)據(jù)的持久化,分別是RDB(Redis Database)和AOF(Append Only File),今天通過本文給大家聊一聊Redis做數(shù)據(jù)持久化的解決方案及底層原理,感興趣的朋友一起看看吧
    2021-07-07

最新評論