來說說快取穿透、快取擊穿、快取雪崩都是什麼?怎麼解決?

紀莫 發表於 2020-09-16

前言

看到題目就知道了,這又是我在面試中遇到的,最近面試,把我的博文質量感覺都提上來了。面一次試感覺夠我總結一週的,但還是每次都能遇到知識盲點,那以後就當面試總結是個掃盲的過程吧。

快取穿透

面試的時候就被問到了這個問題,具體描述就是,正常的請求都是先請求到快取(就當我們的快取是Redis吧),如果快取中存在資料,就直接返回,如果快取中不存在請求的資料,就查詢資料庫,然後將查詢到的資料再放到快取中。

那麼如果現在有一堆的請求,在快取中沒有,資料庫中也沒有,怎麼辦?這種垃圾請求還特別多,而且因為是在資料庫沒有查詢到,所以也不會被放到快取中,這就是快取穿透的場景。

大量的這種請求,最終會導致資料庫壓力劇增,最終就會將資料打垮,若是這個資料庫是核心資料庫,那麼其他所有依賴這個庫的介面都會報錯。

在這裡插入圖片描述
例如,每次請求的引數都是id,而id是我們資料庫裡的自增主鍵,但是請求過來的引數要麼是-1這種,要麼就是特別大的一個數,反正就是不存在的資料。

解決快取穿透

那麼如何解決快取穿透呢?

  • 首先最基本的就是要做引數校驗,非法的引數就直接return,連快取層都到不了。
  • 當請求的資料在穿過Redis後,資料庫也返回空,這樣的資料也可以存入到快取中,然後過期時間可以設定一個比較短的時間,這樣能夠在一定程度上保障後端資料庫的安全。
  • 可以使用Redis的布隆過濾器,這個工具可以有效的防止快取穿透的發生,我們可以將一個引數是否存在儲存為一個boolean值,然後需要一個bit就可以儲存,這樣的資料壓縮到一個資料結構中,就是布隆過濾器的原理。即節省儲存空間,又能達到效果。

快取擊穿

我們在Redis儲存的資料,主要是快取的效果,目的是為了解決DB的壓力,所以一些熱點資料,都是先從快取中獲取的,當快取中不存在的時候再從DB中獲取然後再存入快取。

但是如果一個高頻的熱點資料,在失效的一瞬間,它的大量請求就會直接打到DB上,這樣在DB還沒有返回資料給Redis的時候,DB承受了熱點請求的壓力,就好像快取是一個水桶,然後突然水桶破了一個洞,直接沖垮了後面的堤壩(DB)。

在這裡插入圖片描述

解決快取擊穿

造成快取擊穿的原因是,在同一時刻從資料庫中獲取了大量資料,並且設定了相同的過期時間,這些快取就會在同一時刻失效,這樣就造成了快取擊穿的問題。
解決方案

  • 一些熱點的資料,我們可以設定永不過期;或者是在訪問資料的時候延長過期時間
  • 也可以用分散式鎖,來鎖住資料,保證同一時間只有一個執行緒能夠獲取資料,其他請求獲取不到資料,只能等待,但是在高併發的場景下,這種方案,體驗不太好,並且分散式鎖的壓力也會特別大

快取雪崩

Redis中儲存了很多的資料,但是有時候這些資料會出現,在同一個時刻批量過期的情況,因為有可能這些資料是批量插入的,所以他們的過期時間就會都在同一個時間。

正好在這個批量資料過期的時間點,大量的請求過來了,因為快取資料過期了,所以沒有命中快取,直接請求到了資料庫中。資料庫的壓力突然劇增,甚至有可能直接撐不住掛掉。然後有可能DBA會緊急重啟DB,但是剛一恢復,新的請求立馬又把DB打垮了。

也有可能就是Redis掛了,快取都不能用了,請求也是直接打到了DB上,然後DB也是扛不住壓力,直接掛掉。再恢復,再掛掉。
在這裡插入圖片描述
Redis中同一時刻大量的Key過期,那一瞬間和Redis不存在一樣,還有Redis真的掛了的情況,這對服務和DB來說是災難性的問題。

解決快取雪崩

解決方案

  • 批量存入快取的資料,我們可以為這些資料分別配置比較合理的過期時間,即使是隨機分配過期時間也可以,避免同一時間失效。
  • 熱點資料永不過期,更新操作時直接更新快取,但是並不設定過期時間。
  • 當資料庫快取出問題時,可以採用降級措施,雖然是用DB頂上了請求,但是可以通過降級方案,保證某些資料在同一時刻只能有一個執行緒在查詢資料庫和寫快取,這樣不至於把資料庫給搞崩了。
  • 還有就是為了防止Redis掛了,導致的快取雪崩,可以保證Redis的高可用,就是將Redis叢集部署,然後將熱點資料都分配到不同的節點上,這樣就可以有效的防止雪崩的出現。

當說到Redis高可用的時候,面試有可能會繼續問,怎麼保證Redis在高可用的情況下,也就是叢集中的資料同步時,而資料不會丟失等情況。
這個我準備下一篇來繼續啃。

最新文章