起因:redis分布式鎖自己用過、也看過一些文章,但是總是會(huì)是有不懂之處,于是寫一遍,必須給他安排的明明白白
為什么使用
分布式鎖拆一下是兩個(gè)點(diǎn)
- 鎖
鎖的概念叛薯,從操作系統(tǒng)到語言使用都有使用,就是一個(gè)資源的使用笙纤,一次只能有一個(gè)單位去用耗溜,并發(fā)競爭的情況下,就需要加鎖來保證省容,一個(gè)人使用抖拴,使用完解鎖,再下一個(gè)使用腥椒,如此阿宅。所以鎖是串行化了并發(fā)操作,也會(huì)影響性能笼蛛。 - 分布式
分布式環(huán)境洒放,其實(shí)是集群環(huán)境,就是一個(gè)應(yīng)用部署了多份滨砍,多份同樣的代碼都在跑往湿,單體應(yīng)用上使用java的鎖,已經(jīng)不適用于分布式環(huán)境了惋戏,于是需要第三方來協(xié)調(diào)领追,如zk、redis等日川;第三方來管理鎖蔓腐,多臺(tái)機(jī)器在第三方去獲得鎖矩乐,解鎖龄句。
所以回论,由于現(xiàn)在的應(yīng)用基本都是分布式集群環(huán)境,鎖就演變成了分布式鎖
怎么使用
引入
java語言的鎖通過狀態(tài)管理分歇,我獲得了鎖傀蓉,我的狀態(tài)改為1,解鎖再改為0职抡,如此來管理競爭鎖的線程(lock) redis中的鎖結(jié)合redis的特性葬燎,就是通過redis設(shè)置一個(gè)值,解鎖時(shí)刪除缚甩,因?yàn)槭歉偁幤拙唬灾荒苡幸粋€(gè)set成功
解決原子性問題
- 因此需要使用setnx,只有redis中沒有這個(gè)key才會(huì)set成功
- set之后需要del來解鎖擅威,這里分布式環(huán)境下很明顯兩個(gè)操作是要保證原子性的壕探;因此set再del不行,set再expire也不行(兩步操作郊丛,后一步可能執(zhí)行不到陷入死鎖)李请;因此redis2.8版本更新了set操作,通過setnx ex來保證原子性厉熟,如 set lock:user true ex 5 nx
超時(shí)問題
有一個(gè)問題是在加鎖和解鎖之間导盅,執(zhí)行任務(wù)邏輯的時(shí)候,如果沒執(zhí)行完就到了超時(shí)時(shí)間釋放了鎖揍瑟,第二個(gè)線程進(jìn)來持有了鎖白翻,臨界區(qū)代碼沒有嚴(yán)格串行執(zhí)行,將會(huì)產(chǎn)生問題(因此分布式鎖也不適合做長時(shí)間的任務(wù))
有個(gè)稍微安全又簡單的方案是set value為一個(gè)隨機(jī)數(shù)月培,在釋放時(shí)匹配隨機(jī)數(shù)嘁字,一致再釋放,可以保證當(dāng)前線程的鎖不會(huì)被其他線程釋放杉畜。redis中沒有這種操作纪蜒,因此需要使用lua來執(zhí)行并保證原子性操作
如
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call
else
return 0
end
在實(shí)際使用時(shí),可對這部分try catch此叠,在finally中可以釋放鎖纯续,提前執(zhí)行完畢時(shí)先釋放鎖提升性能。
集群容錯(cuò)性
redis集群中帶來的容錯(cuò)灭袁,在master掛掉之后猬错,slave中沒有同步到鎖,因此新的master沒有鎖茸歧,加鎖成功之后倦炒,有多個(gè)鎖就不安全了。
redlock算法解決這個(gè)問題软瞎,思路也比較簡單逢唤,需要多個(gè)redis master節(jié)點(diǎn)拉讯,采用過半機(jī)制,加鎖時(shí)鳖藕,對過半節(jié)點(diǎn)發(fā)送set(key,value,nx,ex)指令魔慷,過半成功則成功,釋放同樣發(fā)送del指令著恩,比較消耗性能院尔。
分布式鎖如深究還有可重入性包裝等,待更新喉誊,以上內(nèi)容如不對請指出邀摆!