緩存穿透、雪崩、熱點與Redis

向你們推薦這篇文章——Redis架構之防雪崩設計:網站不宕機背後的兵法git

(另外推薦我去年的短文做爲餐前點心——略談服務端緩存設計github

《Redis架構之防雪崩設計》這篇文章(下文稱之爲「原文」)寫得很是好,全面歸納了大規模系統可能面對的緩存穿透和緩存雪崩等問題,能夠看出是一線實戰經驗的精華總結,很是適合你們學習。redis

而我想再補充一些信息,使「原文」的版圖更加完整。算法

關於「緩存穿透」

「原文」給出了空對象和布隆過濾器兩種解決方案。segmentfault

空對象是首選方案,簡單直接,碰到查詢結果爲空的鍵,放一個空值在緩存中,下次再訪問就馬上知道這個鍵無效,不用發出SQL了。但「原文」也說了,存在以下問題:後端

第一,空值作了緩存,意味着緩存層中存了更多的鍵,須要更多的內存空間 ( 若是是攻擊,問題更嚴重 ),比較有效的方法是針對這類數據設置一個較短的過時時間,讓其自動剔除。

第二,緩存層和存儲層的數據會有一段時間窗口的不一致,可能會對業務有必定影響。例如過時時間設置爲 5 分鐘,若是此時存儲層添加了這個數據,那此段時間就會出現緩存層和存儲層數據的不一致,此時能夠利用消息系統或者其餘方式清除掉緩存層中的空對象。緩存

對於第一點,我還建議空值放在另外的緩存空間中,不宜與正常值共用空間,不然當空間不足時,緩存系統的LRU算法可能會先剔除正常值,再剔除空值——這個漏洞可能會受到攻擊。架構

對於第二點,若是是Redis緩存,更新數據後直接在Redis中清除便可;若是是本地緩存,就須要用消息來通知其餘機器清除各自的本地緩存了。(業界終於接受了用消息來同步緩存的設計思想,cheers! )我有一個小項目joint-cache-redis來簡單地演示「用消息來同步多個機器的緩存」,並且在實踐中發現Kafka可能比Redis MQ更適合於這個場景。運維

關於「緩存雪崩」

這句歸納很傳神!緩存層宕掉後,流量會像奔逃的野牛同樣,打向後端存儲分佈式

沒什麼要補充的,就感謝一下Netflix開源的Hystrix吧!雖然只是一個庫,可是要實現可靠的限流算法仍是很有門道的。

關於「緩存熱點 key 重建」

「原文」說到在緩存失效的瞬間,有大量線程來重建緩存,形成後端負載加大,甚至可能會讓應用崩潰,並給出「互斥鎖」和「永遠不過時」兩種候選方案。

互斥鎖(Mutex):

「分佈式緩存加鎖」一般是一個反模式(見我去年的文章大型服務端開發的反模式第7條),若是持有鎖的實例不穩定致使沒及時釋放,就會浪費這個鎖,直到鎖過時。「原文」的做者還指出有死鎖的風險。

實際上是能夠優化的:等待一兩次後,重試時可繞過互斥鎖。即便繞過互斥鎖,也不會產生什麼很差的後果,由於更新緩存是一個冪等操做。

也能夠把鎖的過時時間設得更短。

從這個例子咱們能感受到,冪等操做比非冪等操做更容易優化。

永遠不過時:

"原文"很好地介紹了在Redis中的作法。對於Guava本地緩存就簡單多了,使用refreshAfterWrite便可。

「原文」讀到最後,才知道這是《Redis開發與運維》一書的節選,相信這本書會是國產技術書籍的精品!

相關文章
相關標籤/搜索