天天看點

架構設計 | 緩存管理模式,監控和記憶體回收政策

本文源碼:GitHub·點這裡 || GitEE·點這裡

在業務系統中,查詢時最容易出現性能問題的子產品,查詢面對的資料量大,篩選條件複雜,是以在系統架構中引入緩存層,則是非常必要的,用來緩存熱點資料,達到快速響應的目的。

緩存使用的基本原則:

所有緩存資料,必須設定過期時間;

核心業務流程不通過緩存層;

緩存層移除,不影響現有流程;

系統各個端首頁資料不實時查詢;

報表資料不實時查詢加載;

歸檔資料(定時統計的結果資料)不實時查詢;

這裡是業務架構中常用的緩存政策,緩存通過犧牲強一緻性來提高性能,是以并不是所有的業務都适合用緩存,實際考量都會針對具體的業務,比如使用者相關次元的資料修改頻率低,會使用緩存,但是使用者權限資料(比如:免費次數)會考慮實時校驗,緩存層使用的相對較少。

Cache-Aside模式

業務中最常用的緩存層設計模式,基本實作邏輯和相關概念如下:

架構設計 | 緩存管理模式,監控和記憶體回收政策

緩存命中:直接查詢緩存且命中,傳回資料;

緩存加載:查詢緩存未命中,從資料庫中查詢資料,擷取資料後并加載到緩存;

緩存失效:資料更新寫到資料庫,操作成功後,讓緩存失效,查詢時候再重新加載;

緩存穿透:查詢資料庫不存在的對象,也就不存在緩存層的命中;

緩存擊穿:熱點key在失效的瞬間,高并發查詢這個key,擊穿緩存,直接請求資料庫;

緩存雪崩:緩存Key大批量到過期時間,導緻資料庫壓力過大;

命中率:緩存設計的是否合理要看命中率,命中率高說明緩存有效抗住了大部分請求,命中率可以通過Redis監控資訊計算,一般來說命中率在(70-80)%都算合理。

并發問題

執行讀操作未命中緩存,然後查詢資料庫中取資料,資料已經查詢到還沒放入緩存,同時一個更新寫操作讓緩存失效,然後讀操作再把查詢到資料加載緩存,導緻緩存的髒資料。

在遵守緩存使用原則下出現該情況機率非常低,可以通過複雜的Paxos協定保證一緻性,一般情況是不考量該場景的處理,如果緩存管理過于複雜,會和緩存層核心理念相悖。

基本描述代碼:

Read-Throug模式

當應用系統向緩存系統請求資料時,如果緩存中并沒有對應的資料存在,緩存系統将向底層資料源的讀取資料。如果資料在緩存中存在,則直接傳回緩存中存在的資料。把更新資料庫的操作由緩存層代勞了。

Write-Through模式

更新寫資料時,如果沒有命中緩存,則直接更新資料庫,如果命中了緩存,則先更新緩存,然後由緩存系統自行更新資料庫。

Write-Behind模式

應用系統對緩存中的資料進行更新時,隻更新緩存,不更新資料庫,緩存系統會異步批量向底層資料源更新資料。

業務開發模式中,會涉及到一個問題:如何最大限度保證資料庫和Redis緩存的資料一緻性?

首先說明一下:資料庫和緩存強一緻性同步成本太高,如果追求強一緻,緩存層存在的價值就會很低,如上緩存模式一中幾乎可以解決大部分業務場景問題。

解決這個問題的方式很多:

架構設計 | 緩存管理模式,監控和記憶體回收政策

方案一說明:

資料庫更新寫入資料成功;

準備一個先進先出模式的消息隊列;

把更新的資料包裝為一個消息放入隊列;

基于消息消費服務更新Redis緩存;

分析:消息隊列的穩定和可靠性,操作層面資料庫和緩存層解耦。

方案二說明:

提供一個資料庫Binlog訂閱服務,并解析修改日志;

服務擷取修改資料,并向Redis服務發送消息;

Redis資料進行修改,類似MySQL的主從同步機制;

分析:系統架構層面多出一個服務,且需要解析MySQL日志,操作難度較大,但流程上更為合理。

總結描述

分布式架構中,緩存層面的基本需求就是提高響應速度,不斷優化,追求資料庫和Redis緩存的資料快速一緻性,從提供的各種方案中都可以看出,這也在增加緩存層面處理的複雜性,架構邏輯複雜,就容易導緻程式錯誤,是以針對業務選擇合理的處理邏輯,這點很關鍵。

通過info指令檢視Redis服務的參數資訊,可以通過傳參檢視指定分類配置。通過config..set設定具體配置參數。例如:

傳參說明:

memory:記憶體消耗相關資訊

server:有關Redis伺服器的正常資訊

clients:用戶端連接配接部分

stats:一般統計

cpu:CPU消耗統計資訊

應用案例:

通過上述參數組合,把Redis相關配置參數列印出來,然後可視化輸出,俨然一副高端的感覺。

配置參數說明:

這裡隻對兩個參數說明一下,計算命中率的關鍵資訊:

keyspace_misses:查找緩存Key失敗的次數;

keyspace_hits:查找緩存Key命中的次數;

公式:命中率=命中次數/(hits+misses)查找總次數。

Redis的資料是放在記憶體中的,是以速度快,自然也就受到記憶體大小的限制,如果記憶體使用超過配置,Redis有不同的回收處理政策。

記憶體子產品參數:maxmemory_policy

noenviction:不回收資料,查詢直接傳回錯誤,但可以執行删除;

allkeys-lru:從所有的資料中挑選最近最少使用的資料淘汰;

volatile-lru:已設定過期時間的資料中挑選最近最少使用的資料淘汰;

allkeys-random:從所有資料中任意選擇資料淘汰;

volatile-random:從已設定過期時間的資料中任意選擇資料淘汰;

volatile-ttl:從已設定過期時間的資料中挑選将要過期的資料淘汰;

大部分情況下,業務都是希望最熱點資料可以被緩存,是以相對使用allkeys-lru政策偏多。這裡要根據業務模式特點衡量。

架構設計 | 緩存管理模式,監控和記憶體回收政策

推薦閱讀:《架構設計系列》,蘿蔔青菜,各有所需

序号

标題

01

架構基礎:單服務.叢集.分布式,基本差別和聯系

02

架構設計:分布式業務系統中,全局ID生成政策

03

架構設計:分布式系統排程,Zookeeper叢集化管理

04

架構設計:接口幂等性原則,防重複送出Token管理