實(shí)現(xiàn)多級(jí)緩存的架構(gòu)設(shè)計(jì)方案

- 目錄 -
為什么要做 TMC
多級(jí)緩存解決方案的痛點(diǎn) TMC 整體架構(gòu) TMC 本地緩存 如何透明 整體結(jié)構(gòu) 熱點(diǎn)發(fā)現(xiàn) 整體流程 數(shù)據(jù)收集 熱度滑窗 熱度匯聚 熱點(diǎn)探測 特性總結(jié) 實(shí)戰(zhàn)效果 快手商家某次商品營銷活動(dòng) 雙十一期間部分應(yīng)用 TMC 效果展示** 功能展望

- 前言 -
應(yīng)用層熱點(diǎn)探測 應(yīng)用層本地緩存 應(yīng)用層緩存命中統(tǒng)計(jì)

- 為什么要做 TMC -
活動(dòng)時(shí)間、活動(dòng)類型、活動(dòng)商品之類的信息不可預(yù)期,導(dǎo)致 緩存熱點(diǎn)訪問 情況不可提前預(yù)知; 緩存熱點(diǎn)訪問 出現(xiàn)期間,應(yīng)用層少數(shù) 熱點(diǎn)訪問 key 產(chǎn)生大量緩存訪問請求:沖擊分布式緩存系統(tǒng),大量占據(jù)內(nèi)網(wǎng)帶寬,最終影響應(yīng)用層系統(tǒng)穩(wěn)定性;

- 多級(jí)緩存解決方案的痛點(diǎn) -
熱點(diǎn)探測:如何快速且準(zhǔn)確的發(fā)現(xiàn) 熱點(diǎn)訪問 key ? 數(shù)據(jù)一致性:前置在應(yīng)用層的本地緩存,如何保障與分布式緩存系統(tǒng)的數(shù)據(jù)一致性? 效果驗(yàn)證:如何讓應(yīng)用層查看本地緩存命中率、熱點(diǎn) key 等數(shù)據(jù),驗(yàn)證多級(jí)緩存效果? 透明接入:整體解決方案如何減少對應(yīng)用系統(tǒng)的入侵,做到快速平滑接入?

- TMC整體架構(gòu) -

存儲(chǔ)層:提供基礎(chǔ)的 kv 數(shù)據(jù)存儲(chǔ)能力,針對不同的業(yè)務(wù)場景選用不同的存儲(chǔ)服務(wù)(codis/zankv/aerospike); 代理層:為應(yīng)用層提供統(tǒng)一的緩存使用入口及通信協(xié)議,承擔(dān)分布式數(shù)據(jù)水平切分后的路由功能轉(zhuǎn)發(fā)工作; 應(yīng)用層:提供統(tǒng)一客戶端給應(yīng)用服務(wù)使用,內(nèi)置“熱點(diǎn)探測”、“本地緩存”等功能,對業(yè)務(wù)透明;

- TMC 本地緩存 -
如何透明
基于 spring.data.redis包,使用 RedisTemplate編寫業(yè)務(wù)代碼; 基于 youzan.framework.redis包,使用 RedisClient編寫業(yè)務(wù)代碼;


- 整體結(jié)構(gòu) -

- 模塊劃分 -
Jedis-Client:Java 應(yīng)用與緩存服務(wù)端交互的直接入口,接口定義與原生 Jedis-Client 無異; Hermes-SDK:自研“熱點(diǎn)發(fā)現(xiàn)+本地緩存”功能的 SDK 封裝,Jedis-Client 通過與它交互來集成相應(yīng)能力; Hermes 服務(wù)端集群:接收 Hermes-SDK 上報(bào)的緩存訪問數(shù)據(jù),進(jìn)行熱點(diǎn)探測,將熱點(diǎn) key 推送給 Hermes-SDK 做本地緩存; 緩存集群:由代理層和存儲(chǔ)層組成,為應(yīng)用客戶端提供統(tǒng)一的分布式緩存服務(wù)入口; 基礎(chǔ)組件:etcd 集群、Apollo 配置中心,為 TMC 提供“集群推送”和“統(tǒng)一配置”能力;

- 基本流程 -
Java 應(yīng)用調(diào)用 Jedis-Client 接口獲取 key 的緩存值時(shí),Jedis-Client 會(huì)詢問 Hermes-SDK 該 key 當(dāng)前是否是 熱點(diǎn)key; 對于 熱點(diǎn)key ,直接從 Hermes-SDK 的 熱點(diǎn)模塊 獲取熱點(diǎn) key 在本地緩存的 value 值,不去訪問 緩存集群 ,從而將訪問請求前置在應(yīng)用層; 對于非 熱點(diǎn)key ,Hermes-SDK 會(huì)通過 Callable回調(diào) Jedis-Client 的原生接口,從 緩存集群 拿到 value 值; 對于 Jedis-Client 的每次 key 值訪問請求,Hermes-SDK 都會(huì)通過其 通信模塊 將 key 訪問事件 異步上報(bào)給 Hermes 服務(wù)端集群 ,以便其根據(jù)上報(bào)數(shù)據(jù)進(jìn)行“熱點(diǎn)探測”;
Java 應(yīng)用調(diào)用 Jedis-Client 的 set() del() expire()接口時(shí)會(huì)導(dǎo)致對應(yīng) key 值失效,Jedis-Client 會(huì)同步調(diào)用 Hermes-SDK 的 invalid()方法告知其“key 值失效”事件; 對于 熱點(diǎn) key ,Hermes-SDK 的 熱點(diǎn)模塊 會(huì)先將 key 在本地緩存的 value 值失效,以達(dá)到本地?cái)?shù)據(jù)強(qiáng)一致。同時(shí) 通信模塊 會(huì)異步將“key 值失效”事件通過 etcd 集群 推送給 Java 應(yīng)用集群中其他 Hermes-SDK 節(jié)點(diǎn); 其他 Hermes-SDK 節(jié)點(diǎn)的 通信模塊 收到 “key 值失效”事件后,會(huì)調(diào)用 熱點(diǎn)模塊 將 key 在本地緩存的 value 值失效,以達(dá)到集群數(shù)據(jù)最終一致;
Hermes 服務(wù)端集群 不斷收集 Hermes-SDK上報(bào)的 key 訪問事件,對不同業(yè)務(wù)應(yīng)用集群的緩存訪問數(shù)據(jù)進(jìn)行周期性(3s 一次)分析計(jì)算,以探測業(yè)務(wù)應(yīng)用集群中的熱點(diǎn) key列表; 對于探測到的熱點(diǎn) key列表,Hermes 服務(wù)端集群 將其通過 etcd 集群 推送給不同業(yè)務(wù)應(yīng)用集群的 Hermes-SDK 通信模塊,通知其對熱點(diǎn) key列表進(jìn)行本地緩存;
Hermes-SDK 在啟動(dòng)及運(yùn)行過程中,會(huì)從 Apollo 配置中心 讀取其關(guān)心的配置信息(如:啟動(dòng)關(guān)閉配置、黑白名單配置、etcd 地址…); Hermes 服務(wù)端集群 在啟動(dòng)及運(yùn)行過程中,會(huì)從 Apollo 配置中心 讀取其關(guān)心的配置信息(如:業(yè)務(wù)應(yīng)用列表、熱點(diǎn)閾值配置、etcd 地址…)

- 穩(wěn)定性 -
數(shù)據(jù)上報(bào)異步化:Hermes-SDK 使用 rsyslog技術(shù)對“key 訪問事件”進(jìn)行異步化上報(bào),不會(huì)阻塞業(yè)務(wù); 通信模塊線程隔離:Hermes-SDK 的 通信模塊 使用獨(dú)立線程池+有界隊(duì)列,保證事件上報(bào)&監(jiān)聽的 I/O 操作與業(yè)務(wù)執(zhí)行線程隔離,即使出現(xiàn)非預(yù)期性異常也不會(huì)影響基本業(yè)務(wù)功能; 緩存管控:Hermes-SDK 的 熱點(diǎn)模塊 對本地緩存大小上限進(jìn)行了管控,使其占用內(nèi)存不超過 64MB(LRU),杜絕 JVM 堆內(nèi)存溢出的可能;

- 一致性 -
Hermes-SDK 的 熱點(diǎn)模塊 僅緩存 熱點(diǎn) key 數(shù)據(jù),絕大多數(shù)非熱點(diǎn) key數(shù)據(jù)由 緩存集群 存儲(chǔ); 熱點(diǎn) key 變更導(dǎo)致 value 失效時(shí),Hermes-SDK 同步失效本地緩存,保證 本地強(qiáng)一致; 熱點(diǎn) key 變更導(dǎo)致 value 失效時(shí),Hermes-SDK 通過 etcd 集群 廣播事件,異步失效業(yè)務(wù)應(yīng)用集群中其他節(jié)點(diǎn)的本地緩存,保證 集群最終一致;

- 熱點(diǎn)發(fā)現(xiàn) -
整體流程

數(shù)據(jù)收集:收集 Hermes-SDK 上報(bào)的 key 訪問事件; 熱度滑窗:對 App 的每個(gè) Key,維護(hù)一個(gè)時(shí)間輪,記錄基于當(dāng)前時(shí)刻滑窗的訪問熱度; 熱度匯聚:對 App 的所有 Key,以 的形式進(jìn)行 熱度排序匯總;
熱點(diǎn)探測:對 App,從 熱 Key 排序匯總 結(jié)果中選出 TopN 的熱點(diǎn) Key ,推送給 Hermes-SDK;

- 數(shù)據(jù)收集 -
appName:集群節(jié)點(diǎn)所屬業(yè)務(wù)應(yīng)用 uniqueKey:業(yè)務(wù)應(yīng)用 key 訪問事件 的 key sendTime:業(yè)務(wù)應(yīng)用 key 訪問事件 的發(fā)生時(shí)間 weight:業(yè)務(wù)應(yīng)用 key 訪問事件 的訪問權(quán)值

- 熱度滑窗 -


- 時(shí)間滑窗 -
時(shí)間輪中共 10 個(gè) 時(shí)間片,每個(gè)時(shí)間片記錄當(dāng)前 key 對應(yīng) 3 秒時(shí)間周期的總訪問次數(shù); 時(shí)間輪 10 個(gè)時(shí)間片的記錄累加即表示當(dāng)前 key 從當(dāng)前時(shí)間向前 30 秒時(shí)間窗口內(nèi)的總訪問次數(shù);

- 映射任務(wù) -
對當(dāng)前 App,從 Map<appname,map>< appname,map<="" code="">中取出 appName 對應(yīng)的 Map Map
> ;
遍歷 Map > 中的 key,對每個(gè) key 取出其熱度存入其 時(shí)間輪 對應(yīng)的時(shí)間片中。

- 熱度匯聚 -

遍歷 App 的 key,將每個(gè) key 的 時(shí)間輪 熱度進(jìn)行匯總(即 30 秒時(shí)間窗口內(nèi)總熱度)得到探測時(shí)刻 滑窗總熱度; 將 < key , 滑窗總熱度 > 以排序集合的方式存入 Redis 存儲(chǔ)服務(wù) 中,即 熱度匯聚結(jié)果;

- 熱點(diǎn)探測 -
在前幾步,每 3 秒 一次的 映射任務(wù) 執(zhí)行,對每個(gè) App 都會(huì)產(chǎn)生一份當(dāng)前時(shí)刻的 熱度匯聚結(jié)果 Hermes 服務(wù)端集群 中的“熱點(diǎn)探測”節(jié)點(diǎn),對每個(gè) App,只需周期性從其最近一份 熱度匯聚結(jié)果 中取出達(dá)到熱度閾值的 TopN 的 key 列表,即可得到本次探測的 熱點(diǎn) key 列表;


- 特性總結(jié) -
實(shí)時(shí)性
準(zhǔn)確性
擴(kuò)展性

- 實(shí)戰(zhàn)效果 -
快手商家某次商品營銷活動(dòng)
某核心應(yīng)用的緩存請求&命中率曲線圖:

上圖藍(lán)線為應(yīng)用集群調(diào)用get()方法訪問緩存次數(shù) 上圖綠線為獲取緩存操作命中TMC本地緩存的次數(shù)

上圖為本地緩存命中率曲線圖
熱點(diǎn)緩存對應(yīng)用訪問的加速效果:

上圖為應(yīng)用接口 QPS 曲線

上圖為應(yīng)用接口 RT 曲線
雙十一期間部分應(yīng)用 TMC 效果展示:
商品域核心應(yīng)用效果

活動(dòng)域核心應(yīng)用效果



- 功能展望 -
作者:有贊技術(shù)
來源:https://segmentfault.com/a/1190000017142556/

評論
圖片
表情

