一.可以使用redis,zookeeper,etcd是實(shí)現(xiàn)分布式鎖
二.redis主要是通過setnx、get、getset、del命令來完成加鎖,搶鎖和釋放鎖的操作的。
1.setnx實(shí)現(xiàn)加鎖,返回1加鎖成功
2.get查看鎖是否超時(shí)
3.超時(shí)了使用getset搶鎖
4.del實(shí)現(xiàn)釋放鎖
redis存在的問題
1、redis如果是單機(jī)的話是有單點(diǎn)問題的。
redis集群因?yàn)槭莂p模型,是不能保證一致性的,官方提供了redlock算法來解決這個(gè)問題,但是至少需要3個(gè)master-slave節(jié)點(diǎn)才能完成,成本也較大。redlock相當(dāng)于是來實(shí)現(xiàn)一致性協(xié)議的。
2、鎖的超時(shí)時(shí)間設(shè)定問題,太長(zhǎng)太短都不合適,太長(zhǎng)了如果服務(wù)掛掉了會(huì)一直阻塞業(yè)務(wù),太短了有可能業(yè)務(wù)還沒執(zhí)行完成就釋放了。當(dāng)然可以用官方提供redisson解決。
三.zookeeper是基于順序臨時(shí)節(jié)點(diǎn)和watch機(jī)制實(shí)現(xiàn)分布式鎖的
1.順序節(jié)點(diǎn)可以保證最小的節(jié)點(diǎn)獲取鎖
2.臨時(shí)節(jié)點(diǎn)可以保證業(yè)務(wù)掛了,可以釋放鎖
3.監(jiān)聽機(jī)制可以保證鎖釋放后及時(shí)得到通知,再次獲取鎖
zk采用zab協(xié)議保證一致性,并且不用設(shè)置超時(shí)時(shí)間了,如果服務(wù)加鎖掛掉了,臨時(shí)節(jié)點(diǎn)也會(huì)自動(dòng)刪除。也可用使用Apache開源的curator框架,自帶了分布式鎖解決方案,原理和上述差不多。zk加鎖釋放鎖都是通過動(dòng)態(tài)創(chuàng)建節(jié)點(diǎn)、銷毀節(jié)點(diǎn)來實(shí)現(xiàn)的,性能消耗較大。
四.etcd調(diào)用可以通過restfulAPI的方式進(jìn)行,這些需要通過prevExist實(shí)現(xiàn)分布式鎖,如果prevExist為true,則這是一個(gè)更新請(qǐng)求,如果prevExist的值是false,則是一個(gè)創(chuàng)建請(qǐng)求。
1.server1獲取鎖,設(shè)置超時(shí)時(shí)間是3秒http://127.0.0.1:2379/v2/keys/locks?value=xxx&ttl=3&prevExist=false
2.為了防止業(yè)務(wù)還沒有執(zhí)行完,鎖釋放,所以每隔1秒需求重新設(shè)置下值。這個(gè)就是鎖續(xù)租約。http://127.0.0.1:2379/v2/keys/locks?value=xxx&ttl=3&prevExist=true
3.server2這時(shí)候去獲取鎖,則會(huì)失敗http://127.0.0.1:2379/v2/keys/locks?value=xxx&ttl=3&prevExist=false
4.server2可以監(jiān)聽lock的變化。當(dāng)lock目錄有變化的時(shí)候就會(huì)接到通知,然后重復(fù)步驟3。這里要注意watch事件不能太多。http://127.0.0.1:2379/v2/keys/lock?wait=true
上面這個(gè)是etcd2的實(shí)現(xiàn),etcd3本身已經(jīng)支持分布式鎖了,key增加Revision了,客戶端可以判定自己key對(duì)應(yīng)的Revision是不是最小來獲取鎖,機(jī)制和zk獲取最小值類似。
上面就是redis、zk、etcd怎么實(shí)現(xiàn)分布式鎖的過程了。每種方案都有公司在使用,也比較成熟了。
只要能保持讀取和修改狀態(tài)是原子性操作都能當(dāng)鎖使用,但是分布式鎖需要明確的幾個(gè)條件:
獲取鎖的業(yè)務(wù)無論正常還是異常,都需要保證可以釋放,否則會(huì)出現(xiàn)死鎖的情況,還有就是鎖釋放后需要及時(shí)讓等待鎖的一方知道,方便再次獲取鎖。
希望對(duì)你有幫助,可以看我分享的另一文章,里面有每一步操作的截圖。
我,后續(xù)會(huì)持續(xù)分享架構(gòu)方面文章,謝謝。