緩存預熱
緩存預熱這個應該是一個比較常見的概念,相信很多小伙伴都應該可以很容易的理解,緩存預熱就是系統上線后,將相關的緩存數據直接加載到緩存系統。這樣就可以避免在用戶請求的時候,先查詢數據庫,然后再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數據!
現象:
項目剛上線,服務器迅速宕機。
問題排查:
1、請求數量較高
2、主從之間數據吞吐量較大,數據同步操作頻度較高
3、redis中沒有緩存數據,全部請求數據庫。
解決思路:
前置准備工作:
1. 日常例行統計數據訪問記錄,統計訪問頻度較高的熱點數據
2. 利用LRU數據刪除策略,構建數據留存隊列
例如:storm與kafka配合
准備工作:
1. 將統計結果中的數據分類,根據級別,redis優先加載級別較高的熱點數據
2. 利用分布式多服務器同時進行數據讀取,提速數據加載過程
3. 熱點數據主從同時預熱
實施:
1. 使用腳本程序固定觸發數據預熱過程
2. 如果條件允許,使用了CDN(內容分發網絡),效果會更好
總結:
緩存預熱就是系統啟動前,提前將相關的緩存數據直接加載到緩存系統。避免在用戶請求的時候,先查詢數據庫,然后再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數據!
緩存雪崩
緩存雪崩可能是因為數據未加載到緩存中,或者緩存同一時間大面積的失效,從而導致所有請求都去查數據庫,導致數據庫CPU和內存負載過高,甚至宕機。
現象:
1. 系統平穩運行過程中,忽然數據庫連接量激增
2. 應用服務器無法及時處理請求
3. 大量408,500錯誤頁面出現
4. 客戶反復刷新頁面獲取數據
5. 數據庫崩潰
6. 應用服務器崩潰
7. 重啟應用服務器無效
8. Redis服務器崩潰
9. Redis集群崩潰
10. 重啟數據庫后再次被瞬間流量放倒
問題排查:
1. 在一個較短的時間內,緩存中較多的key集中過期
2. 此周期內請求訪問過期的數據,redis未命中,redis向數據庫獲取數據
3. 數據庫同時接收到大量的請求無法及時處理
4. Redis大量請求被積壓,開始出現超時現象
5. 數據庫流量激增,數據庫崩潰
6. 重啟后仍然面對緩存中無數據可用
7. Redis服務器資源被嚴重占用,Redis服務器崩潰
8. Redis集群呈現崩塌,集群瓦解
9. 應用服務器無法及時得到數據響應請求,來自客戶端的請求數量越來越多,應用服務器崩潰
10. 應用服務器,redis,數據庫全部重啟,效果不理想
解決思路:
1. 更多的頁面靜態化處理
2. 構建多級緩存架構
- Nginx緩存+redis緩存+ehcache緩存
3. 檢測Mysql嚴重耗時業務進行優化
- 對數據庫的瓶頸排查:例如超時查詢、耗時較高事務等
4. 災難預警機制
- 監控redis服務器性能指標(Grafana+Prometheus系統監控之Redis)
- CPU占用、CPU使用率
- 內存容量
- 查詢平均響應時間
- 線程數
5. 限流、降級
短時間范圍內犧牲一些客戶體驗,限制一部分請求訪問,降低應用服務器壓力,待業務低速運轉后再逐步放開訪問(比如令牌桶或者sentinel限流)
解決方案:
1. LRU與LFU切換
2. 數據有效期策略調整
- 根據業務數據有效期進行分類錯峰,A類90分鍾,B類80分鍾,C類70分鍾
- 過期時間使用固定時間+隨機值的形式,稀釋集中到期的key的數量
3. 超熱數據使用永久key
4. 定期維護(自動+人工)
對即將過期數據做訪問量分析,確認是否延時,配合訪問量統計,做熱點數據的延時
5. 加鎖,慎用!不推薦在高並發的場景下使用
緩存擊穿
我們在項目中使用緩存通常都是先檢查緩存中是否存在,如果存在直接返回緩存內容,如果不存在就直接查詢數據庫然后再緩存查詢結果返回。這個時候如果我們查詢的某一個數據在緩存中一直不存在,就會造成每一次請求都查詢DB,這樣緩存就失去了意義,在流量大時,可能DB就掛掉了。
現象:
1. 系統平穩運行過程中
2. 數據庫連接量瞬間激增
3. Redis服務器無大量key過期
4. Redis內存平穩,無波動
5. Redis服務器CPU正常
6. 數據庫崩潰
問題排查:
1. Redis中某個key過期,該key訪問量巨大
2. 多個數據請求從服務器直接壓到Redis后,均未命中
3. Redis在短時間內發起了大量對數據庫中同一數據的訪問
問題分析:
- 單個key高熱數據
- key過期
解決方案:
1. 預先設定
- 以電商為例,每個商家根據店鋪等級,指定若干款主打商品,在購物節期間,加大此類信息key的過期時長
注意:購物節不僅僅指當天,以及后續若干天,訪問峰值呈現逐漸降低的趨勢
2. 現場調整
- 監控訪問量,對自然流量激增的數據延長過期時間或設置為永久性key
3. 后台刷新數據
- 啟動定時任務,高峰期來臨之前,刷新數據有效期,確保不丟失
4. 二級緩存
- 設置不同的失效時間,保障不會被同時淘汰就行
5. 加鎖
- 分布式鎖,防止被擊穿,但是要注意也是性能瓶頸,慎重!
總結
緩存擊穿就是單個高熱數據過期的瞬間,數據訪問量較大,未命中redis后,發起了大量對同一數據的數據庫訪問,導致對數據庫服務器造成壓力。應對策略應該在業務數據分析與預防方面進行,配合運行監控測試與即時調整策略,畢竟單個key的過期監控難度較高,配合雪崩處理策略即可。
緩存穿透
現象:
1. 系統平穩運行過程中
2. 應用服務器流量隨時間增量較大
3. Redis服務器命中率隨時間逐步降低
4. Redis內存平穩,內存無壓力
5. Redis服務器CPU占用激增
6. 數據庫服務器壓力激增
7. 數據庫崩潰
問題排查:
1. Redis中大面積出現未命中
2. 出現非正常URL訪問
問題分析
1.獲取的數據在數據庫中也不存在,數據庫查詢未得到對應數據
2.Redis獲取到null數據未進行持久化,直接返回
3. 下次此類數據到達重復上述過程
4. 出現黑客攻擊服務器
解決方案
1. 緩存null
- 對查詢結果為null的數據進行緩存(長期使用,定期清理),設定短時限,例如30-60秒,最高5分鍾
2. 白名單策略
- 提前預熱各種分類數據id對應的bitmaps,id作為bitmaps的offset,相當於設置了數據白名單。當加載正常數據時,放行,加載異常數據時直接攔截(效率偏低)
- 使用布隆過濾器(有關布隆過濾器的命中問題對當前狀況可以忽略)
3. 實施監控
- 實時監控redis命中率(業務正常范圍時,通常會有一個波動值)與null數據的占比
- 非活動時段波動:通常檢測3-5倍,超過5倍納入重點排查對象
- 活動時段波動:通常檢測10-50倍,超過50倍納入重點排查對象
- 根據倍數不同,啟動不同的排查流程。然后使用黑名單進行防控(運營)
4. key加密
- 問題出現后,臨時啟動防災業務key,對key進行業務層傳輸加密服務,設定校驗程序,過來的key校驗
- 例如每天隨機分配60個加密串,挑選2到3個,混淆到頁面數據id中,發現訪問key不滿足規則,駁回數據訪問。
總結
緩存擊穿訪問了不存在的數據,跳過了合法數據的redis數據緩存階段,每次訪問數據庫,導致對數據庫服務器造成壓力。通常此類數據的出現量是一個較低的值,當出現此類情況以毒攻毒,並及時報警。應對策略應該在臨時預案防范方面多做文章。