1. 程式人生 > 其它 >熱點資料多級快取方案實現(進行中)

熱點資料多級快取方案實現(進行中)

熱點資料多級快取方案實現

整合CountMinSketch過濾器+本地快取caffeine+redis快取+資料庫的多級快取方案

涉及技術點:

  1. caffeine本地快取
  2. redis:lua指令碼、redis事務的原子性
  3. CountMinSketch演算法
  4. 設計思想:計算向資料端遷移

1,背景概述

我們系統在使用過程中,並非所有的資料都是時刻活躍的狀態,一般情況下只有少部分的活躍資料佔據大量的請求。所以,我們在將其他非活躍資料也存放於redis快取或者本地快取時,是非常浪費記憶體資源的一種方式(錢多、機器多的可以無視這個)。

所以為了解決上述浪費記憶體資源的情況,我們一般將熱點資料(當前時間段訪問頻繁的資料)放入快取中從而用於加快資料的響應速度,舉一個生活中的例項:我們平時看視訊網站中的視訊,如果是當前熱播的視訊,我們點開後加載速度相對於那些冷門的視訊速度快很多。這個就是因為這些視訊網站,將熱門視訊資料也是放置在快取中,冷門資料還是儲存在磁碟中(節省費用)。

當前熱點資料快取主要有如下幾個解決方案:

  1. 使用本地快取,例如caffeine、guava、或者自定義快取。
    • 它們直接在單節點服務中使用堆記憶體進行熱點資料的快取;
    • 優點:響應及時、讀併發響應及時;
    • 缺點:
      • ①消耗堆記憶體;
      • ②如果快取中不存在需要查詢資料庫(快取穿透),如果是多節點服務,每個節點都需要重複查詢資料庫,造成資料庫查詢併發量高
      • 已刪除資料不容易進行多節點同步
  2. 使用redis快取
    • 直接使用redis中介軟體的記憶體操作功能實現熱點資料快取
    • 優點:可以響應多節點請求與資料一致性同步
    • 缺點:
      • 相較於本地快取來說,此方案需要額外的網路通訊耗時
      • ②由於redis的單執行緒資料操作,當有大key等耗時指令時,其他請求需要進行排序等待;
      • ③需要依賴中介軟體;
      • 併發相對於本地快取來說要低一些
      • ⑤如果快取中不存在需要查詢資料庫(快取穿透);
      • 熱點資料的快取策略演算法沒有caffeine等快取框架優秀(redis只有單純的LRU、LFU、TTL等簡單驅逐策略),熱點資料命中率低;

另外,在進行資料快取時,我們還經常遇到快取穿透的問題(查詢不存在或者冷門的資料,這個操作會查詢至資料庫,併發量如果很高容易導致服務崩潰),一般情況下我們可以使用布隆過濾器來解決該問題,但是布隆過濾器也有自身的問題(只能新增資料,不能刪除歷史資料)。

因此總結上述常用快取方案存在的問題:

  1. 兩種方案都存在的快取穿透問題,同時使用布隆過濾器解決快取穿透又無法刪除歷史資料;
  2. 本地快取與redis快取各有優缺點;

這裡為了解決上述的兩個問題提出瞭如下的方案【整合CountMinSketch過濾器+本地快取caffeine+redis快取+資料庫的多級快取方案】:

  1. 利用Count-Min Sketch演算法解決快取穿透的問題:
    • ①與布隆過濾器一樣,解決查詢客觀不存在資料,直接查詢資料庫的問題;
    • ②優化布隆過濾器中,不能刪除歷史資料的缺陷;
  2. 利用多級快取解決之前2種快取方案存在的缺陷:
    • ①多節點查詢客觀存在的資料,如果本地快取存在該資料,現在是直接查詢redis快取,由redis快取只查詢一次資料庫;
    • ②由於存在redis用於儲存CountMinSketch過濾器的key是否存在的資料資訊,並且該過濾器中的歷史資料可以被刪除,所以保證了每個節點的本地快取資料一致性;
    • ③現在使用本地快取消除了之前redis快取需要額外網路通訊的問題,並且繼承了本地快取的快取演算法優勢,保證了快取命中率;

同時,也需要額外說明該實現的方案的缺點:

  1. 實現相對複雜,邏輯依賴redis和資料庫(後續可以通過AOP切面代理模式,提取公共部分邏輯,生成方法註解)
  2. 當前不支援資料的修改,只支援刪除和新增(後續可以通過RPC呼叫的方式,單節點修改同步資料至其他節點,同時這些節點資訊可以直接使用redis儲存或者 )

2,技術原理

本處的多級快取方案的結構圖如下:

邏輯流程圖:

流程描述:

  1. 外部查詢請求進入,先查詢CountMinSketch過濾器

    • 如果過濾器中,不存在該資料,直接返回null,然後結束流程
    • 如果過濾器中,存在該資料,直接進入第2步
  2. 查詢caffeine本地快取

    • 如果本地快取中,存在該資料,直接返回資料,然後結束流程
    • 如果本地快取中,不存在該資料,則進行第3步進行查詢,
      • 查詢結果為null,則直接返回給呼叫方
      • 查詢結果不為null,則更新至本地快取後,返回結果資料,然後結束流程
  3. 查詢redis快取

    • 如果redis快取中,存在該資料,重置過期時間,返回該資料
    • 如果redis快取中,不存在該資料,則進入第4步進行查詢,
      • 查詢結果為null,直接返回給呼叫方
      • 查詢結果不為null,則更新至redis快取後,返回給資料呼叫方
  4. 查詢db資料庫

    • 如果db資料庫中,存在該資料,則直接返回給呼叫方
    • 如果db資料庫中,不存在該資料,則將該key值對應於CountMinSketch過濾器中資料自減1,然後將null值返回給呼叫方

3,程式碼實現

4,注意事項

5,疑問解答

  1. 之前面試的時候,有面試官認為查詢CountMinSketch過濾器的時候,都已經查詢過redis,那麼為什麼不在這次查詢的時候直接把資料返回?反而搞這麼複雜的邏輯呢?
    • ①首先,我們已經簡述過本地快取caffeine相對於redis快取的優勢,這個是我們為什麼儘量使用caffeine本地快取,而將redis快取作為輔助的原因。
      • caffeine的快取演算法更優,命中率更高,併發量也更高(演算法優勢
      • 本地快取查詢資料直接使用的堆記憶體資料,無需額外網路通訊消耗,響應更快(類比於計算機CPU的三級快取機制)
    • ②其次,我們查詢redis中的CountMinSketch過濾器時是將運算向資料遷移,最終只需要獲取redis返回的該key值是否存在的布林值即可,網路消耗很少(後續還可以進一步在redis中自定義查詢函式,更加精簡查詢命令傳輸)

參考連結