回覆列表
  • 1 # SapphireCoder

    在傳統單體應用單機部署的情況下,併發問題可以透過使用Java併發相關的鎖如synchronized,但是當規模上升到分散式叢集的情況下,要控制共享資源訪問,就需要透過分散式鎖來實現。常見的分散式鎖方案如資料庫樂觀鎖,Redis鎖,zk鎖等。

    Redis分散式鎖的原理

    Redis分散式鎖可以有多種方式實現但是其核心就是透過以下三個Redis命令組合實現。

    SETNX SETNX key val 當且僅當key不存在時,set一個key為val的字串,返回1;若key存在,則什麼都不做,返回0。 Expire expire key timeout 為key設定一個超時時間,單位為second,超過這個時間鎖會自動釋放,避免死鎖。 Delete delete key 刪除key核心思想使用setnx獲取鎖。如果成功取到鎖,則使用expire命令為鎖新增一個超時時間,超過該時間則自動釋放鎖。 獲取鎖的時候還設定一個獲取的超時時間,若超過這個時間則放棄獲取鎖。注意

    上面為Redis的一個最簡單的鎖實現原理,實際中還需要考慮更多具體的情況作出相應的調整。如

    上面的demo中,當集群系統時間不一致時會有問題當伺服器異常關閉或是重啟,加鎖後沒來得急設定鎖超時時間,如何避免死鎖

    實際開發環境中不確定的因素有很多,需要慢慢地去調整實踐達到理想狀態,可以考慮使用redisson框架來實現。

    如何續期?

    這個情況比較獨特,出現這個問題的根本原因在於鎖失效的時間小於業務處理的時間導致業務還沒處理完畢鎖就釋放了。那麼解決方案是合理地結合業務去設定鎖失效的時間。

    但是也有更好的方案就如前文提到的redisson,其中的可重入鎖概念。

    預設情況下,加鎖的時間是30秒.如果加鎖的業務沒有執行完,那麼到 30-10 = 20秒的時候,就會進行一次續期,把鎖重置成30秒。

  • 2 # 閒談架構

    分散式鎖的需求產生

    分散式鎖的需求是伴隨著應用分散式部署而來的,在單體應用,且只部署一臺伺服器的情況下,透過java的同步鎖即可實現。同步鎖,即是一個原子性的操作。

    那麼當應用進行了分散式部署,應用有多個服務,這個時候應用服務端就沒有一個可提供原子性操作的地方了,Redis效能高,且是單執行緒,因此可提供一個原子性操作的地方,利用它,就可以實現分散式鎖。

    用場景說話,使用Redis分散式鎖的場景如下圖所示:

    如下圖所示,隨後會根據場景說明分散式鎖及續期相關問題的來龍去脈。

    圖中序號1:進來一個請求,這個請求要求我們儲存一個“訂單A”;圖中序號2:2.1 步,請求進來,首先去嘗試設定一個Redis 值,他的鍵就是訂單號“訂單A”,如果嘗試成功,則代表我這個執行緒是第一次設定,相當於我拿到了這個鎖;如果嘗試失敗,那麼,可以丟擲異常或者等待一段時候後再次重試,這裡可以根據業務場景的不同採取不同的策略。這裡的關鍵是在Redis中的操作是單執行緒的,因此該操作是原子性的。2.2步,為了防止應用服務意外中斷,Redis中的資料一直存活,消耗資源,需要設定一個超時時間。(如果為了嚴謹,可以將2.1, 2.2 兩步封裝成一個lua指令碼部署在Redis伺服器上)圖中序號3:情況A,這個時候是當Redis的key還未失效,程式就已經執行完成,且刪除了Redis中的資料,一切正常;情況B:就是需要續期的場景,如果要避免這個場景的出現,可以將Redis key的失效時間設定長一點,可以應對大多數業務。如果要徹底解決,可以在應用端新增一個Redis鎖的註冊中心,然後起一個監聽執行緒去監聽這個註冊中心,發現有鎖還在被持有,但是Redis 已經快過期了,則修改相應key的失效時間,進行續期。

  • 中秋節和大豐收的關聯?
  • 牙齦炎最好的治療方法?