天天看點

【高并發】面試官:講講什麼是緩存穿透?擊穿?雪崩?如何解決?

緩存穿透

首先,我們來說說緩存穿透。什麼是緩存穿透呢?緩存穿透問題在一定程度上與緩存命中率有關。如果我們的緩存設計的不合理,緩存的命中率非常低,那麼,資料通路的絕大部分壓力都會集中在後端資料庫層面。

什麼是緩存穿透?

如果在請求資料時,在緩存層和資料庫層都沒有找到符合條件的資料,也就是說,在緩存層和資料庫層都沒有命中資料,那麼,這種情況就叫作緩存穿透。

我們可以使用下圖來表示緩存穿透的現象。

【高并發】面試官:講講什麼是緩存穿透?擊穿?雪崩?如何解決?

造成緩存穿透的主要原因就是:查詢某個Key對應的資料,Redis緩存中沒有相應的資料,則直接到資料庫中查詢。資料庫中也不存在要查詢的資料,則資料庫會傳回空,而Redis也不會緩存這個空結果。這就造成每次通過這樣的Key去查詢資料都會直接到資料庫中查詢,Redis不會緩存空結果。這就造成了緩存穿透的問題。

如何解決緩存穿透問題?

既然我們知道了造成緩存穿透的主要原因就是緩存中不存在相應的資料,直接到資料庫查詢,資料庫傳回空結果,緩存中不存儲空結果。

那我們就自然而然的想到了第一種解決方案:就是把空對象緩存起來。當第一次從資料庫中查詢出來的結果為空時,我們就将這個空對象加載到緩存,并設定合理的過期時間,這樣,就能夠在一定程度上保障後端資料庫的安全。

第二種解決緩存穿透問題的解決方案:就是使用布隆過濾器,布隆過濾器可以針對大資料量的、有規律的鍵值進行處理。一條記錄是不是存在,本質上是一個Bool值,隻需要使用 1bit 就可以存儲。我們可以使用布隆過濾器将這種表示是、否等操作,壓縮到一個資料結構中。比如,我們最熟悉的使用者性别這種資料,就非常适合使用布隆過濾器來處理。

緩存擊穿

如果我們為緩存中的大部分資料設定了相同的過期時間,則到了某一時刻,緩存中的資料就會批量過期。

什麼是緩存擊穿?

如果緩存中的資料在某個時刻批量過期,導緻大部分使用者的請求都會直接落在資料庫上,這種現象就叫作緩存擊穿。

我們可以使用下圖來表示緩

【高并發】面試官:講講什麼是緩存穿透?擊穿?雪崩?如何解決?

造成緩存擊穿的主要原因就是:我們為緩存中的資料設定了過期時間。如果在某個時刻從資料庫擷取了大量的資料,并設定了相同的過期時間,這些緩存的資料就會在同一時刻失效,造成緩存擊穿問題。

如何解決緩存擊穿問題?

對于比較熱點的資料,我們可以在緩存中設定這些資料永不過期;也可以在通路資料的時候,在緩存中更新這些資料的過期時間;如果是批量入庫的緩存項,我們可以為這些緩存項配置設定比較合理的過期時間,避免同一時刻失效。

還有一種解決方案就是:使用分布式鎖,保證對于每個Key同時隻有一個線程去查詢後端的服務,某個線程在查詢後端服務的同時,其他線程沒有獲得分布式鎖的權限,需要進行等待。不過在高并發場景下,這種解決方案對于分布式鎖的通路壓力比較大。

【高并發】面試官:講講什麼是緩存穿透?擊穿?雪崩?如何解決?

如果緩存系統出現故障,所有的并發流量就會直接到達資料庫。

什麼是緩存雪崩?

如果在某一時刻緩存集中失效,或者緩存系統出現故障,所有的并發流量就會直接到達資料庫。資料存儲層的調用量就會暴增,用不了多長時間,資料庫就會被大流量壓垮,這種級聯式的服務故障,就叫作緩存雪崩。

我們可以用下圖來表示緩存雪崩的現象。

造成緩存雪崩的主要原因就是緩存集中失效,或者緩存服務發生故障,瞬間的大并發流量壓垮了資料庫。

如何解決緩存雪崩問題?

解決緩存雪崩問題最常用的一種方案就是保證Redis的高可用,将Redis緩存部署成高可用叢集(必要時候做成異地多活),可以有效的防止緩存雪崩問題的發生。

為了緩解大并發流量,我們也可以使用限流降級的方式防止緩存雪崩。例如,在緩存失效後,通過加鎖或者使用隊列來控制讀資料庫寫緩存的線程數量。具體點就是設定某些Key隻允許一個線程查詢資料和寫緩存,其他線程等待。則能夠有效的緩解大并發流量對資料庫帶來的巨大沖擊。

另外,我們也可以通過資料預熱的方式将可能大量通路的資料加載到緩存,在即将發生大并發通路的時候,提前手動觸發加載不同的資料到緩存中,并為資料設定不同的過期時間,讓緩存失效的時間點盡量均勻,不至于在同一時刻全部失效。