分布式系統緩存設計淺析


    前幾天聽了部門內朋春大牛講分布式緩存的一個技術分享,還是非常有收獲。

  PPT如下:

 

    這個分享的副標題是“簡單的事情從來不簡單”,這句話講得非常在理。緩存看似簡單,但要做“好”一個緩存系統也是很有講究的。   

    寫點自己的心得收獲吧:

    1. 分布式緩存面臨比較大的三個問題:

       (1) 數據一致性。

               在分布式系統這點顯得尤為重要,主要原因有三點:

               緩存系統與底層數據的一致性。這點在底層系統是“可讀可寫”時,寫得尤為重要

               有繼承關系的緩存之間的一致性。為了盡量提高緩存命中率,緩存也是分層:全局緩存,二級緩存。他們是存在繼承關系的。全局緩存可以有二級緩存來組成。

               多個緩存副本之間的一致性。為了保證系統的高可用性,緩存系統背后往往會接兩套存儲系統(如memcache,redis等),以上的ppt也主要是講這方面的內容。

       (2)緩存雪崩

               當緩存系統重啟或者所有緩存在同一時刻失效(比如某些系統為了提高速度,會在系統啟動是統一將大部分數據刷到緩存中,此時如果設置緩存時間都是24小時,那24小時過后,那就悲劇)時,應用系統由於扛不住壓力而直接掛掉。

       (3)緩存穿透

               查詢一個必然不存在的數據,查詢一個必然不存在的key,每次都會訪問DB,如果有人惡意破壞,那么很可能直接對DB造成影響。

        第一點偏重數據的真實性和實時性,而第二點和第三點更多從性能上考慮。同時緩存並不一定是必需的,特別是當寫操作特別頻繁時。

        

     2. 緩存數據的淘汰

     原先緩存數據的淘汰往往是用設置緩存時間,比如我設置某個數據的緩存時間是24小時,之后的24內這個緩存是不會失效的。優點當然是簡單,缺點也很明顯就是不都靈活,沒做到好的精細化管理。

    我們能利用的資源就是:1. 給緩存加tag,2. 版本號(必須單調遞增,時間戳是最好的選擇)3. 提供手動清理緩存的接口。

    相關步驟可以參見以上的PPT內容。

    緩存相關接口:

var me = Cache.create(...);
me.set(key, value, ttl, tags);
me.get(key);
me.tagrm(tag, offset, flush);

    緩存的數據結構如下:

var data = {
  ‘i’:now, /** 數據寫入時間戳 */
  ‘e’:now + ttl,/** 預期過期時間 */
  ‘k’:key, /** 原始key */
  ‘v’:value, /** 原始值 */
  ‘t’:tags /** tag列表 */
};

    我剛開始的也沒弄明白為什么在data中還要存“原始的key”,后來經朋春提醒,才弄明白:原始的key可能過長或者存在特殊字符時,是不能直接作為某些系統的key,因此往往會對原始key做一次hash來作為緩存的新key。

    

    3. 緩存淘汰的策略

    緩存淘汰的策略有兩種:

    (1) 定時去清理過期的緩存。

   (2)當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統得到新數據並更新緩存。

    兩者各有優劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復雜,具體用哪種方案,大家可以根據自己的應用場景來權衡。

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM