1.setnx key value // 設置成功返回1,設置失敗返回0
2. do something ... // 進行邏輯操做
3.del key // 刪除以前設置的key,即刪除分佈式鎖
複製代碼
初初級分佈式鎖使用setnx + del
完成,先使用setnx
設置key,若是設置成功,就開始進行邏輯操做,邏輯操做完成後,使用del
刪除分佈式鎖。但若是在使用setnx
加鎖後,因爲某些緣由程序終止運行了,那麼del
解鎖命令就永遠得不到執行,那麼以前加的分佈式鎖就永遠在redis中了,其餘業務也就永遠沒法得到鎖。redis
爲了解決del
命令可能未執行致使鎖永遠沒法釋放的問題,因而使用到了expire
命令,給key加過時時間,防止del
命令未運行出現的死鎖狀況。bash
1.setnx key value // 設置成功返回1,設置失敗返回0
2.expire key seconds // 爲key設置過時時間
3. do something ... // 進行邏輯操做
4.del key // 刪除以前設置的key,即刪除分佈式鎖
複製代碼
初級分佈式鎖使用setnx + expire + del
完成,首先setnx
設置key,若是設置成功則調用expire
爲該key設置過時時間,而後開始作一些邏輯操做,最後相關邏輯操做完成後使用del
刪除key來釋放分佈式鎖。
初級分佈式鎖很清晰的邏輯,可是首先要明白,在setnx
、expire
兩個命令之間也會由於某些緣由致使業務中斷,程序就無法正常進行下去,也就會致使分佈式鎖失效。比方說: setnx
成功後,開始設置過時時間應該,可是這時候服務器宕機了,致使expire
命令未執行,因而,以前設置的key就會永遠存在redis中,當服務器恢復正常後,正常業務就再也沒法得到鎖,由於他發現,這個key一直存在,再使用setnx
就一直失敗。服務器
expire
命令未正常運行,這就和第一種「初初級分佈式鎖」僅用
setnx + del
狀況是一毛同樣了,出現了死鎖。
1.set key value ex seconds nx // 設置成功返回1,設置失敗返回nil
2. do something ... // 進行邏輯操做
3.del key // 刪除以前設置的key,即刪除分佈式鎖
複製代碼
中級分佈式鎖的基礎是redis版本已經升級到2.6.12版本以上,set
命令在該版本以前還僅是set key value
的操做模式,升級後就加了ex和nx等參數,使用ex和nx參數後等效於 setnx key value; expire key seconds
兩條命令,且使用set
實現ex和nx的功能都是原子性的,不會出現ex和nx斷檔。分佈式
該分佈式鎖雖然解決了setnx
和expire
兩個命令的斷檔問題,可是若是do something
的邏輯操做執行時間過長會出現什麼新的問題?lua
do something
時間超出設置的過時時間,若是這時候業務邏輯還沒作完,業務B就來獲取鎖了,而後也會走do something
,這時候就會出現業務數據紊亂,也就打破了使用分佈式鎖的初衷do something
時間超出設置的過時時間,業務A的分佈式鎖被釋放,業務B獲取了該鎖,正在執行,這時候業務Ado something
完成了,開始釋放鎖,結果把已經獲取分佈式鎖的業務B的鎖給釋放了如何解決上述問題呢?spa
方法一:
針對問題二,能夠在加鎖操做時,給key的value設置一個隨機數並記錄下來,當do something
走完後,要釋放鎖時,先判斷分佈式鎖的value和當前要刪除的key的value,也就是以前設置的隨機數是否一致,若是一致才能夠刪除,若是刪除不了,就說明這個key已通過期了,被自動釋放了。這個方法仍舊有一個弊端,就是在判斷value是否一致時的操做也不是原子型的,假如業務A的鎖還沒過時,而後最後要開始釋放鎖,他先判斷value是否一致,發現value是一致的,可是由於某些緣由致使要過N長時間才能執行del
操做,而後業務A的鎖到期了自動釋放了,而這時候業務B獲取了鎖,結果業務A的del
操做終於甦醒了,因而他開始釋放鎖,結果把業務B的鎖給釋放了,針對這個問題,說是能夠用lua腳原本解決,由於 Lua 腳本能夠保證連續多個指令的原子性執行(可是我目前還不會lua腳本)
方法二:
針對問題一的數據錯亂,那目前沒招... 要麼就是在業務層作控制,比方說在do something
工做期間判斷鎖是否有效,無效的話就回滾當前業務,拋出異常,還比方說自動續期code