2023-06-23:redis中什么是緩存擊穿?該如何解決?
2023-06-23:redis中什么是緩存擊穿?該如何解決?
答案2023-06-23:
緩存擊穿是指一個緩存中的熱點(diǎn)數(shù)據(jù)非常頻繁地被大量并發(fā)請求訪問,當(dāng)該熱點(diǎn)數(shù)據(jù)失效的瞬間,持續(xù)的大并發(fā)請求無法通過緩存獲取到數(shù)據(jù),而直接訪問數(shù)據(jù)庫,這就好像在一個穩(wěn)固完好的容器上打開了一個洞。
解決緩存擊穿問題的方法包括:
1.設(shè)置熱點(diǎn)數(shù)據(jù)永不過期:將熱點(diǎn)數(shù)據(jù)的緩存過期時間設(shè)置為較長的時間,甚至是永不過期。這確保即使緩存失效,該數(shù)據(jù)仍然可用,從而繞過了緩存擊穿的問題。然而,這種方法可能導(dǎo)致緩存數(shù)據(jù)過期不及時的問題,使得數(shù)據(jù)不夠及時和準(zhǔn)確。
2.使用互斥鎖(Mutex):在數(shù)據(jù)失效時,當(dāng)有新請求到來時,可以通過設(shè)置互斥鎖來保護(hù)數(shù)據(jù)庫訪問過程。如果某個請求已經(jīng)獲取到了鎖,其他請求則需要等待,直到獲取到鎖為止。這樣可以避免大量并發(fā)請求同時訪問數(shù)據(jù)庫,減輕數(shù)據(jù)庫的壓力。然而,使用互斥鎖可能導(dǎo)致并發(fā)性能下降和請求等待時間增加的問題,需要權(quán)衡考慮。
使用互斥鎖
業(yè)界常用的做法是使用互斥鎖(Mutex)。簡單地說,當(dāng)緩存失效時(即獲取的值為空),不會立即去從數(shù)據(jù)庫加載數(shù)據(jù),而是通過緩存工具的某些帶有成功操作返回值的方法(例如Redis的SETNX)來設(shè)置一個互斥鎖鍵(Mutex Key)。如果該操作返回成功,表示當(dāng)前線程獲得了互斥鎖,然后可以繼續(xù)執(zhí)行加載數(shù)據(jù)的操作,并將數(shù)據(jù)回寫至緩存;否則,它將重試整個獲取緩存的方法。
偽代碼如下圖:

永遠(yuǎn)不過期
這里的“永遠(yuǎn)不過期”包含兩層意思:
(1) 在Redis等緩存工具中,確實可以將某些熱點(diǎn)key的過期時間設(shè)置為永不過期,即不設(shè)置過期時間。這樣可以確保熱點(diǎn)數(shù)據(jù)在緩存中一直存在,避免了熱點(diǎn)key過期的問題,實現(xiàn)了“物理”不過期。
(2) 為了保證緩存的實時性和更新能力,雖然在"物理"上不過期,但可以將過期時間的信息存儲在key對應(yīng)的value中。當(dāng)發(fā)現(xiàn)數(shù)據(jù)即將過期時,可以通過后臺的異步線程來進(jìn)行緩存的構(gòu)建或更新,這樣實現(xiàn)了"邏輯"過期。這樣的策略能夠確保緩存在一定時間內(nèi)保持有效,并在過期前進(jìn)行更新,使數(shù)據(jù)保持最新。
從實際應(yīng)用的角度來看,這種緩存策略對性能非常友好。它唯一的缺點(diǎn)是在構(gòu)建緩存期間,其他線程(非構(gòu)建緩存的線程)可能訪問到舊的數(shù)據(jù)。然而,對于一般的互聯(lián)網(wǎng)應(yīng)用功能而言,這個問題是可以容忍的。