貴州潤(rùn)鐵祥建設(shè)工程有限公司網(wǎng)站外包公司軟件開(kāi)發(fā)
目錄
- Redis的租約問(wèn)題
- Redis租約問(wèn)題的想法
- Redis租約問(wèn)題的解決方案
Redis的租約問(wèn)題
首先我們先來(lái)說(shuō)一說(shuō)什么是Redis的租約問(wèn)題。
??在我們實(shí)現(xiàn)Redis分布式鎖的時(shí)候,我們會(huì)出現(xiàn)Redis鎖的時(shí)間<業(yè)務(wù)執(zhí)行執(zhí)行時(shí)間,這其實(shí)就是一個(gè)典型的租約問(wèn)題,那么什么是租約問(wèn)題呢?我們讓用戶(hù)線程獲取鎖之后,同時(shí)為了防止用戶(hù)進(jìn)程產(chǎn)生錯(cuò)誤而無(wú)法釋放鎖,導(dǎo)致其他用戶(hù)再也無(wú)法獲取不到鎖產(chǎn)生的死鎖現(xiàn)象,所以我們?yōu)槊恳粋€(gè)鎖設(shè)定一個(gè)Expire Time,這樣即使在用戶(hù)進(jìn)程不能正常釋放鎖的情況下,過(guò)期時(shí)間到了之后,Redis會(huì)自動(dòng)釋放掉鎖來(lái)讓別的用戶(hù)來(lái)獲取到鎖。
??這就是典型的租約機(jī)制,用戶(hù)申請(qǐng)了一個(gè)租約時(shí)長(zhǎng)為lock_timeout的鎖,用戶(hù)可以在租約期間使用完之后正常釋放鎖,如果說(shuō)了租約時(shí)間,即使用戶(hù)沒(méi)有釋放鎖,Redis也會(huì)自動(dòng)釋放鎖。
?
?
Redis租約問(wèn)題的想法
??我們來(lái)設(shè)想一下,如果用戶(hù)可以很清晰的知道自己將要使用鎖的時(shí)間,那么我們?cè)O(shè)置lock_timeout就很容易了,但是如果當(dāng)用戶(hù)并不知道自己用鎖的時(shí)間,設(shè)置租約就會(huì)是一個(gè)困難,當(dāng)然,一般都不知道。我們?cè)O(shè)置租約時(shí)間
- 如果我們?cè)O(shè)置的時(shí)間過(guò)短,那么可以用戶(hù)還沒(méi)用完鎖,鎖就被Redis釋放掉了,之后多個(gè)用戶(hù)訪問(wèn)一個(gè)共享資源產(chǎn)生錯(cuò)誤。
- 如果我們?cè)O(shè)置的時(shí)間過(guò)長(zhǎng),那么當(dāng)用戶(hù)如果產(chǎn)生錯(cuò)誤不能正常釋放鎖的時(shí)候,其他用戶(hù)線程就需要等待較長(zhǎng)的時(shí)間才能獲取到鎖。
所以,我們就萌生出一個(gè)想法:當(dāng)用戶(hù)并不知道自己會(huì)用多久的時(shí)間,那么我們?yōu)樵撴i設(shè)置一個(gè)較小的lock_timeout,同時(shí)在該鎖的過(guò)期之前,就自動(dòng)的向服務(wù)器延長(zhǎng)該鎖的lifetime.
?
?
Redis租約問(wèn)題的解決方案
Redis租約問(wèn)題一般有兩個(gè)解決方案。
- 業(yè)務(wù)調(diào)研
我們需要大量測(cè)試我們業(yè)務(wù)的執(zhí)行時(shí)間,然后可以將我們所的過(guò)期時(shí)間設(shè)置為業(yè)務(wù)時(shí)間的1.5倍,給他充分的冗余時(shí)間。但是如果我們考慮更多的異常情況發(fā)生的話,那么我們這種方法可能不太靠譜。所以就有了第二種方法。 - 鎖的續(xù)約
鎖的續(xù)約,我們?cè)谌ゼ渔i的時(shí)候,一般都會(huì)去啟動(dòng)一個(gè)線程,而在開(kāi)啟這個(gè)啟動(dòng)線程的時(shí)候,我們同樣去啟動(dòng)一個(gè)守護(hù)線程,這個(gè)守護(hù)線程,我們就可以用來(lái)作為鎖的續(xù)命。過(guò)程:
假設(shè)我們用戶(hù)拿到了我們的鎖,但是我們的業(yè)務(wù)時(shí)間遠(yuǎn)遠(yuǎn)大于我們加鎖的時(shí)間,如果我們的鎖快到我們的過(guò)期時(shí)間的時(shí)候,比如過(guò)期時(shí)間的前5s,這個(gè)時(shí)候我們就可以用我們的守護(hù)線程去掃它,看看我們的業(yè)務(wù)有沒(méi)有執(zhí)行完,如果沒(méi)有執(zhí)行完,那么續(xù)約同樣的lock_timeout,以此類(lèi)推,確保我們當(dāng)前的加鎖時(shí)間大于我們的業(yè)務(wù)執(zhí)行時(shí)間,這個(gè)是鎖續(xù)約的核心思想。
那么我們這么做可能會(huì)出現(xiàn)什么問(wèn)題?
在我們進(jìn)行業(yè)務(wù)調(diào)研后,我們得出了我們業(yè)務(wù)時(shí)間的平均值,如果我們的用戶(hù)線程在執(zhí)行過(guò)程中出現(xiàn)了問(wèn)題,那么業(yè)務(wù)執(zhí)行時(shí)間就會(huì)無(wú)限長(zhǎng),那么我們的豈不是會(huì)進(jìn)行無(wú)限的續(xù)約?所以簡(jiǎn)單的設(shè)計(jì)有點(diǎn)不太合理。
那么怎么解決呢?
我們的解決方案是使用重試次數(shù)(這個(gè)重試次數(shù)是重點(diǎn))
假設(shè)我們的業(yè)務(wù)的執(zhí)行時(shí)間平均是10s,那么我們最多容忍它執(zhí)行50s如果他還沒(méi)有執(zhí)行完成,那么我們就認(rèn)為的服務(wù)器或者代碼有問(wèn)題,我們需要進(jìn)行人為干預(yù)。這里的話,我們需要重試四次即可。
?
?
注意:我們的守護(hù)線程是依賴(lài)于我們的用戶(hù)線程而生的,用戶(hù)線程死,我們的守護(hù)線程就死,所以我們守護(hù)線程來(lái)進(jìn)行續(xù)命,用戶(hù)線程在,守護(hù)線程就在,就可以續(xù)命。
?
?
?
這里使用了Lua腳本,Lua腳本的作用在于保證原子性,它能確保Lua腳本里面的內(nèi)容要么同時(shí)執(zhí)行,要么同時(shí)不執(zhí)行。
?
?
?
?
??
??
??