Redis緩存的三大問題與解決方案
Redis的三大緩存問題也就是緩存擊穿、緩存雪崩和緩存穿透,在生產環(huán)境中會因為這些原因造成請求繞過了Redis直接訪問數(shù)據(jù)庫,使得數(shù)據(jù)庫的負載增大,這樣不僅導致緩存的作用降低,甚至引發(fā)數(shù)據(jù)庫壓力過大而崩潰進而蔓延到整個系統(tǒng)無法使用。下面我們來聊聊Redis緩存的三大問題與解決方案。
1、緩存雪崩
緩存雪崩指的是由于Redis里面同一時間出現(xiàn)了多個key同時失效,導致大量請求直接訪問數(shù)據(jù)庫,瞬間引發(fā)數(shù)據(jù)庫壓力激增,甚至導致數(shù)據(jù)庫崩潰,如下圖所示:
圖片
解決方案:
(1)將Redis進行高可用的架構部署(主從+哨兵、集群),避免Redis出現(xiàn)全盤崩潰宕機的情況。
(2)使用本地緩存、Histrix限流降級、Nginx IP限流等等方法,避免Mysql被大流量沖垮,同時在緩存不可用時可以返回一些默認值或者降級的數(shù)據(jù)。
(3)針對于Redis里面的key設置一個合理的過期時間(如緩存的過期時間為隨機值),避免大量的key同時失效。
2、緩存擊穿
緩存擊穿是指某個熱點數(shù)據(jù)A在緩存中失效的瞬間,此時又有大量的并發(fā)請求同時訪問該數(shù)據(jù)A,由于數(shù)據(jù)A在緩存中失效,大量請求同時訪問數(shù)據(jù)庫,造成數(shù)據(jù)庫壓力驟增。這種情況通常發(fā)生在熱點數(shù)據(jù)或訪問頻繁的數(shù)據(jù)上,如下如圖所示的:
圖片
通常Mysql只能支持2000個請求的并發(fā)量,Redis中的key_1正在承擔4000個請求的并發(fā)量,由于key_1瞬間失效導致4000個并發(fā)請求直接請求數(shù)據(jù)庫,可能就會導致Mysql瞬間宕機,進而蔓延整個系統(tǒng)都無法使用。
解決方案:
(1)給key設置一個合理的過期時間,可以將這個熱點數(shù)據(jù)設置為永不過期,或者及時的給熱點key進行續(xù)期。
(2)使用互斥鎖,我們可以基于Redis或Zookeeper實現(xiàn)一個互斥鎖,等待第一個請求構建緩存之后,再來釋放鎖。如下圖所示:
圖片
這樣后續(xù)的其他的請求就會通過Redis來查詢數(shù)據(jù),那么大量的請求就不會到達Mysql上而導致其的性能下降甚至出現(xiàn)宕機的問題。
(3)對一些熱點數(shù)據(jù)提前加載并定期刷新緩存,防止緩存失效。
3、緩存穿透
緩存穿透是指客戶端頻繁訪問一些根本不存在的緩存數(shù)據(jù),由于緩存中沒有這些數(shù)據(jù)的記錄,每次請求都直接訪問數(shù)據(jù)庫導致數(shù)據(jù)庫壓力增大,但是數(shù)據(jù)庫中也不存在這個數(shù)據(jù)。
圖片
通常是由于攻擊者輸入非法或惡意構造的請求訪問服務,由于Redis緩存的不存在,此時大量請求都是直接到達Mysql上。
解決方案:
(1)緩存空對象,針對這些惡意構建的key在Redis中緩存一個空值并設置一個過期時間,那么后續(xù)請求是不會到達Mysql上,而是直接通過Redis返回的一個空值給到用戶。設置過期時間是因為隨著系統(tǒng)的運行這部分數(shù)據(jù)可能后面會產生,那么key的過期時間到了之后,key會被Redis刪除,后面有用戶正常來訪問的時候,這個key它會被重新緩存到Redis上。
(2)參數(shù)校驗,在系統(tǒng)前端或者應用層對請求的參數(shù)進行有效性驗證,過濾掉明顯無效或惡意的請求,如請求參數(shù)為主鍵id是大于0的,那么對于請求小于0的id參數(shù)是明顯不符合要求的,可以直接返回錯誤請求。
(3)布隆過濾器,判斷這些請求參數(shù)是否存在Redis和Mysql中,如果布隆過濾器判斷這些請求參數(shù)不存在Redis和Mysql中就直接返回,這樣惡意構建的這些請求就被攔截了,當然布隆過濾器存在一定的誤判率。