閱讀592 返回首頁    go 人物


緩存設計學習筆記

背景

最近在《 redis 開發與運維》這是在看11章時候記得筆記

存在和合理性

緩存到處都是啊

先放個最簡單的圖, 這裏麵每一層都可以有緩存
_http_

client 緩存

  • 最常見的瀏覽器的http緩存。
  • 還有app一般也加緩存,比如陌陌,這麼大活躍的情況下,不緩存服務端鴨梨太大,“更多幀”的菜單就是客戶端緩存了的,每15分鍾才會去刷新一次

web server

  • 最常見的nginx 對不常更新的靜態資源可以在location 段裏配expire來設置緩存時間; 還有nginx作為反向代理使用,可以做proxy cache
  • CDN 主要作用也是緩存,將資源緩存到裏用戶最近的物理機上,可以設置更新頻率

業務層和DB

  • 業務邏輯處理進程內的緩存 php-fpm 有yac,java也有很多進程內緩存的庫
  • Redis memcache

總之,請求的任何一個環節都可以根據需要做緩存

緩存收益

  • 加快讀寫速度 基於內存(redis,memcache,yac),減少數據庫(磁盤)io, 內存跟磁盤的讀寫速度不是一個等級的哈
  • 降低後端負載 減少對後端數據的訪問

成本

  • 數據的不一致性:緩存層和存儲層的數據存在一定時間窗口的不一致性,時間窗口取決於更新策略
  • 代碼維護成本:需要處理緩存層和存儲層的邏輯
  • 運維成本: 加了一層cache,比如說redis,運維肯定是有成本的

使用場景

  • 開銷大的複雜計算 如果不加緩存,每次都實時計算,無法滿足高並發量
  • 加速請求響應 這個就是為了更快,內存的io比磁盤的io快

Redis 為例講下這種緩存的設計

更新策略

剔除算法 (LRU/LFU/FIFO)
  • 使用方式 : 配置 maxmemory 和 maxmemory-policy, 對總內存進行限製,達到後按算法進行剔除
  • 場景 :這個通常是從運維角度考慮, 避免沒有限製直接影響整個機器的性能; 業務層麵來說肯定不能依賴這種更新策略
  • 維護成本 :開發人員隻需要選擇合適的算法就行,不用自己對數據進行更新
  • 一致性 :很差,你無法決定數據什麼時候會過期,完全看redis本身的算法實現和觸發機製
超時剔除
  • 使用方式 對key 設置過期時間
  • 場景 最常用的,隻要是對一致性(實時)要求不高的都可以用,可以加快處理速度哦
  • 維護成本 :不高 用expire 設置過期時間即可,前提是允許緩存數據和真實數據在過期時間內存在不一致
  • 一致性 一段時間窗口內(就是設置的過期時間)存在不一致問題
主動更新
  • 使用場景 : 一致性要求高的地方,真實數據更新後,立刻要求緩存也更新
  • 一致性: 高; 注意的地方是主動更新萬一失敗,舊數據可能會很久不被更新
  • 維護成本: 高 主要開發主動更新的邏輯,並且保證更新的正確性

粒度控製

這個實際上就是緩存內容的選擇問題,假設mongo裏有一條完整的記錄,我們是選擇全部數據都緩存還是選擇其中的部分數據緩存起來的問題
我們從3個角度來分析下

通用性

全部數據肯定比部分數據更通用,但很多業務場景隻需要部分數據

空間占用:

全部數據顯然占用更多的空間,成本更高

  • 內存還是比較昂貴的,全緩存起來可能會浪費
  • 全部數據本身如果比較大的話,在高吞吐量的情況下,對網絡帶寬影響也比較大,極端情況會阻塞網絡
  • 大的數據結構序列號和反序列化也耗時啊
代碼維護

全部數據就不用講了。。。部分數據開發成本就比較多了

結合實踐來分析下

就拿我們平台的應用信息 來說,數據非常多,基本配置幾十個字段,區分ios和android的配置也各有20來個字段,

  • 當前是全部字段 json序列化後都存redis裏呢
  • 實際業務開發中,你會經常發現我就為了拿1-2個字段,但是得整個讀出來然後還json_decode ... 覺得好蛋疼
  • 如果redis真的是緩存層,應用信息這個單節點的redis早就掛了
  • 還好,我們的redis 基本是當存儲層在用了;完整的應用信息都會有進程內緩存(php yac,java那邊也加了)起來
  • 所以實際用時的經驗來說,我覺得這種還是根據業務分門別類拆成多個key來存比較好,出了問題遷移和隔離方便,雖然開發成本高了點

緩存穿透

概念:不存在的數據每次請求都會去到存儲層查詢,並且對該數據並發請求量很大,就會對後端係統造成很大的壓力,失去了緩存保護後端存儲的意義。這就叫做緩存穿透

過程如下
  • 緩存層不命中
  • 存儲層不命中,不將空結果填入緩存
  • 返回空結果
  • 如果出現了大量存儲層的空命中,很可能就是出現了緩存穿透問題
原因分析
  • 自身的業務代碼邏輯有問題,或者數據出了問題
  • 惡意攻擊、爬蟲等造成大量空命中
辦法1 緩存空對象
  • 空值也緩存起來,就可以保護存儲層了
  • 空值緩存起來,會浪費更多內存;如果是攻擊,那就更慘了。通常的辦法是設個比較短的過期時間,讓他自動過期
  • 加了過期又需要考慮 數據不一致的問題,如果在意,還需要開發-數據有了後清除空值的邏輯
辦法2 攔截
  • 把存在的key存起來,加一層攔截
  • 常用的比如布隆過濾器 我們陌陌客戶端在用戶資料幀的”已玩過的遊戲“就用了這個攔截掉大部分請求(1.8億/2.5億)

最後更新:2017-10-21 18:33:23

  上一篇:go  交換機端口總結
  下一篇:go  Joomla行業解決方案