一:通過redis實現(xiàn)
redis是基于單線程,在某個時刻只會有一個線程執(zhí)行命令,可以利用set原子性的操作,配合set nx(RedisStringCommands.SetOption.SET_IF_ABSENT) ,這樣,當(dāng)多個線程或多個節(jié)點嘗試獲取鎖時,只有一個可以成功,其他的會因為鎖已存在而獲取失敗。這種方式通過 Redis 來實現(xiàn)分布式鎖,可以確保在不同的應(yīng)用實例或節(jié)點之間同步對共享資源的訪問,從而避免并發(fā)沖突。
優(yōu)點:實現(xiàn)簡單,在內(nèi)存的中獲取的鎖,很快。
缺點:鎖有點重,對AB倆個線程,A在某一時刻獲取了鎖,B線程只能等待。B線程需要阻塞。
可能出現(xiàn)的問題:會造成死鎖的情況,當(dāng)A競爭到了鎖,如果A在此刻由于內(nèi)部異常造成A掛了,沒有釋放掉鎖,就會造成B死鎖。
死鎖處理方案:
1、設(shè)置一個key的TTL過期時間。
2、處理完之后,主動將鎖釋放(將key del掉)
3、當(dāng)然除了以上倆種常用的處理方式還可以使用樂觀鎖的處理方式。樂觀鎖通過維護一個版本號,如果版本號和鎖的版本號一直即可獲得鎖,和其他的樂觀鎖類似,樂觀鎖在一定程度上可以防止死鎖,但也會存在缺點:系統(tǒng)必要的開銷會增大,若版本號不一致,會一直比對版本號,若鎖被頻繁搶奪可能對系統(tǒng)的性能產(chǎn)生影響。
4、使用紅鎖redLock,基本思想:在多個redis節(jié)點中,使用全局唯一的key,設(shè)置不同的value(可以為uuid、時間戳等),當(dāng)set的value和攜帶的value大部分節(jié)點的值一致則說明獲取到鎖成功。(為啥要大部分,不要完全?因為在不同的節(jié)點setkey可能會有網(wǎng)絡(luò)延遲,時鐘漂移等情況?;蛘邩O端情況下,高并發(fā)多個節(jié)點同時set成功)
二、通過MQ實現(xiàn)
1、可以通過設(shè)置MQ隊列
channel.queueDeclare("myLockQueue", false, true, false, arguments);
將參數(shù)設(shè)置 exclusive=true
和 durable=false
,確保它是一個獨占隊列只能有一個連接且非持久化的隊列。
在綁定了此隊列的消費者,獲取鎖的時候,在同一時刻只能有一個消費者能夠去消費此隊列里面的消息,在消費者消費完之后就將隊列的里面的鎖重新publish上去。等待第二個消費者進行消費。
鎖的產(chǎn)生:
- 當(dāng)一個消費者需要獲取鎖時,它向隊列發(fā)送一個消息,表示它要獲取鎖。
- 由于隊列是獨占的,同一時刻只能有一個消費者能夠消費隊列中的消息。
鎖的釋放:
當(dāng)獲取到鎖的消費者獲取到之后,就重新將“鎖”消息publish上去,等待下一個消費者獲取。
基于MQ的方式實現(xiàn)的分布式鎖也會產(chǎn)生一些問題:
1、當(dāng)消息丟失了,如果時在消費者消費完之后往隊列里面添加釋放鎖的消息,消息沒有推送到隊列里面去,就會造成其他已經(jīng)進入隊列想要獲取到鎖的消費者進行死鎖或者鎖無法釋放。基于這種問題的解決方案可以使用重試機制,在一定次數(shù)的重試方式避免引發(fā)上述問題。文章來源:http://www.zghlxwxcb.cn/news/detail-802362.html
2、在并發(fā)的場景下,由于MQ的消息是異步的,本身在獲取鎖的時候就會帶來時間的延遲問題,某個消息丟失,消費者A和消費者B在處理的消息時,消息的狀態(tài)不一致,導(dǎo)致消費者A誤以為拿到了鎖,而繼續(xù)業(yè)務(wù)邏輯操作。文章來源地址http://www.zghlxwxcb.cn/news/detail-802362.html
到了這里,關(guān)于分布式鎖的幾種實現(xiàn)方式:的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!