天天看點

老徐和阿珍的故事:緩存穿透、緩存擊穿、緩存雪崩、緩存熱點,傻傻分不清楚

人物背景:

老徐,男,本名徐福貴,從事Java相關研發工作多年,職場老油條,摸魚小能手,雖然歲數不大但長的比較着急,人稱老徐。據說之前炒某币敗光了所有家産,甚至現在還有欠債。

阿珍,女,本名陳家珍,剛剛入職不久的實習生,雖然是職場菜鳥但聰明好學。據說是學校的四大校花之一,追求她的人從旺角排到了銅鑼灣,不過至今還單身。

阿珍:“在高并發下遇到瓶頸的時候,經常會用到緩存來提高整個系統的性能。”

老徐:“嗯,不過緩存能夠大大提升整個系統的性能,但同時也引入了更多複雜性。”

阿珍點了點頭,說:“是啊,緩存穿透、緩存擊穿、緩存雪崩、緩存熱點這些東西,這些東西我一直分不清楚,經常混淆。”

老徐立刻自信滿滿地說:“這個我懂啊,你聽我給你娓娓道來。”

緩存穿透

緩存穿透是指在查詢緩存資料時,緩存和資料庫中都沒有對應資料,在緩存中找不到對應的資料,每次都要去資料庫中再查詢一遍,然後傳回資料不存在。

在這個場景中,緩存并沒有起到分擔資料庫通路壓力的作用。讀取不存在的資料的請求量一般不會太大,但如果出現一些惡意攻擊,故意大量通路某些不存在的資料,就會對資料庫造成很多壓力。

阿珍:“太可怕了,萬一遇到了這樣攻擊,該怎麼辦呀?”

老徐:“這個很好應對的,一般有兩種辦法。”

第一個是:如果查詢資料庫中的資料沒有找到,則直接設定一個特定值存到緩存中。之後讀取緩存時就會擷取到這個特定值,直接傳回空值,就不會繼續通路資料庫了。

第二個是:把已存在資料的key存放在布隆過濾器中。當有新的請求時,先到布隆過濾器中查詢是否存在,如果不存在該條資料直接傳回;如果存在該條資料再查詢緩存查詢資料庫。

緩存擊穿

緩存擊穿是指在查詢緩存資料時,資料庫原本有的資料,但是緩存中沒有,生成緩存資料需要耗費較長時間或者大量資源,這時候如果有大量請求該資料,會對資料庫甚至系統造成較大壓力。

阿珍:“哦?該怎麼解決呀?”

老徐:“這個很好解決,一般有兩個做法。”

第一個是:對緩存更新操作加入鎖的保護,保證隻有一個線程能夠進行緩存更新的操作,沒有擷取更新鎖的線程要麼等待鎖釋放後重新讀取緩存,要麼直接傳回空值或者預設值。

第二個是:背景作業定時更新緩存,而不是在通路頁面時生成緩存資料。這樣可以按照一定政策定時更新緩存,不會對存儲系統較大的瞬時壓力。

緩存雪崩

緩存雪崩是指當大量緩存同時失效或過期後,大量請求直接通路對資料庫,甚至耗費較長時間或者大量資源計算緩存結果,引起系統性能的急劇下降。

阿珍搶先說道:“這個我知道怎麼解決!”老徐反問:“怎麼解決?”

阿珍回答:“同一類型的緩存的過期時間可以設定一個随機值,比如:原來的過期時間是5分鐘,在此基礎上加0~60秒,那麼過期時間就變為在5~6分鐘内波動,有效防止都在同一個時間點上大量緩存過期。”

緩存熱點

緩存熱點是指大部分甚至所有的業務請求都命中同一份緩存資料。

雖然緩存本身的性能比較高,但對于一些特别熱點的資料,如果大部分甚至所有的請求都命中同一份緩存資料,則這份資料所在的緩存伺服器的壓力也會很大。比如,電商的爆品秒殺活動,短時間内被上千萬的使用者通路。

阿珍:“遇到了這種情況,該怎麼辦呀?”

老徐:“這個很好解決的,一般有兩種辦法:複制多份緩存副本和本地記憶體緩存。”

複制多份緩存副本,就是将請求分散到多個緩存伺服器上,減輕緩存熱點導緻的單台緩存伺服器壓力。在設計緩存副本的時候,有一個細節需要注意:不同的緩存副本不要設定統一的過期時間,否則就會出現所有緩存副本同時生成同時失效的情況,進而引發緩存的雪崩效應。

把熱點資料緩存在用戶端的本地記憶體中,并且設定一個失效時間。對于每次讀請求,将首先檢查該資料是否存在于本地緩存中,如果存在則直接傳回,如果不存在再去通路分布式緩存的伺服器。

阿珍用崇拜的眼神看着老徐,說:“老徐,你太牛了,什麼都懂!”

老徐不好意思地撓了撓頭,說:“也沒有了。”