2018年末最后一篇
原文發(fā)布于 https://mp.weixin.qq.com/s/BnWtbetNq076iRRZfnGRrw
一侥加、引子
1-1. TMC 是什么
TMC 镣丑,即“透明多級緩存( Transparent Multilevel Cache )”浑娜,是有贊 PaaS 團隊給公司內(nèi)應(yīng)用提供的整體緩存解決方案。
TMC 在通用“分布式緩存解決方案(如 CodisProxy + Redis ,如有贊自研分布式緩存系統(tǒng) zanKV )”基礎(chǔ)上,增加了以下功能:
- 應(yīng)用層熱點探測
- 應(yīng)用層本地緩存
- 應(yīng)用層緩存命中統(tǒng)計
以幫助應(yīng)用層解決緩存使用過程中出現(xiàn)的熱點訪問問題臭脓。
1-2. 為什么要做 TMC
使用有贊服務(wù)的電商商家數(shù)量和類型很多,商家會不定期做一些“商品秒殺”腹忽、“商品推廣”活動来累,導(dǎo)致“營銷活動”、“商品詳情”窘奏、“交易下單”等鏈路應(yīng)用出現(xiàn) 緩存熱點訪問 的情況:
- 活動時間嘹锁、活動類型、活動商品之類的信息不可預(yù)期着裹,導(dǎo)致 緩存熱點訪問 情況不可提前預(yù)知领猾;
- 緩存熱點訪問 出現(xiàn)期間,應(yīng)用層少數(shù) **熱點訪問 key ** 產(chǎn)生大量緩存訪問請求:沖擊分布式緩存系統(tǒng)骇扇,大量占據(jù)內(nèi)網(wǎng)帶寬摔竿,最終影響應(yīng)用層系統(tǒng)穩(wěn)定性;
為了應(yīng)對以上問題少孝,需要一個能夠 自動發(fā)現(xiàn)熱點 并 將熱點緩存訪問請求前置在應(yīng)用層本地緩存 的解決方案继低,這就是 TMC 產(chǎn)生的原因。
1-3. 多級緩存解決方案的痛點
基于上述描述稍走,我們總結(jié)了下列 多級緩存解決方案 需要解決的需求痛點:
- 熱點探測:如何快速且準確的發(fā)現(xiàn) **熱點訪問 key ** 袁翁?
- 數(shù)據(jù)一致性:前置在應(yīng)用層的本地緩存柴底,如何保障與分布式緩存系統(tǒng)的數(shù)據(jù)一致性?
- 效果驗證:如何讓應(yīng)用層查看本地緩存命中率粱胜、熱點 key 等數(shù)據(jù)柄驻,驗證多級緩存效果?
- 透明接入:整體解決方案如何減少對應(yīng)用系統(tǒng)的入侵焙压,做到快速平滑接入鸿脓?
TMC 聚焦上述痛點,設(shè)計并實現(xiàn)了整體解決方案涯曲。以支持“熱點探測”和“本地緩存”答憔,減少熱點訪問時對下游分布式緩存服務(wù)的沖擊,避免影響應(yīng)用服務(wù)的性能及穩(wěn)定性掀抹。
二、 TMC 整體架構(gòu)
TMC 整體架構(gòu)如上圖心俗,共分為三層:
- 存儲層:提供基礎(chǔ)的kv數(shù)據(jù)存儲能力傲武,針對不同的業(yè)務(wù)場景選用不同的存儲服務(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)置“熱點探測”狠持、“本地緩存”等功能疟位,對業(yè)務(wù)透明;
本篇聚焦在應(yīng)用層客戶端的“熱點探測”喘垂、“本地緩存”功能甜刻。
三、 TMC 本地緩存
3-1. 如何透明
TMC 是如何減少對業(yè)務(wù)應(yīng)用系統(tǒng)的入侵正勒,做到透明接入的得院?
對于公司 Java 應(yīng)用服務(wù),在緩存客戶端使用方式上分為兩類:
- 基于
spring.data.redis
包章贞,使用RedisTemplate
編寫業(yè)務(wù)代碼祥绞; - 基于
youzan.framework.redis
包,使用RedisClient
編寫業(yè)務(wù)代碼鸭限;
不論使用以上那種方式蜕径,最終通過JedisPool
創(chuàng)建的Jedis
對象與緩存服務(wù)端代理層做請求交互。
TMC 對原生jedis包的JedisPool
和Jedis
類做了改造败京,在JedisPool初始化過程中集成TMC“熱點發(fā)現(xiàn)”+“本地緩存”功能Hermes-SDK
包的初始化邏輯兜喻,使Jedis
客戶端與緩存服務(wù)端代理層交互時先與Hermes-SDK
交互,從而完成 “熱點探測”+“本地緩存”功能的透明接入赡麦。
對于 Java 應(yīng)用服務(wù)虹统,只需使用特定版本的 jedis-jar 包弓坞,無需修改代碼,即可接入 TMC 使用“熱點發(fā)現(xiàn)”+“本地緩存”功能车荔,做到了對應(yīng)用系統(tǒng)的最小入侵渡冻。
3-2. 整體結(jié)構(gòu)
3-2-1. 模塊劃分
TMC 本地緩存整體結(jié)構(gòu)分為如下模塊:
- Jedis-Client: Java 應(yīng)用與緩存服務(wù)端交互的直接入口,接口定義與原生 Jedis-Client 無異忧便;
- Hermes-SDK:自研“熱點發(fā)現(xiàn)+本地緩存”功能的SDK封裝族吻, Jedis-Client 通過與它交互來集成相應(yīng)能力;
- Hermes服務(wù)端集群:接收 Hermes-SDK 上報的緩存訪問數(shù)據(jù)珠增,進行熱點探測超歌,將熱點 key 推送給 Hermes-SDK 做本地緩存;
- 緩存集群:由代理層和存儲層組成蒂教,為應(yīng)用客戶端提供統(tǒng)一的分布式緩存服務(wù)入口巍举;
- 基礎(chǔ)組件: etcd 集群、 Apollo 配置中心凝垛,為 TMC 提供“集群推送”和“統(tǒng)一配置”能力懊悯;
3-2-2. 基本流程
1) key 值獲取
- Java 應(yīng)用調(diào)用 Jedis-Client 接口獲取key的緩存值時,Jedis-Client 會詢問 Hermes-SDK 該 key 當(dāng)前是否是 熱點key梦皮;
- 對于 熱點key 炭分,直接從 Hermes-SDK 的 熱點模塊 獲取熱點 key 在本地緩存的 value 值,不去訪問 緩存集群 剑肯,從而將訪問請求前置在應(yīng)用層捧毛;
- 對于非 熱點key ,Hermes-SDK 會通過
Callable
回調(diào) Jedis-Client 的原生接口让网,從 緩存集群 拿到 value 值呀忧; - 對于 Jedis-Client 的每次 key 值訪問請求,Hermes-SDK 都會通過其 通信模塊 將 key訪問事件 異步上報給 Hermes服務(wù)端集群 溃睹,以便其根據(jù)上報數(shù)據(jù)進行“熱點探測”荐虐;
2)key值過期
- Java 應(yīng)用調(diào)用 Jedis-Client 的
set()
del()
expire()
接口時會導(dǎo)致對應(yīng) key 值失效,Jedis-Client 會同步調(diào)用 Hermes-SDK 的invalid()
方法告知其“ key 值失效”事件丸凭; - 對于 熱點key 福扬,Hermes-SDK 的 熱點模塊 會先將 key 在本地緩存的 value 值失效,以達到本地數(shù)據(jù)強一致惜犀。同時 通信模塊 會異步將“ key 值失效”事件通過 etcd集群 推送給 Java 應(yīng)用集群中其他 Hermes-SDK 節(jié)點铛碑;
- 其他Hermes-SDK節(jié)點的 通信模塊 收到 “ key 值失效”事件后,會調(diào)用 熱點模塊 將 key 在本地緩存的 value 值失效虽界,以達到集群數(shù)據(jù)最終一致汽烦;
3)熱點發(fā)現(xiàn)
- Hermes服務(wù)端集群 不斷收集 Hermes-SDK上報的 key訪問事件,對不同業(yè)務(wù)應(yīng)用集群的緩存訪問數(shù)據(jù)進行周期性(3s一次)分析計算莉御,以探測業(yè)務(wù)應(yīng)用集群中的熱點key列表撇吞;
- 對于探測到的熱點key列表俗冻,Hermes服務(wù)端集群 將其通過 etcd集群 推送給不同業(yè)務(wù)應(yīng)用集群的 Hermes-SDK 通信模塊,通知其對熱點key列表進行本地緩存牍颈;
4)配置讀取
- Hermes-SDK 在啟動及運行過程中迄薄,會從 Apollo配置中心 讀取其關(guān)心的配置信息(如:啟動關(guān)閉配置、黑白名單配置煮岁、etcd地址...)讥蔽;
- Hermes服務(wù)端集群 在啟動及運行過程中,會從 Apollo配置中心 讀取其關(guān)心的配置信息(如:業(yè)務(wù)應(yīng)用列表画机、熱點閾值配置冶伞、 etcd 地址...);
3-2-3. 穩(wěn)定性
TMC本地緩存穩(wěn)定性表現(xiàn)在以下方面:
- 數(shù)據(jù)上報異步化:Hermes-SDK 使用
rsyslog技術(shù)
對“ key 訪問事件”進行異步化上報步氏,不會阻塞業(yè)務(wù)响禽; - 通信模塊線程隔離:Hermes-SDK 的 通信模塊 使用獨立線程池+有界隊列,保證事件上報&監(jiān)聽的I/O操作與業(yè)務(wù)執(zhí)行線程隔離荚醒,即使出現(xiàn)非預(yù)期性異常也不會影響基本業(yè)務(wù)功能芋类;
- 緩存管控:Hermes-SDK 的 熱點模塊 對本地緩存大小上限進行了管控,使其占用內(nèi)存不超過 64MB(LRU)腌且,杜絕 JVM 堆內(nèi)存溢出的可能;
3-2-4. 一致性
TMC 本地緩存一致性表現(xiàn)在以下方面:
- Hermes-SDK 的 熱點模塊 僅緩存 熱點key 數(shù)據(jù)榛瓮,絕大多數(shù)非熱點 key 數(shù)據(jù)由 緩存集群 存儲铺董;
- 熱點key 變更導(dǎo)致 value 失效時,Hermes-SDK 同步失效本地緩存禀晓,保證 本地強一致精续;
- 熱點key 變更導(dǎo)致 value 失效時,Hermes-SDK 通過 etcd集群 廣播事件粹懒,異步失效業(yè)務(wù)應(yīng)用集群中其他節(jié)點的本地緩存重付,保證 集群最終一致;
四凫乖、TMC熱點發(fā)現(xiàn)
4-1. 整體流程
TMC 熱點發(fā)現(xiàn)流程分為四步:
- 數(shù)據(jù)收集:收集 Hermes-SDK 上報的 key訪問事件确垫;
- 熱度滑窗:對 App 的每個 Key ,維護一個時間輪帽芽,記錄基于當(dāng)前時刻滑窗的訪問熱度删掀;
-
熱度匯聚:對 App 的所有 Key ,以
<key,熱度>
的形式進行 熱度排序匯總导街; - 熱點探測:對 App 披泪,從 熱Key排序匯總 結(jié)果中選出 TopN的熱點Key ,推送給 Hermes-SDK搬瑰;
4-2. 數(shù)據(jù)收集
Hermes-SDK 通過本地rsyslog
將 key訪問事件 以協(xié)議格式放入 kafka 款票,Hermes服務(wù)端集群 的每個節(jié)點消費 kafka 消息控硼,實時獲取 key訪問事件。
訪問事件協(xié)議格式如下:
- appName:集群節(jié)點所屬業(yè)務(wù)應(yīng)用
- uniqueKey:業(yè)務(wù)應(yīng)用 key訪問事件 的 key
- sendTime:業(yè)務(wù)應(yīng)用 key訪問事件 的發(fā)生時間
- weight:業(yè)務(wù)應(yīng)用 key訪問事件 的訪問權(quán)值
Hermes服務(wù)端集群 節(jié)點將收集到的 key訪問事件 存儲在本地內(nèi)存中艾少,內(nèi)存數(shù)據(jù)結(jié)構(gòu)為Map<String, Map<String, LongAdder>>
卡乾,對應(yīng)業(yè)務(wù)含義映射為Map< appName , Map< uniqueKey , 熱度 >>
。
4-3. 熱度滑窗
4-3-1. 時間滑窗
Hermes服務(wù)端集群 節(jié)點姆钉,對每個App的每個 key 说订,維護了一個 時間輪:
- 時間輪中共10個 時間片,每個時間片記錄當(dāng)前 key 對應(yīng) 3 秒時間周期的總訪問次數(shù)潮瓶;
- 時間輪10個時間片的記錄累加即表示當(dāng)前 key 從當(dāng)前時間向前 30 秒時間窗口內(nèi)的總訪問次數(shù)陶冷;
4-3-2. 映射任務(wù)
Hermes服務(wù)端集群 節(jié)點,對每個 App 每3秒 生成一個 映射任務(wù) 毯辅,交由節(jié)點內(nèi) “緩存映射線程池” 執(zhí)行埂伦。映射任務(wù) 內(nèi)容如下:
- 對當(dāng)前 App ,從
Map< appName , Map< uniqueKey , 熱度 >>
中取出 appName 對應(yīng)的MapMap< uniqueKey , 熱度 >>
思恐; - 遍歷
Map< uniqueKey , 熱度 >>
中的 key 沾谜,對每個 key 取出其熱度存入其 時間輪 對應(yīng)的時間片中;
4-4. 熱度匯聚
完成第二步“熱度滑窗”后胀莹,映射任務(wù) 繼續(xù)對當(dāng)前 App 進行“熱度匯聚”工作:
- 遍歷 App 的 key 基跑,將每個 key 的 時間輪 熱度進行匯總(即30秒時間窗口內(nèi)總熱度)得到探測時刻 滑窗總熱度;
- 將
< key , 滑窗總熱度 >
以排序集合的方式存入 Redis存儲服務(wù) 中描焰,即 熱度匯聚結(jié)果媳否;
4-5. 熱點探測
- 在前幾步,每3秒 一次的 映射任務(wù) 執(zhí)行荆秦,對每個 App 都會產(chǎn)生一份當(dāng)前時刻的 熱度匯聚結(jié)果 篱竭;
- Hermes服務(wù)端集群 中的“熱點探測”節(jié)點,對每個 App 步绸,只需周期性從其最近一份 熱度匯聚結(jié)果 中取出達到熱度閾值的 TopN 的 key 列表掺逼,即可得到本次探測的 熱點key列表;
TMC 熱點發(fā)現(xiàn)整體流程如下圖:
4-6. 特性總結(jié)
4-6-1. 實時性
Hermes-SDK基于rsyslog + kafka 實時上報 key訪問事件瓤介。
映射任務(wù) 3秒一個周期完成“熱度滑窗” + “熱度匯聚”工作吕喘,當(dāng)有 熱點訪問場景 出現(xiàn)時最長3秒即可探測出對應(yīng) 熱點key。
4-6-2. 準確性
key 的熱度匯聚結(jié)果由“基于時間輪實現(xiàn)的滑動窗口”匯聚得到刑桑,相對準確地反應(yīng)當(dāng)前及最近正在發(fā)生訪問分布兽泄。
4-6-3.擴展性
Hermes服務(wù)端集群 節(jié)點無狀態(tài),節(jié)點數(shù)可基于 kafka 的 partition 數(shù)量橫向擴展漾月。
“熱度滑窗” + “熱度匯聚” 過程基于 App 數(shù)量病梢,在單節(jié)點內(nèi)多線程擴展。
五、TMC實戰(zhàn)效果
5-1. 快手商家某次商品營銷活動
有贊商家通過快手直播平臺為某商品搞活動蜓陌,造成該商品短時間內(nèi)被集中訪問產(chǎn)生訪問熱點觅彰,活動期間 TMC 記錄的實際熱點訪問效果數(shù)據(jù)如下:
5-1-1. 某核心應(yīng)用的緩存請求&命中率曲線圖
上圖藍線為應(yīng)用集群調(diào)用
get()
方法訪問緩存次數(shù)-
上圖綠線為獲取緩存操作命中 TMC 本地緩存的次數(shù)
本地緩存命中率曲線圖 上圖為本地緩存命中率曲線圖
可以看出活動期間緩存請求量及本地緩存命中量均有明顯增長,本地緩存命中率達到近 80% (即應(yīng)用集群中 80% 的緩存查詢請求被 TMC 本地緩存攔截)钮热。
5-1-2. 熱點緩存對應(yīng)用訪問的加速效果
-
上圖為應(yīng)用接口QPS曲線
應(yīng)用接口RT曲線 上圖為應(yīng)用接口RT曲線
可以看出活動期間應(yīng)用接口的請求量有明顯增長填抬,由于 TMC 本地緩存的效果應(yīng)用接口的 RT 反而出現(xiàn)下降。
5-2. 雙十一期間部分應(yīng)用 TMC 效果展示
5-2-1. 商品域核心應(yīng)用效果
5-2-2. 活動域核心應(yīng)用效果
六隧期、TMC功能展望
在有贊飒责, TMC 目前已為商品中心、物流中心仆潮、庫存中心宏蛉、營銷活動、用戶中心性置、網(wǎng)關(guān)&消息等多個核心應(yīng)用模塊提供服務(wù)拾并,后續(xù)應(yīng)用也在陸續(xù)接入中。
TMC 在提供“熱點探測” + “本地緩存”的核心能力同時鹏浅,也為應(yīng)用服務(wù)提供了靈活的配置選擇嗅义,應(yīng)用服務(wù)可以結(jié)合實際業(yè)務(wù)情況在“熱點閾值”、“熱點key探測數(shù)量”隐砸、“熱點黑白名單”維度進行自由配置以達到更好的使用效果之碗。
最后, TMC 的迭代還在持續(xù)進行中...