Redis做爲緩存可能會出現的問題及解決方案
Redis是個大話題,只要是去面試Java開發,幾乎必問。基礎一點的問Redis是什麼東西?用來作什麼?Redis支持哪些數據類型?Redis的性能爲何那麼好?複雜一點的就會問到緩存穿透、緩存擊穿、緩存雪崩等問題。而我在面試的時候也被問到了Redis爲何用來作緩存的問題。面試
因此我以爲頗有必要總結一下Redis做爲緩存使用,可能會引起的問題。以達到溫故而知新的效果數據庫
ps:在本文章中,就不討論Redis能用來幹啥?這種基礎問題了緩存
1、Redis簡介:
在討論Redis做爲緩存使用,可能會引起的問題以前,咱們得了解官方是怎麼定義Redis服務器
Redis是一個開源的內存中的數據結構存儲系統,它能夠用做:數據庫、緩存和消息中間件。網絡
它支持多種類型的數據結構,如字符串(Strings),散列(Hash),列表(List),集合(Set),有序集合(Sorted Set或者是ZSet)。數據結構
Redis 內置了複製(Replication),LUA腳本(Lua scripting), LRU驅動事件(LRU eviction),事務(Transactions) 和不一樣級別的磁盤持久化(Persistence),並經過 Redis哨兵(Sentinel)和自動分區(Cluster)提供高可用性(High Availability)。併發
Redis也提供了兩種持久化策略,這些策略可讓用戶將本身的數據保存到磁盤上面進行存儲。根據實際狀況,能夠每隔必定時間將數據集以快照的形式保存在磁盤(RDB策略),或者將全部操做成功的命令追加到命令日誌中(AOF策略),它會在執行命令時,將被執行的命令複製到硬盤裏面,實現實時持久化數據的效果。固然,根據實際開發的需求,你也能夠關閉持久化功能,單純的將Redis做爲一個高效的網絡的緩存數據功能使用。工具
2、Redis做爲緩存使用,可能會引起的問題(重點)
Redis由C語言開發,而且將數據存儲在內存中,能夠說Redis徹底是基於內存進行操做,對數據讀寫的速度極快、性能極好。官方提供的數據是能夠達到每秒100000+的吞吐量(每秒內查詢次數),如此優秀的機制使Redis極其適合做爲緩存使用。性能
1.緩存穿透
程序在處理緩存時,通常是先從緩存查詢,若是緩存沒有這個key(理解爲數據),則會從數據庫中查詢,並將查詢到的數據保存到緩存中去。spa
好,問題來了,若是有個壞心眼的人向服務器發起請求,去查詢一個必定不存在的數據,因爲緩存中沒有查到對應的數據時須要從數據庫查詢,查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到數據庫去查詢,緩存形同虛設,這就是緩存穿透。
解決方案:
1)最粗暴也是最經常使用的方法就是,若是一個查詢的數據爲空(不論是數據不存在仍是系統故障),咱們就把這個空結果進行緩存,但要把它的過時時間設置得很短,最長不超過5分鐘,這樣能有效的解決緩存穿透問題。
2)其次,能夠採用布隆過濾器,也能解決緩存穿透問題
2.緩存擊穿
緩存擊穿和緩存穿透在本質上很類似,都是查詢數據時緩存失去了做用,致使請求直接去數據庫查詢數據,可是形成緩存失效的緣由倒是天差地別。
大量用戶在同一時間內訪問某熱點數據時,存儲在緩存中的熱點數據卻忽然失效(過時時間),結果就是大量的請求直接訪問數據庫,使數據庫的壓力變大,甚至致使數據庫宕機,這就是緩存擊穿。
解決方案:比較經常使用的方法是加互斥鎖(mutex)保證數據的一致性。簡單地來講,就是在緩存失效的時候(判斷拿出來的值爲空),不是當即去訪問數據庫,而是先使用緩存工具的某些帶成功操做返回值的操做(好比Redis的SETNX或者Memcache的ADD)去set另外一個請求所須要的數據,當操做返回成功時,再進行訪問數據庫的操做並回設緩存;不然,就重試整個get緩存的方法。
3.緩存雪崩
若是緩存的數據集中在一段時間內大批失效,而不巧的是在這段時間內又有大量用戶發起請求訪問數據,這樣就會形成大量的緩存擊穿,全部的請求都會直接去訪問數據庫,致使數據庫在短期內宕機,這就是緩存雪崩。
ps:這裏我使用了誇張的修辭手法。緩存雪崩不必定會形成數據庫宕機,但緩存若是發生雪崩現象,那確定是很嚴重的
解決方案:
1)加鎖排隊。加互斥鎖,添加信息隊列
2)數據預熱。能夠經過緩存Reload機制,預先去更新緩存,再即將發生大併發訪問前手動觸發加載緩存不一樣的key,設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻
3)設置熱點緩存永不過期
筆者: 以上問題及解決方案純粹我的看法,若是有錯誤的地方,還請指正