來說說快取穿透、快取擊穿、快取雪崩都是什麼?怎麼解決?
前言
看到題目就知道了,這又是我在面試中遇到的,最近面試,把我的博文品質感覺都提上來了。面一次試感覺夠我總結一周的,但還是每次都能遇到知識盲點,那以後就當面試總結是個掃盲的過程吧。
快取穿透
面試的時候就被問到了這個問題,具體描述就是,正常的請求都是先請求到快取(就當我們的快取是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在高可用的情況下,也就是集群中的數據同步時,而數據不會丟失等情況。
這個我準備下一篇來繼續啃。