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