欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

2021年最新Redis面試題匯總(4)

 更新時(shí)間:2021年07月15日 17:32:35   作者:java李楊勇  
在程序員面試過(guò)程中redis相關(guān)的知識(shí)是常被問到的話題。這篇文章主要介紹了幾道Redis面試題,整理一下分享給大家,感興趣的小伙伴們可以參考一下

1、Redis 實(shí)現(xiàn)分布式鎖

1)加鎖

加鎖通常使用 set 命令來(lái)實(shí)現(xiàn),偽代碼如下:

set key value PX milliseconds NX

幾個(gè)參數(shù)的意義如下:

key、value:鍵值對(duì)

PX milliseconds:設(shè)置鍵的過(guò)期時(shí)間為 milliseconds 毫秒。

NX:只在鍵不存在時(shí),才對(duì)鍵進(jìn)行設(shè)置操作。SET key value NX 效果等同于 SETNX key value。

PXexpireTime 參數(shù)則是用于解決沒有解鎖導(dǎo)致的死鎖問題。因?yàn)槿绻麤]有過(guò)期時(shí)間,萬(wàn)一程序員寫的代碼有 bug 導(dǎo)致沒有解鎖操作,則就出現(xiàn)了死鎖,因此該參數(shù)起到了一個(gè)“兜底”的作用。

NX 參數(shù)用于保證在多個(gè)線程并發(fā) set 下,只會(huì)有1個(gè)線程成功,起到了鎖的“唯一”性。

2)解鎖

解鎖需要兩步操作:

1)查詢當(dāng)前“鎖”是否還是我們持有,因?yàn)榇嬖谶^(guò)期時(shí)間,所以可能等你想解鎖的時(shí)候,“鎖”已經(jīng)到期,然后被其他線程獲取了,所以我們?cè)诮怄i前需要先判斷自己是否還持有“鎖”

2)如果“鎖”還是我們持有,則執(zhí)行解鎖操作,也就是刪除該鍵值對(duì),并返回成功;否則,直接返回失敗。

由于當(dāng)前 Redis 還沒有原子命令直接支持這兩步操作,所以當(dāng)前通常是使用 Lua 腳本來(lái)執(zhí)行解鎖操作,Redis 會(huì)保證腳本里的內(nèi)容執(zhí)行是一個(gè)原子操作。

腳本代碼如下,邏輯比較簡(jiǎn)單:

if redis.call("get",KEYS[1]) == ARGV[1]
then
    return redis.call("del",KEYS[1])
else
    return 0
end

兩個(gè)參數(shù)的意義如下:

KEYS[1]:我們要解鎖的 key

ARGV[1]:我們加鎖時(shí)的 value,用于判斷當(dāng)“鎖”是否還是我們持有,如果被其他線程持有了,value 就會(huì)發(fā)生變化。

上述方法是 Redis 當(dāng)前實(shí)現(xiàn)分布式鎖的主流方法,可能會(huì)有一些小優(yōu)區(qū)別,但是核心都是這個(gè)思路??粗孟駴]啥毛病,但是真的是這個(gè)樣子嗎?讓我們繼續(xù)往下看。

2、Redis 分布式鎖過(guò)期了,還沒處理完怎么辦

為了防止死鎖,我們會(huì)給分布式鎖加一個(gè)過(guò)期時(shí)間,但是萬(wàn)一這個(gè)時(shí)間到了,我們業(yè)務(wù)邏輯還沒處理完,怎么辦?

首先,我們?cè)谠O(shè)置過(guò)期時(shí)間時(shí)要結(jié)合業(yè)務(wù)場(chǎng)景去考慮,盡量設(shè)置一個(gè)比較合理的值,就是理論上正常處理的話,在這個(gè)過(guò)期時(shí)間內(nèi)是一定能處理完畢的。

之后,我們?cè)賮?lái)考慮對(duì)這個(gè)問題進(jìn)行兜底設(shè)計(jì)。

關(guān)于這個(gè)問題,目前常見的解決方法有兩種:

  • 守護(hù)線程“續(xù)命”:額外起一個(gè)線程,定期檢查線程是否還持有鎖,如果有則延長(zhǎng)過(guò)期時(shí)間。Redisson 里面就實(shí)現(xiàn)了這個(gè)方案,使用“看門狗”定期檢查(每1/3的鎖時(shí)間檢查1次),如果線程還持有鎖,則刷新過(guò)期時(shí)間。
  • 超時(shí)回滾:當(dāng)我們解鎖時(shí)發(fā)現(xiàn)鎖已經(jīng)被其他線程獲取了,說(shuō)明此時(shí)我們執(zhí)行的操作已經(jīng)是“不安全”的了,此時(shí)需要進(jìn)行回滾,并返回失敗。

同時(shí),需要進(jìn)行告警,人為介入驗(yàn)證數(shù)據(jù)的正確性,然后找出超時(shí)原因,是否需要對(duì)超時(shí)時(shí)間進(jìn)行優(yōu)化等等。

3、守護(hù)線程續(xù)命的方案有什么問題嗎

Redisson 使用看門狗(守護(hù)線程)“續(xù)命”的方案在大多數(shù)場(chǎng)景下是挺不錯(cuò)的,也被廣泛應(yīng)用于生產(chǎn)環(huán)境,但是在極端情況下還是會(huì)存在問題。

問題例子如下:

  1. 線程1首先獲取鎖成功,將鍵值對(duì)寫入 redis 的 master 節(jié)點(diǎn)
  2. 在 redis 將該鍵值對(duì)同步到 slave 節(jié)點(diǎn)之前,master 發(fā)生了故障
  3. redis 觸發(fā)故障轉(zhuǎn)移,其中一個(gè) slave 升級(jí)為新的 master此時(shí)新的 master
  4. 并不包含線程1寫入的鍵值對(duì),因此線程2嘗試獲取鎖也可以成功拿到鎖
  5. 此時(shí)相當(dāng)于有兩個(gè)線程獲取到了鎖,可能會(huì)導(dǎo)致各種預(yù)期之外的情況發(fā)生,例如最常見的臟數(shù)據(jù)

解決方法:上述問題的根本原因主要是由于 redis 異步復(fù)制帶來(lái)的數(shù)據(jù)不一致問題導(dǎo)致的,因此解決的方向就是保證數(shù)據(jù)的一致。

當(dāng)前比較主流的解法和思路有兩種:

1)Redis 作者提出的 RedLock;

2)Zookeeper 實(shí)現(xiàn)的分布式鎖。

4、RedLock

首先,該方案也是基于文章開頭的那個(gè)方案(set加鎖、lua腳本解鎖)進(jìn)行改良的,所以 antirez 只描述了差異的地方,大致方案如下。

假設(shè)我們有 N 個(gè) Redis 主節(jié)點(diǎn),例如 N = 5,這些節(jié)點(diǎn)是完全獨(dú)立的,我們不使用復(fù)制或任何其他隱式協(xié)調(diào)系統(tǒng),為了取到鎖,客戶端應(yīng)該執(zhí)行以下操作:

  • 獲取當(dāng)前時(shí)間,以毫秒為單位。
  • 依次嘗試從5個(gè)實(shí)例,使用相同的 key 和隨機(jī)值(例如UUID)獲取鎖。當(dāng)向Redis 請(qǐng)求獲取鎖時(shí),客戶端應(yīng)該設(shè)置一個(gè)超時(shí)時(shí)間,這個(gè)超時(shí)時(shí)間應(yīng)該小于鎖的失效時(shí)間。例如你的鎖自動(dòng)失效時(shí)間為10秒,則超時(shí)時(shí)間應(yīng)該在 5-50 毫秒之間。這樣可以防止客戶端在試圖與一個(gè)宕機(jī)的 Redis 節(jié)點(diǎn)對(duì)話時(shí)長(zhǎng)時(shí)間處于阻塞狀態(tài)。如果一個(gè)實(shí)例不可用,客戶端應(yīng)該盡快嘗試去另外一個(gè)Redis實(shí)例請(qǐng)求獲取鎖。
  • 客戶端通過(guò)當(dāng)前時(shí)間減去步驟1記錄的時(shí)間來(lái)計(jì)算獲取鎖使用的時(shí)間。當(dāng)且僅當(dāng)從大多數(shù)(N/2+1,這里是3個(gè)節(jié)點(diǎn))的Redis節(jié)點(diǎn)都取到鎖,并且獲取鎖使用的時(shí)間小于鎖失效時(shí)間時(shí),鎖才算獲取成功。
  • 如果取到了鎖,其真正有效時(shí)間等于初始有效時(shí)間減去獲取鎖所使用的時(shí)間(步驟3計(jì)算的結(jié)果)。
  • 如果由于某些原因未能獲得鎖(無(wú)法在至少N/2+1個(gè)Redis實(shí)例獲取鎖、或獲取鎖的時(shí)間超過(guò)了有效時(shí)間),客戶端應(yīng)該在所有的Redis實(shí)例上進(jìn)行解鎖(即便某些Redis實(shí)例根本就沒有加鎖成功,防止某些節(jié)點(diǎn)獲取到鎖但是客戶端沒有得到響應(yīng)而導(dǎo)致接下來(lái)的一段時(shí)間不能被重新獲取鎖)。

可以看出,該方案為了解決數(shù)據(jù)不一致的問題,直接舍棄了異步復(fù)制,只使用 master 節(jié)點(diǎn),同時(shí)由于舍棄了 slave,為了保證可用性,引入了 N 個(gè)節(jié)點(diǎn),官方建議是 5。

該方案看著挺美好的,但是實(shí)際上我所了解到的在實(shí)際生產(chǎn)上應(yīng)用的不多,主要有兩個(gè)原因:1)該方案的成本似乎有點(diǎn)高,需要使用5個(gè)實(shí)例;2)該方案一樣存在問題。

該方案主要存以下問題:

  • 嚴(yán)重依賴系統(tǒng)時(shí)鐘。如果線程1從3個(gè)實(shí)例獲取到了鎖,但是這3個(gè)實(shí)例中的某個(gè)實(shí)例的系統(tǒng)時(shí)間走的稍微快一點(diǎn),則它持有的鎖會(huì)提前過(guò)期被釋放,當(dāng)他釋放后,此時(shí)又有3個(gè)實(shí)例是空閑的,則線程2也可以獲取到鎖,則可能出現(xiàn)兩個(gè)線程同時(shí)持有鎖了。
  • 如果線程1從3個(gè)實(shí)例獲取到了鎖,但是萬(wàn)一其中有1臺(tái)重啟了,則此時(shí)又有3個(gè)實(shí)例是空閑的,則線程2也可以獲取到鎖,此時(shí)又出現(xiàn)兩個(gè)線程同時(shí)持有鎖了。

針對(duì)以上問題其實(shí)后續(xù)也有人給出一些相應(yīng)的解法,但是整體上來(lái)看還是不夠完美,所以目前實(shí)際應(yīng)用得不是那么多。

5、使用緩存時(shí),先操作數(shù)據(jù)庫(kù) or 先操作緩存

1)先操作數(shù)據(jù)庫(kù)

案例如下,有兩個(gè)并發(fā)的請(qǐng)求,一個(gè)寫請(qǐng)求,一個(gè)讀請(qǐng)求,流程如下:

​可能存在的臟數(shù)據(jù)時(shí)間范圍:更新數(shù)據(jù)庫(kù)后,失效緩存前。這個(gè)時(shí)間范圍很小,通常不會(huì)超過(guò)幾毫秒。

2)先操作緩存

案例如下,有兩個(gè)并發(fā)的請(qǐng)求,一個(gè)寫請(qǐng)求,一個(gè)讀請(qǐng)求,流程如下:

​可能存在的臟數(shù)據(jù)時(shí)間范圍:更新數(shù)據(jù)庫(kù)后,下一次對(duì)該數(shù)據(jù)的更新前。這個(gè)時(shí)間范圍不確定性很大,情況如下:

  • 如果下一次對(duì)該數(shù)據(jù)的更新馬上就到來(lái),那么會(huì)失效緩存,臟數(shù)據(jù)的時(shí)間就很短。
  • 如果下一次對(duì)該數(shù)據(jù)的更新要很久才到來(lái),那這期間緩存保存的一直是臟數(shù)據(jù),時(shí)間范圍很長(zhǎng)。

結(jié)論:通過(guò)上述案例可以看出,先操作數(shù)據(jù)庫(kù)和先操作緩存都會(huì)存在臟數(shù)據(jù)的情況。但是相比之下,先操作數(shù)據(jù)庫(kù),再操作緩存是更優(yōu)的方式,即使在并發(fā)極端情況下,也只會(huì)出現(xiàn)很小量的臟數(shù)據(jù)。

6、為什么是讓緩存失效,而不是更新緩存

1)更新緩存

案例如下,有兩個(gè)并發(fā)的寫請(qǐng)求,流程如下:

​分析:數(shù)據(jù)庫(kù)中的數(shù)據(jù)是請(qǐng)求B的,緩存中的數(shù)據(jù)是請(qǐng)求A的,數(shù)據(jù)庫(kù)和緩存存在數(shù)據(jù)不一致。

2)失效(刪除)緩存

案例如下,有兩個(gè)并發(fā)的寫請(qǐng)求,流程如下:

​分析:由于是刪除緩存,所以不存在數(shù)據(jù)不一致的情況。

結(jié)論:通過(guò)上述案例,可以很明顯的看出,失效緩存是更優(yōu)的方式。

7、如何保證數(shù)據(jù)庫(kù)和緩存的數(shù)據(jù)一致性

在上文的案例中,無(wú)論是先操作數(shù)據(jù)庫(kù),還是先操作緩存,都會(huì)存在臟數(shù)據(jù)的情況,有辦法避免嗎?

答案是有的,由于數(shù)據(jù)庫(kù)和緩存是兩個(gè)不同的數(shù)據(jù)源,要保證其數(shù)據(jù)一致性,其實(shí)就是典型的分布式事務(wù)場(chǎng)景,可以引入分布式事務(wù)來(lái)解決,常見的有:2PC、TCC、MQ事務(wù)消息等。

但是引入分布式事務(wù)必然會(huì)帶來(lái)性能上的影響,這與我們當(dāng)初引入緩存來(lái)提升性能的目的是相違背的。

所以在實(shí)際使用中,通常不會(huì)去保證緩存和數(shù)據(jù)庫(kù)的強(qiáng)一致性,而是做出一定的犧牲,保證兩者數(shù)據(jù)的最終一致性。

如果是實(shí)在無(wú)法接受臟數(shù)據(jù)的場(chǎng)景,則比較合理的方式是放棄使用緩存,直接走數(shù)據(jù)庫(kù)。

保證數(shù)據(jù)庫(kù)和緩存數(shù)據(jù)最終一致性的常用方案如下:

1)更新數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)產(chǎn)生 binlog。

2)監(jiān)聽和消費(fèi) binlog,執(zhí)行失效緩存操作。

3)如果步驟2失效緩存失敗,則引入重試機(jī)制,將失敗的數(shù)據(jù)通過(guò)MQ方式進(jìn)行重試,同時(shí)考慮是否需要引入冪等機(jī)制。

​兜底:當(dāng)出現(xiàn)未知的問題時(shí),及時(shí)告警通知,人為介入處理。

人為介入是終極大法,那些外表看著光鮮艷麗的應(yīng)用,其背后大多有一群苦逼的程序員,在不斷的修復(fù)各種臟數(shù)據(jù)和bug。

​8、緩存穿透

描述:訪問一個(gè)緩存和數(shù)據(jù)庫(kù)都不存在的 key,此時(shí)會(huì)直接打到數(shù)據(jù)庫(kù)上,并且查不到數(shù)據(jù),沒法寫緩存,所以下一次同樣會(huì)打到數(shù)據(jù)庫(kù)上。

此時(shí),緩存起不到作用,請(qǐng)求每次都會(huì)走到數(shù)據(jù)庫(kù),流量大時(shí)數(shù)據(jù)庫(kù)可能會(huì)被打掛。此時(shí)緩存就好像被“穿透”了一樣,起不到任何作用。

解決方案:

1)接口校驗(yàn)。在正常業(yè)務(wù)流程中可能會(huì)存在少量訪問不存在 key 的情況,但是一般不會(huì)出現(xiàn)大量的情況,所以這種場(chǎng)景最大的可能性是遭受了非法攻擊??梢栽谧钔鈱酉茸鲆粚有r?yàn):用戶鑒權(quán)、數(shù)據(jù)合法性校驗(yàn)等,例如商品查詢中,商品的ID是正整數(shù),則可以直接對(duì)非正整數(shù)直接過(guò)濾等等。

2)緩存空值。當(dāng)訪問緩存和DB都沒有查詢到值時(shí),可以將空值寫進(jìn)緩存,但是設(shè)置較短的過(guò)期時(shí)間,該時(shí)間需要根據(jù)產(chǎn)品業(yè)務(wù)特性來(lái)設(shè)置。

3)布隆過(guò)濾器。使用布隆過(guò)濾器存儲(chǔ)所有可能訪問的 key,不存在的 key 直接被過(guò)濾,存在的 key 則再進(jìn)一步查詢緩存和數(shù)據(jù)庫(kù)。

9、布隆過(guò)濾器

布隆過(guò)濾器的特點(diǎn)是判斷不存在的,則一定不存在;判斷存在的,大概率存在,但也有小概率不存在。并且這個(gè)概率是可控的,我們可以讓這個(gè)概率變小或者變高,取決于用戶本身的需求。

布隆過(guò)濾器由一個(gè) bitSet 和 一組 Hash 函數(shù)(算法)組成,是一種空間效率極高的概率型算法和數(shù)據(jù)結(jié)構(gòu),主要用來(lái)判斷一個(gè)元素是否在集合中存在。

在初始化時(shí),bitSet 的每一位被初始化為0,同時(shí)會(huì)定義 Hash 函數(shù),例如有3組 Hash 函數(shù):hash1、hash2、hash3。

寫入流程

當(dāng)我們要寫入一個(gè)值時(shí),過(guò)程如下,以“jionghui”為例:

1)首先將“jionghui”跟3組 Hash 函數(shù)分別計(jì)算,得到 bitSet 的下標(biāo)為:1、7、10。

2)將 bitSet 的這3個(gè)下標(biāo)標(biāo)記為1。

假設(shè)我們還有另外兩個(gè)值:java 和 diaosi,按上面的流程跟 3組 Hash 函數(shù)分別計(jì)算,結(jié)果如下:

java:Hash 函數(shù)計(jì)算 bitSet 下標(biāo)為:1、7、11

diaosi:Hash 函數(shù)計(jì)算 bitSet 下標(biāo)為:4、10、11

查詢流程

當(dāng)我們要查詢一個(gè)值時(shí),過(guò)程如下,同樣以“jionghui”為例::

1)首先將“jionghui”跟3組 Hash 函數(shù)分別計(jì)算,得到 bitSet 的下標(biāo)為:1、7、10。

2)查看 bitSet 的這3個(gè)下標(biāo)是否都為1,如果這3個(gè)下標(biāo)不都為1,則說(shuō)明該值必然不存在,如果這3個(gè)下標(biāo)都為1,則只能說(shuō)明可能存在,并不能說(shuō)明一定存在。

其實(shí)上圖的例子已經(jīng)說(shuō)明了這個(gè)問題了,當(dāng)我們只有值“jionghui”和“diaosi”時(shí),bitSet 下標(biāo)為1的有:1、4、7、10、11。

當(dāng)我們又加入值“java”時(shí),bitSet 下標(biāo)為1的還是這5個(gè),所以當(dāng) bitSet 下標(biāo)為1的為:1、4、7、10、11 時(shí),我們無(wú)法判斷值“java”存不存在。

其根本原因是,不同的值在跟 Hash 函數(shù)計(jì)算后,可能會(huì)得到相同的下標(biāo),所以某個(gè)值的標(biāo)記位,可能會(huì)被其他值給標(biāo)上了。

這也是為啥布隆過(guò)濾器只能判斷某個(gè)值可能存在,無(wú)法判斷必然存在的原因。但是反過(guò)來(lái),如果該值根據(jù) Hash 函數(shù)計(jì)算的標(biāo)記位沒有全部都為1,那么則說(shuō)明必然不存在,這個(gè)是肯定的。

降低這種誤判率的思路也比較簡(jiǎn)單:

  • 一個(gè)是加大 bitSet 的長(zhǎng)度,這樣不同的值出現(xiàn)“沖突”的概率就降低了,從而誤判率也降低。
  • 提升 Hash 函數(shù)的個(gè)數(shù),Hash 函數(shù)越多,每個(gè)值對(duì)應(yīng)的 bit 越多,從而誤判率也降低。

布隆過(guò)濾器的誤判率還有專門的推導(dǎo)公式,有興趣的可以去搜相關(guān)的文章和論文查看。

10、緩存擊穿

描述:某一個(gè)熱點(diǎn) key,在緩存過(guò)期的一瞬間,同時(shí)有大量的請(qǐng)求打進(jìn)來(lái),由于此時(shí)緩存過(guò)期了,所以請(qǐng)求最終都會(huì)走到數(shù)據(jù)庫(kù),造成瞬時(shí)數(shù)據(jù)庫(kù)請(qǐng)求量大、壓力驟增,甚至可能打垮數(shù)據(jù)庫(kù)。

解決方案:

1)加互斥鎖。在并發(fā)的多個(gè)請(qǐng)求中,只有第一個(gè)請(qǐng)求線程能拿到鎖并執(zhí)行數(shù)據(jù)庫(kù)查詢操作,其他的線程拿不到鎖就阻塞等著,等到第一個(gè)線程將數(shù)據(jù)寫入緩存后,直接走緩存。

關(guān)于互斥鎖的選擇,網(wǎng)上看到的大部分文章都是選擇 Redis 分布式鎖(可以參考我之前的文章:面試必問的分布式鎖,你懂了嗎?),因?yàn)檫@個(gè)可以保證只有一個(gè)請(qǐng)求會(huì)走到數(shù)據(jù)庫(kù),這是一種思路。

但是其實(shí)仔細(xì)想想的話,這邊其實(shí)沒有必要保證只有一個(gè)請(qǐng)求走到數(shù)據(jù)庫(kù),只要保證走到數(shù)據(jù)庫(kù)的請(qǐng)求能大大降低即可,所以還有另一個(gè)思路是 JVM 鎖。

JVM 鎖保證了在單臺(tái)服務(wù)器上只有一個(gè)請(qǐng)求走到數(shù)據(jù)庫(kù),通常來(lái)說(shuō)已經(jīng)足夠保證數(shù)據(jù)庫(kù)的壓力大大降低,同時(shí)在性能上比分布式鎖更好。

需要注意的是,無(wú)論是使用“分布式鎖”,還是“JVM 鎖”,加鎖時(shí)要按 key 維度去加鎖。

我看網(wǎng)上很多文章都是使用一個(gè)“固定的 key”加鎖,這樣會(huì)導(dǎo)致不同的 key 之間也會(huì)互相阻塞,造成性能嚴(yán)重?fù)p耗。

使用 redis 分布式鎖的偽代碼,僅供參考:

public Object getData(String key) throws InterruptedException {
    Object value = redis.get(key);
    // 緩存值過(guò)期
    if (value == null) {
        // lockRedis:專門用于加鎖的redis;
        // "empty":加鎖的值隨便設(shè)置都可以
        if (lockRedis.set(key, "empty", "PX", lockExpire, "NX")) {
            try {
                // 查詢數(shù)據(jù)庫(kù),并寫到緩存,讓其他線程可以直接走緩存
                value = getDataFromDb(key);
                redis.set(key, value, "PX", expire);
            } catch (Exception e) {
                // 異常處理
            } finally {
                // 釋放鎖
                lockRedis.delete(key);
            }
        } else {
            // sleep50ms后,進(jìn)行重試
            Thread.sleep(50);
            return getData(key);
        }
    }
    return value;
}

2)熱點(diǎn)數(shù)據(jù)不過(guò)期。直接將緩存設(shè)置為不過(guò)期,然后由定時(shí)任務(wù)去異步加載數(shù)據(jù),更新緩存。

這種方式適用于比較極端的場(chǎng)景,例如流量特別特別大的場(chǎng)景,使用時(shí)需要考慮業(yè)務(wù)能接受數(shù)據(jù)不一致的時(shí)間,還有就是異常情況的處理,不要到時(shí)候緩存刷新不上,一直是臟數(shù)據(jù),那就涼了。

11、緩存雪崩

描述:大量的熱點(diǎn) key 設(shè)置了相同的過(guò)期時(shí)間,導(dǎo)在緩存在同一時(shí)刻全部失效,造成瞬時(shí)數(shù)據(jù)庫(kù)請(qǐng)求量大、壓力驟增,引起雪崩,甚至導(dǎo)致數(shù)據(jù)庫(kù)被打掛。

緩存雪崩其實(shí)有點(diǎn)像“升級(jí)版的緩存擊穿”,緩存擊穿是一個(gè)熱點(diǎn) key,緩存雪崩是一組熱點(diǎn) key。

解決方案:

1)過(guò)期時(shí)間打散。既然是大量緩存集中失效,那最容易想到就是讓他們不集中生效??梢越o緩存的過(guò)期時(shí)間時(shí)加上一個(gè)隨機(jī)值時(shí)間,使得每個(gè) key 的過(guò)期時(shí)間分布開來(lái),不會(huì)集中在同一時(shí)刻失效。

2)熱點(diǎn)數(shù)據(jù)不過(guò)期。該方式和緩存擊穿一樣,也是要著重考慮刷新的時(shí)間間隔和數(shù)據(jù)異常如何處理的情況。

3)加互斥鎖。該方式和緩存擊穿一樣,按 key 維度加鎖,對(duì)于同一個(gè) key,只允許一個(gè)線程去計(jì)算,其他線程原地阻塞等待第一個(gè)線程的計(jì)算結(jié)果,然后直接走緩存即可。

總結(jié)

本篇文章就到這里了,希望能給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

2021年最新Redis面試題匯總(1)

2021年最新Redis面試題匯總(2)

2021年最新Redis面試題匯總(3)

相關(guān)文章

  • SWT(JFace) 體驗(yàn)之FontRegistry

    SWT(JFace) 體驗(yàn)之FontRegistry

    測(cè)試代碼如下:
    2009-06-06
  • Spring集成Mybatis過(guò)程詳細(xì)講解

    Spring集成Mybatis過(guò)程詳細(xì)講解

    mybatis-plus是一個(gè)Mybatis的增強(qiáng)工具,在Mybatis的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生,下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合Mybatis-plus案例及用法實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • 帶你3分鐘帶你搞定Spring Boot中Schedule

    帶你3分鐘帶你搞定Spring Boot中Schedule

    本文主要圍繞Spring scheduled應(yīng)用實(shí)踐進(jìn)行分享,如果是單體應(yīng)用,使用SpringBoot內(nèi)置的@scheduled注解可以解決大部分業(yè)務(wù)需求,對(duì)Spring Boot中Schedule 相關(guān)知識(shí)感興趣的朋友一起看看吧
    2024-07-07
  • java中的定時(shí)器和多線程

    java中的定時(shí)器和多線程

    這篇文章主要介紹了java中的定時(shí)器和多線程用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • SpringBoot3集成和使用Jasypt的代碼詳解

    SpringBoot3集成和使用Jasypt的代碼詳解

    隨著信息安全的日益受到重視,加密敏感數(shù)據(jù)在應(yīng)用程序中變得越來(lái)越重要,Jasypt作為一個(gè)簡(jiǎn)化Java應(yīng)用程序中數(shù)據(jù)加密的工具,為開發(fā)者提供了一種便捷而靈活的加密解決方案,本文將深入解析Jasypt的工作原理,需要的朋友可以參考下
    2024-01-01
  • SpringBoot整合微信小程序支付V3(支付退款)

    SpringBoot整合微信小程序支付V3(支付退款)

    小程序支付在很多項(xiàng)目都會(huì)使用,本文主要介紹了SpringBoot整合微信小程序支付V3,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Java?數(shù)據(jù)結(jié)構(gòu)與算法系列精講之?dāng)?shù)組

    Java?數(shù)據(jù)結(jié)構(gòu)與算法系列精講之?dāng)?shù)組

    數(shù)組是有序的元素序列,若將有限個(gè)類型相同的變量的集合命名,那么這個(gè)名稱為數(shù)組名。組成數(shù)組的各個(gè)變量稱為數(shù)組的分量,也稱為數(shù)組的元素,有時(shí)也稱為下標(biāo)變量。數(shù)組是在程序設(shè)計(jì)中,為了處理方便, 把具有相同類型的若干元素按有序的形式組織起來(lái)的一種形式
    2022-02-02
  • java初學(xué)者如何讓編程學(xué)習(xí)起來(lái)更簡(jiǎn)單

    java初學(xué)者如何讓編程學(xué)習(xí)起來(lái)更簡(jiǎn)單

    我們給大家?guī)?lái)一篇關(guān)于java初學(xué)者如何讓編程學(xué)習(xí)起來(lái)更簡(jiǎn)單的基礎(chǔ)性文章,有需要的朋友們可以學(xué)習(xí)下。
    2020-11-11
  • JAVA技術(shù)實(shí)現(xiàn)上傳下載文件到FTP服務(wù)器(完整)

    JAVA技術(shù)實(shí)現(xiàn)上傳下載文件到FTP服務(wù)器(完整)

    這篇文章主要介紹了JAVA技術(shù)實(shí)現(xiàn)上傳下載文件到FTP服務(wù)器(完整),本文使用 Apache Jakarta Commons Net(commons-net-3.3.jar) 基于FileZilla Server服務(wù)器實(shí)現(xiàn)FTP服務(wù)器上文件的上傳/下載/刪除等操作,需要的朋友可以參考下
    2015-07-07
  • Java switch case數(shù)據(jù)類型原理解析

    Java switch case數(shù)據(jù)類型原理解析

    這篇文章主要介紹了Java switch case數(shù)據(jù)類型原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01

最新評(píng)論