老徐和阿珍的故事:快取穿透、快取擊穿、快取雪崩、快取熱點,傻傻分不清楚
- 2022 年 3 月 28 日
- 筆記
人物背景:
老徐,男,本名徐福貴,從事Java相關研發工作多年,職場老油條,摸魚小能手,雖然歲數不大但長的比較著急,人稱老徐。據說之前炒某幣敗光了所有家產,甚至現在還有欠債。
阿珍,女,本名陳家珍,剛剛入職不久的實習生,雖然是職場菜鳥但聰明好學。據說是學校的四大校花之一,追求她的人從旺角排到了銅鑼灣,不過至今還單身。

阿珍:「在高並發下遇到瓶頸的時候,經常會用到快取來提高整個系統的性能。」
老徐:「嗯,不過快取能夠大大提升整個系統的性能,但同時也引入了更多複雜性。」
阿珍點了點頭,說:「是啊,快取穿透、快取擊穿、快取雪崩、快取熱點這些東西,這些東西我一直分不清楚,經常混淆。」
老徐立刻自信滿滿地說:「這個我懂啊,你聽我給你娓娓道來。」
快取穿透
快取穿透是指在查詢快取數據時,快取和資料庫中都沒有對應數據,在快取中找不到對應的數據,每次都要去資料庫中再查詢一遍,然後返回數據不存在。
在這個場景中,快取並沒有起到分擔資料庫訪問壓力的作用。讀取不存在的數據的請求量一般不會太大,但如果出現一些惡意攻擊,故意大量訪問某些不存在的數據,就會對資料庫造成很多壓力。
阿珍:「太可怕了,萬一遇到了這樣攻擊,該怎麼辦呀?」
老徐:「這個很好應對的,一般有兩種辦法。」
第一個是:如果查詢資料庫中的數據沒有找到,則直接設置一個特定值存到快取中。之後讀取快取時就會獲取到這個特定值,直接返回空值,就不會繼續訪問資料庫了。
第二個是:把已存在數據的key存放在布隆過濾器中。當有新的請求時,先到布隆過濾器中查詢是否存在,如果不存在該條數據直接返回;如果存在該條數據再查詢快取查詢資料庫。

快取擊穿
快取擊穿是指在查詢快取數據時,資料庫原本有得數據,但是快取中沒有,生成快取數據需要耗費較長時間或者大量資源,這時候如果有大量請求該數據,會對資料庫甚至系統造成較大壓力。
阿珍:「哦?該怎麼解決呀?」
老徐:「這個很好解決,一般有兩個做法。」
第一個是:對快取更新操作加入鎖的保護,保證只有一個執行緒能夠進行快取更新的操作,沒有獲取更新鎖的執行緒要麼等待鎖釋放後重新讀取快取,要麼直接返回空值或者默認值。
第二個是:後台作業定時更新快取,而不是在訪問頁面時生成快取數據。這樣可以按照一定策略定時更新快取,不會對存儲系統較大的瞬時壓力。

快取雪崩
快取雪崩是指當大量快取同時失效或過期後,大量請求直接訪問對資料庫,甚至耗費較長時間或者大量資源計算快取結果,引起系統性能的急劇下降。
阿珍搶先說道:「這個我知道怎麼解決!」老徐反問:「怎麼解決?」
阿珍回答:「同一類型的快取的過期時間可以設置一個隨機值,比如:原來的過期時間是5分鐘,在此基礎上加060秒,那麼過期時間就變為在56分鐘內波動,有效防止都在同一個時間點上大量快取過期。」
快取熱點
快取熱點是指大部分甚至所有的業務請求都命中同一份快取數據。
雖然快取本身的性能比較高,但對於一些特別熱點的數據,如果大部分甚至所有的請求都命中同一份快取數據,則這份數據所在的快取伺服器的壓力也會很大。比如,電商的爆品秒殺活動,短時間內被上千萬的用戶訪問。
阿珍:「遇到了這種情況,該怎麼辦呀?」
老徐:「這個很好解決的,一般有兩種辦法:複製多份快取副本和本地記憶體快取。」
複製多份快取副本,就是將請求分散到多個快取伺服器上,減輕快取熱點導致的單台快取伺服器壓力。在設計快取副本的時候,有一個細節需要注意:不同的快取副本不要設置統一的過期時間,否則就會出現所有快取副本同時生成同時失效的情況,從而引發快取的雪崩效應。

把熱點數據快取在客戶端的本地記憶體中,並且設置一個失效時間。對於每次讀請求,將首先檢查該數據是否存在於本地快取中,如果存在則直接返回,如果不存在再去訪問分散式快取的伺服器。
阿珍用崇拜的眼神看著老徐,說:「老徐,你太牛了,什麼都懂!」
老徐不好意思地撓了撓頭,說:「也沒有了。」

最後,謝謝你這麼帥,還給我點贊和關注。