用redis构建分布式锁
單實例的實現(xiàn)#
從2.6.12版本開始,redis為SET命令增加了一系列選項:
EX seconds – 設(shè)置鍵key的過期時間,單位時秒
PX milliseconds – 設(shè)置鍵key的過期時間,單位時毫秒
NX – 只有鍵key不存在的時候才會設(shè)置key的值
XX – 只有鍵key存在的時候才會設(shè)置key的值
如果有2個進(jìn)程(可能位于不同機(jī)器)需要競爭某個資源,可以為這個資源加鎖,鎖放在redis里面,這樣兩個進(jìn)程都能訪問到,例如下面的命令:
SET resource-name random-value NX EX max-lock-time
僅當(dāng)key不存在時,設(shè)置一個鍵值對,并且設(shè)置了key的過期時間。
如果其中一個進(jìn)程set成功,那么另外一個進(jìn)程會set失敗,只要判斷set命令的返回值,就可以判斷是否加鎖成功。
這里resouce-name是需要加鎖的資源,而random-value每個進(jìn)程都可以寫唯一值,而max-lock-time是鎖的最大持有時間。
如何釋放鎖:
a客戶端獲得的鎖(鍵key)已經(jīng)由于過期時間到了被redis服務(wù)器刪除,但是這個時候a客戶端還去執(zhí)行DEL命令。而b客戶端已經(jīng)在a設(shè)置的過期時間之后重新獲取了這個同樣key的鎖,那么a執(zhí)行DEL就會釋放了b客戶端加好的鎖。
if redis.call(“get”,KEYS[1]) == ARGV[1]
then
return redis.call(“del”,KEYS[1])
else
return 0
end
由于每個進(jìn)程寫入的value是自己生成的隨機(jī)數(shù),可以保證一個進(jìn)程只能刪除自己加的鎖,而避免誤刪其它進(jìn)程加的鎖。
回到頂部
分布式鎖#
在分布式版本的算法里我們假設(shè)我們有N個Redis master節(jié)點,這些節(jié)點都是完全獨立的,我們不用任何復(fù)制或者其他隱含的分布式協(xié)調(diào)算法。我們已經(jīng)描述了如何在單節(jié)點環(huán)境下安全地獲取和釋放鎖。因此我們理所當(dāng)然地應(yīng)當(dāng)用這個方法在每個單節(jié)點里來獲取和釋放鎖。在我們的例子里面我們把N設(shè)成5,這個數(shù)字是一個相對比較合理的數(shù)值,因此我們需要在不同的計算機(jī)或者虛擬機(jī)上運行5個master節(jié)點來保證他們大多數(shù)情況下都不會同時宕機(jī)。一個客戶端需要做如下操作來獲取鎖:
1.獲取當(dāng)前時間(單位是毫秒)。
2.輪流用相同的key和隨機(jī)值在N個節(jié)點上請求鎖,在這一步里,客戶端在每個master上請求鎖時,會有一個和總的鎖釋放時間相比小的多的超時時間。比如如果鎖自動釋放時間是10s,那每個節(jié)點鎖請求的超時時間可能是5~50ms的范圍,這個可以防止一個客戶端在某個宕掉的master節(jié)點上阻塞過長時間,如果一個master節(jié)點不可用了,我們應(yīng)該盡快嘗試下一個master節(jié)點。
3.客戶端計算第二步中獲取鎖所花的時間,只有當(dāng)客戶端在大多數(shù)master節(jié)點上成功獲取了鎖(在這里是3個),而且總共消耗的時間不超過鎖釋放時間,這個鎖就認(rèn)為是獲取成功了。
4.如果鎖獲取成功了,那現(xiàn)在鎖自動釋放時間就是最初的鎖釋放時間減去之前獲取鎖所消耗的時間。
5.如果鎖獲取失敗了,不管是因為獲取成功的鎖不超過一半(N/2+1)還是因為總消耗時間超過了鎖釋放時間,一定要盡快在獲取鎖成功的節(jié)點上釋放鎖,這樣就沒必要等到key超時后才能重新獲取這個鎖(但是如果網(wǎng)絡(luò)分區(qū)的情況發(fā)生而且客戶端無法連接到Redis節(jié)點時,會損失等待key超時這段時間的系統(tǒng)可用性)。
注意:當(dāng)一個客戶端獲取鎖失敗時,這個客戶端應(yīng)該在一個隨機(jī)延時后進(jìn)行重試,之所以采用隨機(jī)延時是為了避免不同客戶端同時重試導(dǎo)致誰都無法拿到鎖的情況出現(xiàn)。同樣的道理客戶端越快嘗試在大多數(shù)Redis節(jié)點獲取鎖,出現(xiàn)多個客戶端同時競爭鎖和重試的時間窗口越小,可能性就越低,所以最完美的情況下,客戶端應(yīng)該用多路傳輸?shù)姆绞酵瑫r向所有Redis節(jié)點發(fā)送SET命令。
參考文檔:
http://ifeve.com/redis-lock/
https://github.com/SPSCommerce/redlock-py
總結(jié)
以上是生活随笔為你收集整理的用redis构建分布式锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 幂等性问题剖析
- 下一篇: docker安装ActiveMQ