Redis分布式鎖原理及go的實現

2021-10-05 21:51:38 字數 4199 閱讀 1828

業務背景: 後台定時任務重新整理redis的資料到資料庫中,有多台機器開啟了此定時同步的任務,但是需要其中一台工作,其他的作為備用,提高可用性。使用redis分布式鎖進行限制,拿到鎖的機器去執行具體業務,拿不到鎖的繼續輪詢。

分布式鎖:當多個程序不在同乙個系統中,多個程序共同競爭同乙個資源,用分布式鎖控制多個程序對資源的互斥訪問。採用redis伺服器儲存鎖資訊(即set乙個key表示已加鎖),可以實現多程序的併發讀鎖的狀態,如果沒有鎖,則只允許乙個程序加鎖。

redis分布式鎖實現的關鍵點:

問題問題描述

解決方案

互斥性保證只有乙個client可以獲取資源

加鎖原子性

如果鎖不存在則執行加鎖操作,必須是原子性操作

原子性命令或者執行lua指令碼

避免死鎖

當拿到鎖的client因宕機或網路原因斷線後,如果鎖不能釋放就會產生死鎖

為鎖加超時時間

鎖超時時間設定

鎖超時時間到了,業務沒執行完問題

心跳執行緒,不斷更新鎖超時時間

鎖的所屬權

解鈴還須繫鈴人,加鎖和解鎖必須是同乙個客戶端,客戶端自己不能把別人加的鎖給解了。

client與鎖進行一一對應,使用uuid作為鎖的值

自動重連

網路故障導致client連線redis失敗的情況,網路恢復後可以自動重連

輪詢方案一:採用redis的原子性命令「set key value ex expire-time nx」可以實現分布式鎖的基本功能,其中的nx(not exist)即判斷是否已存在鎖,如果不存在key則可進行操作,set key value 等同於加鎖,ex expire-time即設定超時時間,可以避免死鎖,但是超時時間的設定需要根據具體業務設定乙個合理的經驗值,避免鎖超時時間到了,業務沒執行完的問題。

方案二:採用lua指令碼實現,redis會將整個指令碼作為乙個整體執行,因此lua指令碼可以實現原子性操作。相較於方案一,此處增加了心跳執行緒,不斷更新鎖超時時間,解決鎖超時時間設定不合理的問題;生成uuid(或者是隨機數字串)作為鎖的值,用於保證鎖與client的一一對應;採用輪詢來實現斷線自動重連。

talk is cheap. show me the code.

加鎖流程圖:

定義鎖的變數名為lock,那麼對應redis命令:

判斷是否加鎖的命令:get lock

加鎖的命令:set lock

設定超時時間的命令:expire expire-time

三條命令分開執行是不具有原子性的,比如可能會出現乙個程序執行get lock得到的結果為nil即尚未加鎖,在其執行set lock前另乙個程序也執行了set lock,導致兩個程序都認為是可以加鎖的,失去互斥性。

因此判斷尚未加鎖、加鎖、設定超時時間必須原子操作,使用redis的命令「set key value ex expire-time nx」可以實現該原子操作。

// 加鎖失敗,繼續輪詢

if result !=

"ok"

// 加鎖成功

fmt.

println

("work begining..."

)// 此處處理業務

fmt.

println

("work end");

// 業務處理結束後釋放鎖

result, err := rds.do(

"del"

,"lock"

)break;}

}此方法弊端是對超時時間的設定有要求,需要根據具體業務設定乙個合理的經驗值,避免鎖超時時間到了,業務沒執行完的問題。

// 生成uuid標識鎖與client的對應關係

uuidclient,err = uuid.

newv4()

//也可以生成隨機數字串來代替

if err !=

nil lualock := redis.

newscript(1

, script_lock)

luadel:= redis.

newscript(1

, script_del)

fortrue

if result ==

0 fmt.

println

("set lock succeed.")go

resetexpire()

// 加鎖成功

fmt.

println

("work begining..."

)// 此處處理業務

fmt.

println

("work end");

// 業務處理結束後釋放鎖

result, err = redis.

int(luadel.

do(rds,

"lock"

, uuidclient.

string()

))return}}

}redis採用lua指令碼可以執行更多的個性化的原子操作,在我專案中就採用這種容錯性更高的方式。

[1] redis分布式鎖的正確實現方式

[2] 解決redis分布式鎖過期時間到了業務沒執行完問題

Redis分布式鎖原理及實現

ps 該篇博文目錄為 redis分布式鎖使用 中的 有瑕疵,為避免錯誤使用,請移步 感興趣的也可以看看到底瑕疵在哪 解決問題 多個程序多台機器,對乙個資料進行的操作的互斥。比如,下訂單和扣庫存的操作,這兩個操作必須連貫,乙個執行緒執行完這兩個操作後,下面乙個執行緒才可以介入執行,如果同時併發執行,極...

redis分布式鎖原理

以redisson為例 rlock lock redissonclient.getlock key lock.lock timeoutsecond,timeunit.seconds 原則 1.自己加的鎖自己釋放,2.鎖到期了業務沒執行完還需續期 if redis.call exists keys 1...

redis分布式鎖原理

舉例子 秒殺方式看醫生,乙個人看5min 1.第一次只允許乙個人直接進行來,x10 00 00進去了,setnx roomid,now 5min 出來時間假如是10 05 00 2.時間到了10 05 00,3個人同時進來,需要去看牆上的鐘錶,乙個人乙個的看 a進入病房看到,看到鐘錶時間10 05 ...