緩存雪崩
緩存雪崩指的是緩存同一時間大面積的失效,所以,后面的請求都會落到數據庫上,造成數據庫短時間 內承受大量請求而崩掉。
解決辦法
事前:盡量保證整個 Redis 集群的高可用性,發現機器宕機盡快補上,選擇合適的內存淘汰策略。
事中:本地ehcache緩存 + hystrix限流&降級,避免MySQL崩掉, 通過加鎖或者隊列來控制讀數據庫 寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。
事后:利用 Redis 持久化機制保存的數據盡快恢復緩存
緩存穿透
一般是黑客故意去請求緩存中不存在的數據,導致所有的請求都落到數據庫上,造成數據庫短時間內承 受大量 請求而崩掉。
解決辦法
1、布隆過濾器
這是最常見的一種解決方法了,它是將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不 存在的數據會被 這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓 力。
對所有可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則丟棄,從而避免了對底層存儲 系統的查詢壓力;
這里稍微科普一下布隆過濾器。
布隆過濾器是引入了k(k>1)k(k>1)個相互獨立的哈希函數,保證在給定的空間、誤判率下,完成元 素判重的過程。 它的優點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困難。
該算法的核心思想就是利用多個不同的Hash函數來解決“沖突”。Hash存在一個沖突(碰撞)的問 題,用同一個Hash得到的兩個URL的值有可能相同。為了減少沖突,我們可以多引入幾個Hash,如 果通過其中的一個Hash值我們得出某元素不在集合中,那么該元素肯定不在集合中。只有在所有的 Hash函數告訴我們該元素在集合中時,才能確定該元素存在于集合中。這便是布隆過濾器的基本思 想,一般用于在大數據量的集合中判定某元素是否存在。
2、緩存空對象
當存儲層不命中后,即使返回的空對象也將其緩存起來,同時會設置一個過期時間,之后再訪問這個數 據將會從緩存中獲取,保護了后端數據源;如果一個查詢返回的數據為空(不管是數據不存 在,還是系 統故障),我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過五分鐘。
但是這種方法會存在兩個問題:
1、如果空值能夠被緩存起來,這就意味著緩存需要更多的空間存儲更多的鍵,因為這當中可能會有很 多的空值的鍵;
2、即使對空值設置了過期時間,還是會存在緩存層和存儲層的數據會有一段時間窗口的不一致,這對 于需要保持一致性的業務會有影響。
我們可以從適用場景和維護成本兩方面對這兩匯總方法進行一個簡單比較:
適用場景:緩存空對象適用于1、數據命中不高 2、數據頻繁變化且實時性較高 ;而布隆過濾器適用1、 數據命中不高 2、數據相對固定即實時性較低
維護成本:緩存空對象的方法適合1、代碼維護簡單 2、需要較多的緩存空間 3、數據會出現不一致的現 象;布隆過濾器適合 1、代碼維護較復雜 2、緩存空間要少一些
緩存預熱
緩存預熱是指系統上線后,將相關的緩存數據直接加載到緩存系統。這樣就可以避免在用戶請求的時 候,先查詢數據庫,然后再將數據緩存的問題。用戶會直接查詢事先被預熱的緩存數據!
解決思路
1、直接寫個緩存刷新頁面,上線時手工操作下;
2、數據量不大,可以在項目啟動的時候自動進行加載;
3、定時刷新緩存;
緩存更新
除了緩存服務器自帶的緩存失效策略之外(Redis默認的有6中策略可供選擇),我們還可以根據具體的 業務需求進行自定義的緩存淘汰,常見的策略有兩種:
(1)定時去清理過期的緩存;定時刪除和惰性刪除
(2)當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統得到新數 據并更新緩存。
兩者各有優劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過 來都要判斷緩存失效,邏輯相對比較復雜!具體用哪種方案,大家可以根據自己的應用場景來權衡。
緩存擊穿
緩存擊穿,是指一個key非常熱點,在不停的扛著大并發,大并發集中對這一個點進行訪問,當這個key 在失效的瞬間,持續的大并發就穿破緩存,直接請求數據庫,就像在一個屏障上鑿開了一個洞。 比如常見的電商項目中,某些貨物成為“爆款”了,可以對一些主打商品的緩存直接設置為永不過期。即 便某些商品自己發酵成了爆款,也是直接設為永不過期就好了。mutex key互斥鎖基本上是用不上的,有 個詞叫做大道至簡。
緩存降級
當訪問量劇增、服務出現問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然 需要保證服務還是可用的,即使是有損服務。系統可以根據一些關鍵數據進行自動降級,也可以配置開 關實現人工降級。
降級的最終目的是保證核心服務可用,即使是有損的。而且有些服務是無法降級的(如加入購物車、結 算)。
以參考日志級別設置預案:
(1)一般:比如有些服務偶爾因為網絡抖動或者服務正在上線而超時,可以自動降級;
(2)警告:有些服務在一段時間內成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發送告警;
(3)錯誤:比如可用率低于90%,或者數據庫連接池被打爆了,或者訪問量突然猛增到系統能承受的 最大閥值,此時可以根據情況自動降級或者人工降級;
(4)嚴重錯誤:比如因為特殊原因數據錯誤了,此時需要緊急人工降級。
服務降級的目的,是為了防止Redis服務故障,導致數據庫跟著一起發生雪崩問題。因此,對于不重要的 緩存數據,可以采取服務降級策略,例如一個比較常見的做法就是,Redis出現問題,不去數據庫查詢, 而是直接返回默認值給用戶。
浙公網安備 33010602011771號