字節二面:假設10W人突訪,系統怎么保證不Crash ?
今年行情不大好,很多小伙伴來找我改簡歷聊面試經歷,這不,最近知識星球的同學經過朋友內推才獲得面試機會,但是在二面的時候被問倒了,這是一道場景題:假設10W人突防,系統怎么做到不crash(崩潰) ?
心理防線比較差的同學一聽到10W這個數字估計就有點崩潰了,其實仔細理解,這個題,是面試當中一道比較高端的場景題。
這個題目的回答,大有玄機。回答得有水平,能夠直接拿到offer。可惜,很多小伙伴可能一句話都說不上來。
如果面試遇到這個問題,很多小伙伴的第一反應:
怎么可能,我們的系統,總體的用戶量,不到1萬, 怎么可能會有10W人同時訪問。
疑問歸疑問。
這個問題,如果遇到了,只能會硬著頭皮作答。
如果直接用這個疑問去反問面試官,那么 ,面試官一定會說:這小子 沒有遇到過事情,沒有見過市面。
為啥呢?
因為哪怕用戶不到1萬,其實,咱們的系統,還是可能會有10W人同時訪問滴。這10W人從哪里來的呢? 這些人包括:
- 爬蟲
- 刷子(羊毛黨)
爬蟲對訪問量的貢獻
大家應該聽過一句話吧,整個互聯網上大概有 50%以上的流量其實是爬蟲。
一個做反爬蟲哥們,發現了一個極端案例,
某個頁面12000次點擊里邊,98%的點擊率,是爬蟲貢獻的。
爬蟲和用戶的比例是 19比1.
那么 1W用戶, 可能會對應到19W 爬蟲,
那么 1W用戶, 有沒有 10W的 同時訪問的可能呢?
因為 大量爬蟲的存著, 當然有的。
刷子用戶(羊毛黨)對訪問量的貢獻
“羊毛黨”戰術之一:開啟機器人批量注冊新賬號,招募“新兵”。
“這是個‘昏招’,批量注冊的賬號很容易識別。
“羊毛黨”戰術之二:提前囤積賬號,囤積的老賬號”。
但通過注冊時間、注冊地與下單地比對等方式,很快識別出來。
某年的“618”電商節活動期間,某電商公司,平均每天攔截“羊毛黨”賬號2000萬個。
那么 1W用戶, 可能會對應到多少羊毛黨用戶呢?
其中,可能會包含部分 提前囤積賬號
另外,在 活動執行的過程中, 還是有 可能 批量注冊大量的新賬號
那么 1W用戶, 有沒有 10W的 同時訪問的可能呢?
只要有利可圖,就會有 刷子用戶(羊毛黨),他們會通過群體人手,或者 自動化工具,制造大量的瞬間流量。
這些自動化工具,在 1s之內, 嘗試10W次。
所以,只要是有利可圖,如 秒殺等, 那么 1W用戶, 有沒有 10W的 同時訪問的可能呢?
當然有的。
那么,假設10W人突然訪問,現有架構能否扛住?
按照之前和大家分析的架構理論
一個系統10W人同時訪問 , 也就是:并發量為 10w Qps
那么 10w Qps ,對應到多少用戶量呢 ?
是 一個1億的用戶量。
而 ,我們很多同學手上的 系統, 總體的用戶量 不到1萬,
不到1萬的用戶,對應到多少 的 吞吐量呢?
是 10。
沒錯,如果 總體的用戶量 不到1萬,按照 正常估算, 吞吐量就只有 10。
也就是說, 如果我們按照 1萬 做系統架構
這種架構,對于 qps 為10 的小流量來說,可以說是 小菜一碟。
可以說,用牛刀 在 殺雞。
那么,如果發生突發情況,
假設10W人突然訪問,我們的架構,如何抵抗?
大家看看,上面的架構, 能抵抗嗎?
接入層和服務層如何抵抗?
方式之一:擴容
方式之二:限流
首先能用到的策略:擴容
大家首先會想到的策略,就是擴容。
但是,如果流量是突發的, 又不知道什么時候擴, 怎么辦呢?
那么就是自動擴容。
其次能用到的策略:限流
- nginx 限流
- SpringCloud gateway 限流
接入層限流可以進行 nginx 限流
微服務 SpringCloud gateway 里邊,
還 可以使用 redis lua進行分布式限流, 或者使用 sentinel 進行 限流,
經過擴容和限流,關注公眾號:碼猿技術專欄,回復關鍵詞:1111 獲取阿里內部Java性能調優手冊! 咱們的系統,應該可以扛住 10Wqps, 因為可以把流量限制到 1Wqps,甚至是 1 K qps。
誰怪 有那么多刷子流量,或者 爬蟲流量呢。
但是,限流是無奈之舉。
或者說,如果10Wqps,都是有效流量, 不能使用限流這 簡單粗暴的方式 , 而是這個 10Wqps 必須進入到服務層。
分布式Redis集群如何抵抗?
這個 10Wqps 必須進入到服務層。
怎么辦?
服務層 倒是好說,和網關一樣, 可以通過擴容解決。
所以,后面的 流量就進入 redis集群。
redis 集群一般搭建的是 3主3從:
一般來說,主節點提供服務, 從節點是做冗余的, 并不提供數據的寫入服務。
redis cluster模式官方默認主節點提供讀寫, 從節點提供slot數據備份以及故障轉移。默認情況下,從節點并不提供數據讀寫服務。
單個redis 的吞吐量,一般就是 2W左右。
那么 10Wqps,訪問 redis cluster,分布到 3個節點, 還是不夠。
如果 10Wqps 訪問的是同一個key, 那就問題更大了。
因為 單個redis 的吞吐量,一般就是 2W左右。怎么可能扛住 5倍的吞吐量。
于是就很容易出現 redis cpu 100%, 請求排隊, 沒有響應,嚴重的情況 出現 redis 雪崩。
于是乎,改怎么辦?
大概也有兩種方案:
方法一:redis 擴容
方法二:本地緩存
方法一 redis 擴容 可以解決 key 的訪問量比較 均勻的問題。比如擴容到 10主10從,就可以承擔 20Wqps的 流量。
但是方法一 要求每個key的訪問量 必須分布得比較均勻。如果20w qps 的流量,全部來自一個key, 則方案一 無效。
方法二 本地緩存 可以解決 單個key 訪問量 巨大的問題。這種 占據大量流量的 單個key,叫做 hotkey(熱key)。
所以,接下來,還是得調整系統的架構, 加入本地緩存的 環節。
解決 10WQps 突發流量的本地緩存架構
解決 10WQps 突發流量的本地緩存架構,大致有兩種:
- 二級緩存架構
- 三級緩存架構
二級緩存架構:
java 本地緩存+ redis 分布式緩存,具體如下圖:
先發問一級緩存caffeine ,如果 沒有找到,再訪問 二級緩存 redis 集群
三級緩存架構:
nginx本地緩存+ java 本地緩存+ redis 分布式緩存,具體如下圖:
本地緩存的優缺點
1. 快但是量少:訪問速度快,但無法進行大數據存儲
本地緩存相對于分布式緩存的好處是,由于數據不需要跨網絡傳輸,故性能更好,
但是由于占用了應用進程的內存空間,如 Java 進程的 JVM 內存空間,故不能進行大數據量的數據存儲。
2. 需要解決數據一致性問題:本地緩存、分布式緩存、DB數據一致性問題
與此同時,本地緩存只支持被該應用進程訪問,一般無法被其他應用進程訪問,故在應用進程的集群部署當中,
如果對應的數據庫數據,存在數據更新,則需要同步更新不同部署節點的緩存數據來包保證數據一致性,
復雜度較高并且容易出錯,如基于 rocketmq 的發布訂閱機制來同步更新各個部署節點。
3.未持久化,容易丟失:數據隨應用進程的重啟而丟失
由于本地緩存的數據是存儲在應用進程的內存空間的,所以當應用進程重啟時,本地緩存的數據會丟失。
所以對于需要更改然后持久化的數據,需要注意及時保存,否則可能會造成數據丟失。
4.需要盡量緩存熱點key,而提升緩存的命中率
由于本地緩存太小,從而很容易被淘汰,
如果還沒有來得及訪問,本地緩存中的數據,就被淘汰了,那就失去了本地緩存的價值, 當然,本地緩存的命中率也會很低。
如何提升緩存的命中率?
方式1:采用更好的 緩存淘汰策略
比如caffeine中,使用了 w-tinylfu 策略。
這種策略的 緩存的命中率,比較簡單的 lfu、lru 都 高出很多。
有測試表明:caffeine 比 guava 的命中率,不同場景,都會高出10%以上。
方式2:盡量識別和緩存 熱點數據
簡單的說,把熱點數據, 加載到本地緩存。
什么是HotKey?
在某個Key接收到的訪問次數、顯著高于其它Key時,我們可以將其稱之為HotKey,
從訪問量上來說,常見的HotKey如:
- 某Redis實例的每秒總訪問量為10000,而其中一個Key的每秒訪問量達到了7000(訪問次數顯著高于其它Key)對一個擁有上千個成員且總大小為1MB的HASH Key每秒發送大量的HGETALL(帶寬占用顯著高于其它Key)
- 對一個擁有數萬個成員的ZSET Key每秒發送大量的ZRANGE(CPU時間占用顯著高于其它Key)
從業務上來說, 常見的HotKey如:
1 、MySQL等數據庫會被頻繁訪問的熱數據
如爆款商品的skuId。
2 、redis的被密集訪問的key
如爆款商品的各維度信息,skuId、shopId等。
3 、機器人、爬蟲、刷子用戶
如用戶的userId、uuid、ip等。
4 、某個接口地址
如/sku/query或者更精細維度的。
注意,我們的HotKey探測框架只關心key,其實就是一個字符串,
HotKey對服務層和數據層的風險
在擁有大量并發用戶的系統中,HotKey一直以來都是一個不可避免的問題。
- 或許是突然某些商品成了爆款,
- 或許是海量用戶突然涌入某個店鋪,
- 或許是秒殺時瞬間大量開啟的爬蟲用戶,
- 突發大批機器人以遠超正常用戶的速度發起極其密集的請求,這些機器人只需要很小的代價,就能發出百倍于普通用戶的請求量,從而大幅擠占正常用戶的資源。
以京東為例的這些頭部互聯網公司,動輒某個爆品,會瞬間引入每秒上百萬甚至數百萬的請求,當然流量多數會在幾秒內就消失。
但就是這短短的幾秒的HotKey,就會瞬間造成其所在redis分片集群癱瘓。
原因也很簡單,redis作為一個單線程的結構,所有的請求到來后都會去排隊,當請求量遠大于自身處理能力時,后面的請求會陷入等待、超時。
由于該redis分片完全被這個key的請求給打滿,導致該分片上所有其他數據操作都無法繼續提供服務,也就是HotKey不僅僅影響自己,還會影響和它合租的數據。
這樣,redis 緩存沒有響應之后,相當于 redis 擊穿, 請求直接轉向DB
DB的吞吐量,比如會低很多,DB 就會雪崩。
總結一下,HotKey帶來的常見問題
- HotKey占用大量的Redis CPU時間,使其性能變差并影響其它請求;
- Redis Cluster中各node流量不均衡造成Redis Cluster的分布式優勢無法被Client利用,一個分片負載很高而其它分片十分空閑從而產生讀/寫熱點問題;
- 在搶購、秒殺活動中,由于商品對應庫存Key的請求量過大,超出Redis處理能力造成超賣;
- HotKey的請求壓力數量超出Redis的承受能力造成緩存擊穿,此時大量強求將直接指向后端存儲,將后端存儲打掛并影響到其它業務;
HotKey問題的根本:
HotKey問題歸根到底就是如何找到HotKey,并將HotKey放到本地內存的問題。
只要該key在內存里,我們就能極快地來對它做邏輯,內存訪問和redis訪問的速度不在一個量級。
如果該key是在本地內存中,讀取一個內存中的值,每秒多少個萬次都是很正常的,不存在任何數據層的瓶頸。
但問題是事先不知道HotKey在哪里?
那么,問題就來了,如何進行 HotKey的探測?
HotKey探測關鍵指標
1、實時性
這個很容易理解,key往往是突發性瞬間就熱了,根本不給你再慢悠悠手工去配置中心添加HotKey再推送到jvm的機會。
它大部分時間不可預知,來得也非常迅速,可能某個商家上個活動,瞬間HotKey就出現了。如果短時間內沒能進到內存,就有redis集群被打爆的風險。
所以HotKey探測框架最重要的就是實時性,最好是某個key剛有熱的苗頭,在1秒內它就已經進到整個服務集群的內存里了,1秒后就不會再去密集訪問redis了。
同理,對于刷子用戶也一樣,剛開始刷,1秒內我就把它給禁掉了。
2、準確性
這個很重要,也容易實現,累加數量,做到不誤探,精準探測,保證探測出的HotKey是完全符合用戶自己設定的閾值。
3、集群一致性
這個比較重要,尤其是某些帶刪除key的場景,要能做到刪key時整個集群內的該key都會刪掉,以避免數據的錯誤。
4、高性能
這個是核心之一,高性能帶來的就是低成本,做HotKey探測目的就是為了降低數據層的負載,提升應用層的性能,節省服務器資源。不然,大家直接去整體擴充redis集群規模就好了。
理論上,在不影響實時性的情況下,要完成實時HotKey探測,所消耗的機器資源越少,那么經濟價值就越大。
如何實現HotKey探測?
HotKey探測方案1: 流計算集群
通過 流式計算集群 storm/ flink 集群,進行 topkey
java 應用將訪問 記錄發送到 消息隊列,如 kafka
storm、flink 集群,進行top N 的計算,把top N 結果存在 redis
其中的 top N 的key,就是熱點 key
HotKey探測方案2: 流計算集群
有贊透明多級緩存解決方案
HotKey探測方案3: 結合開源hotkey,做熱點探測
比如:結合京東開源hotkey,做熱點探測
HotKey探測方案2:有贊透明多級緩存解決方案(TMC)
一、TMC簡介
1-1. TMC 是什么
TMC ,即“透明多級緩存( Transparent Multilevel Cache )”,是有贊 PaaS 團隊給公司內應用提供的整體緩存解決方案。
TMC 在通用“分布式緩存解決方案(如 CodisProxy + Redis ,如有贊自研分布式緩存系統 zanKV )”基礎上,增加了以下功能:
- 應用層熱點探測
- 應用層本地緩存
- 應用層緩存命中統計
以幫助應用層解決緩存使用過程中出現的熱點訪問問題。
1-2. 為什么要做 TMC
使用有贊服務的電商商家數量和類型很多,商家會不定期做一些“商品秒殺”、“商品推廣”活動,導致“營銷活動”、“商品詳情”、“交易下單”等鏈路應用出現 緩存熱點訪問 的情況:
- 活動時間、活動類型、活動商品之類的信息不可預期,導致 緩存熱點訪問 情況不可提前預知;
- 緩存熱點訪問 出現期間,應用層少數 熱點訪問 key 產生大量緩存訪問請求:沖擊分布式緩存系統,大量占據內網帶寬,最終影響應用層系統穩定性;
為了應對以上問題,需要一個能夠 自動發現熱點 并 將熱點緩存訪問請求前置在應用層本地緩存 的解決方案,這就是 TMC 產生的原因。
1-3. 多級緩存解決方案的痛點
基于上述描述,我們總結了下列 多級緩存解決方案 需要解決的需求痛點:
- 熱點探測:如何快速且準確的發現 熱點訪問 key ?
- 數據一致性:前置在應用層的本地緩存,如何保障與分布式緩存系統的數據一致性?
- 效果驗證:如何讓應用層查看本地緩存命中率、熱點 key 等數據,驗證多級緩存效果?
- 透明接入:整體解決方案如何減少對應用系統的入侵,做到快速平滑接入?
TMC 聚焦上述痛點,設計并實現了整體解決方案。
以支持“熱點探測”和“本地緩存”,減少熱點訪問時對下游分布式緩存服務的沖擊,避免影響應用服務的性能及穩定性。
二、 TMC 整體架構
TMC 整體架構如上圖,共分為三層:
- 存儲層:提供基礎的kv數據存儲能力,針對不同的業務場景選用不同的存儲服務( codis / zankv / aerospike );
- 代理層:為應用層提供統一的緩存使用入口及通信協議,承擔分布式數據水平切分后的路由功能轉發工作;
- 應用層:提供統一客戶端給應用服務使用,內置“熱點探測”、“本地緩存”等功能,對業務透明;
三、 TMC 本地緩存
3-1. 如何透明
TMC 是如何減少對業務應用系統的入侵,做到透明接入的?
對于公司 Java 應用服務,在緩存客戶端使用方式上分為兩類:
- 基于spring.data.redis包,使用RedisTemplate編寫業務代碼;
- 基于youzan.framework.redis包,使用RedisClient編寫業務代碼;
不論使用以上那種方式,最終通過JedisPool?創建的Jedis對象與緩存服務端代理層做請求交互。
TMC 對原生jedis包的JedisPool和Jedis類做了改造,
在JedisPool初始化過程中, 集成TMC“熱點發現”+“本地緩存”功能Hermes-SDK包的初始化邏輯,
使Jedis?客戶端與緩存服務端代理層交互時, 先與Hermes-SDK交互,從而完成 “熱點探測”+“本地緩存”功能的透明接入。
對于 Java 應用服務,只需使用特定版本的 jedis-jar 包,無需修改代碼,即可接入 TMC 使用“熱點發現”+“本地緩存”功能,做到了對應用系統的最小入侵。
3-2. 整體結構
3-2-1. 模塊劃分
TMC 本地緩存整體結構分為如下模塊:
- Jedis-Client:Java 應用與緩存服務端交互的直接入口,接口定義與原生 Jedis-Client 無異;
- Hermes-SDK:自研“熱點發現+本地緩存”功能的SDK封裝, Jedis-Client 通過與它交互來集成相應能力;
- Hermes服務端集群:接收 Hermes-SDK 上報的緩存訪問數據,進行熱點探測,將熱點 key 推送給 Hermes-SDK 做本地緩存;
- 緩存集群:由代理層和存儲層組成,為應用客戶端提供統一的分布式緩存服務入口;
- 基礎組件:etcd 集群、 Apollo 配置中心,為 TMC 提供“集群推送”和“統一配置”能力;
3-2-2. 基本流程
1) key 值獲取
- Java 應用調用 Jedis-Client 接口獲取key的緩存值時,Jedis-Client 會詢問 Hermes-SDK 該 key 當前是否是 熱點key;
- 對于 熱點key ,直接從 Hermes-SDK 的 熱點模塊 獲取熱點 key 在本地緩存的 value 值,不去訪問 緩存集群 ,從而將訪問請求前置在應用層;
- 對于非 熱點key ,Hermes-SDK 會通過Callable回調 Jedis-Client 的原生接口,從 緩存集群 拿到 value 值;
- 對于 Jedis-Client 的每次 key 值訪問請求,Hermes-SDK 都會通過其 通信模塊 將 key訪問事件 異步上報給 Hermes服務端集群 ,以便其根據上報數據進行“熱點探測”;
2)key值過期
- Java 應用調用 Jedis-Client 的set() del() expire()接口時會導致對應 key 值失效,Jedis-Client 會同步調用 Hermes-SDK 的invalid()方法告知其“ key 值失效”事件;
- 對于 熱點key ,Hermes-SDK 的 熱點模塊 會先將 key 在本地緩存的 value 值失效,以達到本地數據強一致。同時 通信模塊 會異步將“ key 值失效”事件通過 etcd集群 推送給 Java 應用集群中其他 Hermes-SDK 節點;
- 其他Hermes-SDK節點的 通信模塊 收到 “ key 值失效”事件后,會調用 熱點模塊 將 key 在本地緩存的 value 值失效,以達到集群數據最終一致;
3)熱點發現
- Hermes服務端集群 不斷收集 Hermes-SDK上報的 key訪問事件,對不同業務應用集群的緩存訪問數據進行周期性(3s一次)分析計算,以探測業務應用集群中的熱點key列表;
- 對于探測到的熱點key列表,Hermes服務端集群 將其通過 etcd集群 推送給不同業務應用集群的 Hermes-SDK 通信模塊,通知其對熱點key列表進行本地緩存;
4)配置讀取
- Hermes-SDK 在啟動及運行過程中,會從 Apollo配置中心 讀取其關心的配置信息(如:啟動關閉配置、黑白名單配置、etcd地址...);
- Hermes服務端集群 在啟動及運行過程中,會從 Apollo配置中心 讀取其關心的配置信息(如:業務應用列表、熱點閾值配置、 etcd 地址...);
3-2-3. 穩定性
TMC本地緩存穩定性表現在以下方面:
- 數據上報異步化:Hermes-SDK 使用rsyslog技術對“ key 訪問事件”進行異步化上報,不會阻塞業務;
- 通信模塊線程隔離:Hermes-SDK 的 通信模塊 使用獨立線程池+有界隊列,保證事件上報&監聽的I/O操作與業務執行線程隔離,即使出現非預期性異常也不會影響基本業務功能;
- 緩存管控:Hermes-SDK 的 熱點模塊 對本地緩存大小上限進行了管控,使其占用內存不超過 64MB(LRU),杜絕 JVM 堆內存溢出的可能;
3-2-4. 一致性
TMC 本地緩存一致性表現在以下方面:
- Hermes-SDK 的 熱點模塊 僅緩存 熱點key 數據,絕大多數非熱點 key 數據由 緩存集群 存儲;
- 熱點key 變更導致 value 失效時,Hermes-SDK 同步失效本地緩存,保證 本地強一致;
- 熱點key 變更導致 value 失效時,Hermes-SDK 通過 etcd集群 廣播事件,異步失效業務應用集群中其他節點的本地緩存,保證 集群最終一致;
四、TMC熱點發現
4-1. 整體流程
TMC 熱點發現流程分為四步:
- 數據收集:收集 Hermes-SDK 上報的 key訪問事件;
- 熱度滑窗:對 App 的每個 Key ,維護一個時間輪,記錄基于當前時刻滑窗的訪問熱度;
- 熱度匯聚:對 App 的所有 Key ,以<key,熱度>的形式進行 熱度排序匯總;
- 熱點探測:對 App ,從 熱Key排序匯總 結果中選出 TopN的熱點Key ,推送給 Hermes-SDK;
4-2. 數據收集
Hermes-SDK 通過本地rsyslog將 key訪問事件 以協議格式放入 kafka ,Hermes服務端集群 的每個節點消費 kafka 消息,實時獲取 key訪問事件。
訪問事件協議格式如下:
- appName:集群節點所屬業務應用
- uniqueKey:業務應用 key訪問事件 的 key
- sendTime:業務應用 key訪問事件 的發生時間
- weight:業務應用 key訪問事件 的訪問權值
Hermes服務端集群 節點將收集到的 key訪問事件 存儲在本地內存中,
內存數據結構為Map<String, Map<String, LongAdder>>,
對應業務含義映射為Map< appName , Map< uniqueKey , 熱度 >>。
4-3. 熱度滑窗
4-3-1. 時間滑窗
Hermes服務端集群 節點,對每個App的每個 key ,維護了一個 時間輪:
- 時間輪中共10個 時間片,每個時間片記錄當前 key 對應 3 秒時間周期的總訪問次數;
- 時間輪10個時間片的記錄累加即表示當前 key 從當前時間向前 30 秒時間窗口內的總訪問次數;
4-3-2. 映射任務
Hermes服務端集群 節點,對每個 App 每3秒 生成一個 映射任務 ,交由節點內 “緩存映射線程池” 執行。
映射任務 內容如下:
- 對當前 App ,從Map< appName , Map< uniqueKey , 熱度 >>中取出 appName 對應的Map Map< uniqueKey , 熱度 >>;
- 遍歷Map< uniqueKey , 熱度 >>中的 key ,對每個 key 取出其熱度存入其 時間輪 對應的時間片中;
4-4. 熱度匯聚
完成第二步“熱度滑窗”后,映射任務 繼續對當前 App 進行“熱度匯聚”工作:
- 遍歷 App 的 key ,將每個 key 的 時間輪 熱度進行匯總(即30秒時間窗口內總熱度)得到探測時刻 滑窗總熱度;
- 將 < key , 滑窗總熱度 > 以排序集合的方式存入 Redis存儲服務 中,即 熱度匯聚結果;
4-5. 熱點探測
- 在前幾步,每3秒 一次的 映射任務 執行,對每個 App 都會產生一份當前時刻的 熱度匯聚結果 ;
- Hermes服務端集群 中的“熱點探測”節點,對每個 App ,只需周期性從其最近一份 熱度匯聚結果 中取出達到熱度閾值的 TopN 的 key 列表,即可得到本次探測的 熱點key列表;
TMC 熱點發現整體流程如下圖:
4-6. 特性總結
4-6-1. 實時性
Hermes-SDK基于rsyslog + kafka 實時上報 key訪問事件。映射任務 3秒一個周期完成“熱度滑窗” + “熱度匯聚”工作,當有 熱點訪問場景 出現時最長3秒即可探測出對應 熱點key。
4-6-2. 準確性
key 的熱度匯聚結果由“基于時間輪實現的滑動窗口”匯聚得到,相對準確地反應當前及最近正在發生訪問分布。
4-6-3.擴展性
Hermes服務端集群 節點無狀態,節點數可基于 kafka 的 partition 數量橫向擴展。
“熱度滑窗” + “熱度匯聚” 過程基于 App 數量,在單節點內多線程擴展。
五、TMC實戰效果
5-1. 快手商家某次商品營銷活動
有贊商家通過快手直播平臺為某商品搞活動,造成該商品短時間內被集中訪問產生訪問熱點,活動期間 TMC 記錄的實際熱點訪問效果數據如下:
5-1-1. 某核心應用的緩存請求&命中率曲線圖
- 上圖藍線為應用集群調用get()方法訪問緩存次數
- 上圖綠線為獲取緩存操作命中 TMC 本地緩存的次數
- 上圖為本地緩存命中率曲線圖
可以看出活動期間緩存請求量及本地緩存命中量均有明顯增長,本地緩存命中率達到近 80% (即應用集群中 80% 的緩存查詢請求被 TMC 本地緩存攔截)。
5-1-2. 熱點緩存對應用訪問的加速效果
- 上圖為應用接口QPS曲線
- 上圖為應用接口RT曲線
可以看出活動期間應用接口的請求量有明顯增長,由于 TMC 本地緩存的效果應用接口的 RT 反而出現下降。
5-2. 雙十一期間部分應用 TMC 效果展示
5-2-1. 商品域核心應用效果
5-2-2. 活動域核心應用效果
六、TMC功能展望
在有贊, TMC 目前已為商品中心、物流中心、庫存中心、營銷活動、用戶中心、網關&消息等多個核心應用模塊提供服務,后續應用也在陸續接入中。
TMC 在提供“熱點探測” + “本地緩存”的核心能力同時,也為應用服務提供了靈活的配置選擇,應用服務可以結合實際業務情況在“熱點閾值”、“熱點key探測數量”、“熱點黑白名單”維度進行自由配置以達到更好的使用效果。
配合三級緩存的使用,需要進行 熱key的 探測,有贊平臺通過 熱key的探測和 支持,
其中:活動期間,本地緩存命中率達到近 80%的命中率, 并且, 響應時間,和平峰時段,沒有變化。
HotKey探測方案3: 結合開源hotkey,做熱點探測
基于開源hotkey進行 熱點探測,有很多小伙伴,在生產系統進行了 緩存系統的重構
下面將重構前與重構后做下對照,來說明這套機制的優缺點。
特性 | 重構系統前 | 使用京東hotkey重構系統后 |
機器資源 | 高配物理機/虛擬機 | 普通物理機/虛擬機/容器 |
管控復雜 | 無法控制熱點,不易監控 | 熱點數據可以監控統計,可以手動刷新 |
資源利用率 | 資源利用率低,無論是否是熱點數據都占用資源 | 資源利用率高,大部分熱點數據持有資源 |
突發流量 | 無法彈性應對突發流量 | 彈性應對突發流量 |
預發流量 | 預設所有數據 | 只提前預設熱點數據 |
數據一致性 | 集群內數據不一致情況時常發生,出現“橫跳”現象 | 集群內數據一致性高,極少或不發生不一致性情況 |
假設10W人同時訪問,如何保證不 雪崩?
- 擴容
- 限流
- 三級緩存
三級緩存 強烈推薦進行 熱點探測 相結合, 主要的優勢是:
- 通過熱點探測,既能提升 本地緩存命中率,
- 除此之外,還能識別 刷子用戶, 把刷子用戶加入 黑名單, 并且利用 bloom 過濾器進行緩存。 從而提升系統的安全性。