分布式鎖
是控制分布式系統(tǒng)之間共同訪問共享資源的一種鎖的實(shí)現(xiàn)
分布式鎖需要解決的問題
1、互斥性:任意時(shí)刻只能有一個(gè)客戶端獲取鎖;
2、安全性:鎖只能被持有該鎖的客戶端刪除,不能由其他客戶端刪除;
3、死鎖:如果獲取鎖的客戶端出現(xiàn)宕機(jī)而未能釋放鎖,那么其他客戶端將再也無法獲取到鎖而導(dǎo)致死鎖;
4、容錯(cuò):當(dāng)部分Redis節(jié)點(diǎn)宕機(jī)時(shí),客戶端仍然能獲取鎖和釋放鎖。
由于Redis為單進(jìn)程單線程模式,采用隊(duì)列模式將并發(fā)訪問變成串行訪問,且多客戶端對Redis的連接并不存在競爭關(guān)系,故利用該特性可實(shí)現(xiàn)分布式鎖。
利用Redis的SETNX命令來實(shí)現(xiàn),由于當(dāng)某個(gè) key 不存在的時(shí)候,SETNX 才會設(shè)置該 key。并且 Redis 采用單進(jìn)程單線程模型,所以,不需要擔(dān)心并發(fā)的問題。就可以利用 SETNX 的特性維護(hù)一個(gè) key,存在的時(shí)候,即鎖被某個(gè)線程持有;不存在的時(shí)候,沒有線程持有鎖。
至此還有一個(gè)問題:如果一個(gè)請求獲取到了鎖,但是在執(zhí)行時(shí)因?yàn)槟承┰蛞馔馔顺隽?,如服?wù)器宕機(jī)。導(dǎo)致創(chuàng)建了鎖但是沒有刪除鎖,那么這個(gè)鎖將一直存在,以至于以后緩存再也得不到更新,就是死鎖問題。于是我們需要給鎖設(shè)置一個(gè)過期時(shí)間以防止這種情況的發(fā)生。
因?yàn)?** SetNX** 不具備設(shè)置過期時(shí)間的功能,所以我們需要借助 Expire 來設(shè)置,同時(shí)我們需要把兩者放在一個(gè)事務(wù)中,以確保請求的原子性,以免 SetNX 成功了 Expire 卻失敗了,并且只有在獲取到鎖時(shí)才設(shè)置過期時(shí)間。