通過Redis實現分布式鎖

2021-09-26 16:20:00 字數 2826 閱讀 3056

分布式鎖是控制分布式系統或不同系統之間共同訪問共享資源的一種鎖的實現;如果不同的系統或同一系統的不同主機間共享某一資源時,往往需要通過互斥來防止彼此干擾,以此來保證一致性。

互斥性

任一時刻只能有乙個客戶端獲取鎖,不能有兩個客戶端都獲取到鎖

安全性

鎖只能被持有該鎖的客戶端刪除,不能由其他客戶端刪除

死鎖

獲取鎖的客戶端因為某些原因而宕機,而未能釋放鎖,其他客戶端再也不能獲取到該鎖而導致死鎖,此時需要有機制避免死鎖的發生

容錯

當部分節點(如redis節點)宕機時,客戶端仍能獲取鎖和釋放鎖

使用setnx(set if not exist)指令:setnx key value

「setnx key value」:如果key不存在,則建立並賦值

時間複雜度:o(1),高效

返回值:設定成功(即「key不存在,建立並賦值成功」),返回1;

​ 設定失敗(即「key存在,建立並賦值失敗」),返回0;

正因為setnex有上述功能,並且操作是原子的,因此初期時被人們用來實現分布式鎖

我們在執行某段**邏輯時,先嘗試使用setnex對某個key設值,如果設值成功,則證明此時沒有其他執行緒在執行該段**或者占用該獨佔資源,我們的執行緒就能順利地執行該段**邏輯;如果設值失敗,則證明此時有其他程式或者執行緒占用該資源,那麼當前執行緒就需要等待,直至下次的setnex成功。

但此時我們有個疑問:一旦某個執行緒成功setnex某個key,那這個key就會被該執行緒長久持有,後續其他線性該如何再次獲取到鎖?

因此,我們還需要解決下面乙個問題:如何解決setnex長期有效的問題?,即為key設定乙個過期時間。

使用expire指令:expire key seconds

「expire key seconds」:設定key的生存時間,當key過期時(生存時間為0),會被自動刪除

缺點:原子性得不到滿足

偽**

// 獲取redis服務

redisservice redisservice = springutils.

getbean

(redisservice.

class);

// 執行setnex並獲取返回狀態

long status = redisservice.

setnx

(key,

"1")

;// 判斷是否設定成功

if(status ==1)

但是該段程式存在風險。

當程式執行完第4行邏輯時,由於某些原因導致程式掛掉,導致未給key設定生存時間,則key會被一直占用著,這就意味著其他的執行緒永遠也無法執行獨佔資源邏輯。

這就是之前提到的,原子性得不到滿足。也就是說,雖然setnex是原子的,expire是原子的,但二者的組合操作卻不是原子的,即這種方法實現的分布式鎖使得原子性得不到滿足。

從redis2.6.12版本開始,我們就可以使用set操作將setnex和expire操作揉在一起執行。

具體指令如下:

set key value [ex seconds] [px milliseconds] [nx|xx]

ex second:設定鍵的過期時間為second秒

px millisecond:設定鍵的過期時間為millisecond毫秒

nx:只在鍵不存在時,才對鍵進行設定操作,與setnex相同

xx:只在鍵已經存在時,才對鍵進行設定操作,與setnex相反

set操作成功完成時,返回ok;若設定了nx和xx,但因條件未達到而造成操作未執行,則返回nil

這個「12345」為value,可以設定成request id或執行緒id,即可用來標識當前占用該資源的請求或者執行緒

即滿足分布式鎖的原子性需求。

在程式中可用以下的偽**邏輯實現分布式鎖

redisservice redisservice = springutils.

getbean

(redisservice.

class);

string result = redisservice.

set(lockkey, requestid, set_if_not_exist, set_with_expire_time, expiretime);if

("ok"

.equals

(result)

)

接下來,我們再了解下與key過期的相關性問題。

當大量的key集中過期,由於清除大量的key很耗時,會出現短暫的卡頓現象。

解決方案

在設定key的過期時間的時候,給每個key加上隨機值,將key的過期時間分散開來,避免卡頓現象的發生。

們再了解下與key過期的相關性問題。

當大量的key集中過期,由於清除大量的key很耗時,會出現短暫的卡頓現象。

解決方案

在設定key的過期時間的時候,給每個key加上隨機值,將key的過期時間分散開來,避免卡頓現象的發生。

通過Redis實現分布式鎖

當多執行緒的情況,可用redis來實現鎖。關於分布式鎖的原理網上很多,我這裡就只給出其中一種寫法。spring redis host 192.168.119.103 port 6379 password 123456附上 package com.redis.service import org.sl...

如何通過Redis實現分布式鎖

互斥性,安全性,死鎖,容錯 時間複雜度 o 1 返回值 設定成功,返回1 設定失敗,返回0。expire key seconds 設定key的生存時間,當key過期時 生存時間為0 會自動刪除 缺點 原子性得不到滿足 set key value ex secounds px milliseconds...

如何通過Redis實現分布式鎖

目錄 分布式鎖需要解決的問題 如何通過redis實現分布式鎖 如何解決setnx長期有效的問題 大量的key同時過期的注意事項 互斥性 任意時刻,只能有乙個客戶端獲取鎖 安全性 鎖只能由持有該鎖的客戶端刪除 死鎖 獲取鎖的客戶端因為某些原因宕機而未能釋放鎖,其他客戶端就無法獲取鎖 容錯 當一些red...