1. 程式人生 > 程式設計 >redis快取設計

redis快取設計

快取的利於弊及應用場景

這裡我們主要討論以Redis為代表的基於記憶體的快取方案。

快取的優點

  • 提升訪問速度,減少後端如資料庫儲存的時間消耗
  • 減輕後端如資料庫的壓力

快取帶來的問題

任何系統每增加一個元件,在帶來新的特性的同時也必然會帶來額外的複雜度,可以說系統的設計過程就是一個折中的過程。快取的引入也帶來了一些需要考慮的問題:

  • 資料不一致: 快取層和儲存層的資料存在著一定的時間視窗的不一致性,時間視窗跟快取更新策略有關
  • 程式碼維護成本: 需要同時處理快取和儲存層的邏輯
  • 運維成本: 為了保證redis的可用性和併發性,會引入redis sentinelredis cluster等架構,這又增加了系統複雜性和運維難度。

應用場景

  • 開銷大的複雜運算
  • 加速請求響應

快取更新策略

  • LRU/LFU/FIFO演演算法
  • 超時剔除
  • 主動更新

應用

  • 低一致性業務建議:最大記憶體+淘汰策略
  • 高一致性:超時剔除和主動更新

快取穿透

快取穿透: 是指查詢一個根本不存在的資料, 快取層和儲存層都不會命中。這會造成儲存層壓力變大。

快取穿透的發現:

通常可以在程式中分別統計

  • 總呼叫數
  • 快取層命中數
  • 儲存層命中數

如果發現大量儲存層空命中, 可能就是出現了快取穿透問題。

快取穿透的解決方案

  • 快取空物件
    • 佔用記憶體: 原因是為了防止大量空物件(被攻擊) 方案是可以設定比較短的過期時間,讓其自動剔除
    • 資料不一致: 原因是
      儲存層添加了資料,但是快取空物件還沒過期, 方案是可以使用訊息佇列,
  • bloomfilter攔截
    • 這種方法適用於資料命中不高、 資料相對固定、 實時性低(通常是資料集較大) 的應用場景, 程式碼維護較為複雜,但是快取空間佔用少。

無底洞優化

由於快取叢集通常會將key進行hash,然後對映到相應的節點上,造成key的分佈與業務無關,批量操作通常需要從不同節點上獲取,相比於單機批量操作只涉及一次網路操作,分散式批量操作會涉及多次網路時間。

常見的IO優化思路:

  • 命令本身的優化,例如優化SQL語句等
  • 減少網路通訊次數
    • pipeline
    • mget
  • 降低介入成本,例如客戶端使用長連/連線池、NIO等

叢集客戶端優化方案

  • 序列IO,把key的請求按照節點分組,然後依次處理
  • 並行IO,把key的請求按照節點分組,然後並行處理
  • hash_tag實現, 可以將多個key強制分配到一個節點上,它的操作時間=1此網路時間+n次命令時間,效能最高,但是資料維護成本高,資料易傾斜

雪崩優化

雪崩定義:由於快取層承載著大量請求,有效地儲存了儲存層,但是如果快取層由於某些原因不能提供服務,於是所有的請求都會到達儲存層,儲存層的呼叫會暴增。

說到底就是快取扛不住了,把壓力衝擊到了儲存層。

預防和緩解快取雪崩問題的三個方面

  • 保證快取層服務高可用性,redis提供了Redis SentinelRedis Cluster
  • 依賴隔離元件為後端限流並降級,降級機制,如Hystrix
  • 提前演練,專案上線前,演練快取層宕掉後,應用及後端的負載情況以及可能出現的問題。

熱點key重建優化

快取+過期時間的策略既可以加速資料讀寫,又保證資料的定期更新,這種模式基本能夠滿足絕大部分需求。但有兩個問題:

  • 熱點key,併發量非常大
  • 重建快取不能在短時間完成(長時生成快取)

熱點key重建

  • 互斥鎖
  • 永遠不過期,但是重建期間會有不一致問題