由於緩存失效,致使請求直接命中數據庫。致使 DB 負荷大增,最終宕機。redis
1)緩存高可用數據庫
經過搭建緩存的高可用,避免緩存掛掉致使沒法提供服務的狀況,從而下降出現緩存雪崩的狀況。緩存
假設咱們使用 Redis 做爲緩存,則可使用 Redis Sentinel 或 Redis Cluster 實現高可用。服務器
2)本地緩存網絡
若是使用本地緩存(Ehcache、Guava Cache )時,即便分佈式緩存掛了,也能夠將 DB 查詢到的結果緩存到本地,避免後續請求所有到達 DB 中。數據結構
3)請求 DB 限流(Guava RateLimiter、Sentinel)分佈式
經過限制 DB 的每秒請求數,避免 DB 宕機。這樣至少能有兩個好處:線程
可能有一部分用戶,還可使用,系統還沒死透。
將來緩存服務恢復後,系統當即就已經恢復,無需在處理 DB 也掛掉的狀況。對象
4)服務降級(Hystrix、Sentinel)blog
若是請求被限流,或者請求 DB 超時,咱們能夠服務降級,提供一些默認的值,或者友情提示。
緩存穿透,是指查詢一個不存在的數據,當緩存不命中時,會從 DB 查詢到數據,再更新到緩存中,而且處於容錯考慮,若是從 DB 查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到 DB 去查詢。
在流量大時,可能 DB 就掛掉了,要是有人利用不存在的 key 頻繁攻擊咱們的應用,這就是漏洞。好比使用程序瞬間產生大量的請求,攻擊服務器。
方案一,緩存空對象:當從 DB 查詢數據爲空,咱們仍然將這個空結果進行緩存,具體的值須要使用特殊的標識,能和真正緩存的數據區分開。另外,須要設置較短的過時時間,通常建議不要超過 5 分鐘。可是當客戶端同一時刻發起大量請求時,會致使redis垃圾緩存過多,可能致使redis宕機。我的認爲客戶端同一時刻發起大量請求時,應該使用限流機制,避免大量垃圾請求進入後臺。若是不少客戶端發起DDOS攻擊,就不太好防了。
方案二,使用互斥鎖排隊(或者分段鎖),即根據key獲取value值爲空時,鎖上,從數據庫中load數據後再釋放鎖。若其它線程獲取鎖失敗,則等待一段時間後重試。這裏要注意,分佈式環境中要使用分佈式鎖,單機的話用普通的鎖(synchronized、Lock)就夠了。
方案三,此方案摘自網絡,BloomFilter 布隆過濾器:在緩存服務的基礎上,構建 BloomFilter 數據結構,在 BloomFilter 中存儲對應的 KEY 是否存在,若是存在,說明該 KEY 對應的值爲空。那麼整個邏輯的以下:
一、根據 KEY 查詢緩存。若是存在對應的值,直接返回;若是不存在,繼續向下執行。
二、根據 KEY 查詢在緩存 BloomFilter 的值。若是存在值,說明該 KEY 不存在對應的值,直接返回空;若是不存在值,繼續向下執行。
三、查詢 DB 對應的值,若是存在,則更新到緩存,並返回該值。若是不存在值,更新到緩存 BloomFilter 中,並返回空。
在實際請求中,可能存在熱點key的狀況,致使緩存宕機。好比某個流量明星微博發了某條信息,幾千萬人都在看,這條微博就會成爲熱點key。
識別熱點key,如發現是熱點key,緩存到本地。同時作好熔斷、降級處理。盜用網絡的一張圖片(不記得出處了),以下: