背景
近幾年互聯(lián)網(wǎng)的快速發(fā)展中,互聯(lián)網(wǎng)業(yè)務(wù)發(fā)展越來越復(fù)雜,業(yè)務(wù)也被拆分得越來越細(xì),阿里內(nèi)部業(yè)務(wù)也發(fā)生著翻天覆地的變化,從最初的單體應(yīng)用,到后面的分布式集群,再到最近幾年大中臺(tái)小前臺(tái)的業(yè)務(wù)形態(tài),作為后端開發(fā),依賴的服務(wù)方越來越多,同時(shí)依賴服務(wù)方的故障因素也會(huì)越來越多的會(huì)影響到閑魚的上層業(yè)務(wù)的穩(wěn)定。 例如在閑魚主推商品流的業(yè)務(wù)場景中,商品中臺(tái)數(shù)據(jù)庫的抖動(dòng)會(huì)造成主推商品流的卡頓或者頁面顯示空窗現(xiàn)象,個(gè)性化算法中臺(tái)向量集群的擴(kuò)容也會(huì)造成推薦內(nèi)容延時(shí)被拖到非常長,后面還有可能依賴其他的業(yè)務(wù)中臺(tái),作為上層業(yè)務(wù)如何保證依賴的中臺(tái)越來越多的情況下,還能保證服務(wù)的穩(wěn)定性運(yùn)行呢? 業(yè)界主流溜一遍
根據(jù)日常解決問題的經(jīng)驗(yàn),不能直接解決業(yè)務(wù)問題本身,可以折中解決業(yè)務(wù)問題也是一個(gè)不錯(cuò)的辦法。上述業(yè)務(wù)問題中,當(dāng)業(yè)務(wù)出現(xiàn)問題的時(shí)候,可以折中提前置備好所需的業(yè)務(wù)數(shù)據(jù)返回給業(yè)務(wù),也是一個(gè)不錯(cuò)的辦法。在閑魚主推商品流的業(yè)務(wù)場景中,對可靠性要求非常高,因?yàn)橥扑]商品失敗,用戶看到推薦頁出現(xiàn)空窗,業(yè)務(wù)所需的數(shù)據(jù)量大概是5頁的推薦商品數(shù)據(jù)流,大概為3M左右。在實(shí)際解決問題中,筆者從業(yè)務(wù)所需的數(shù)據(jù)量級(jí)、可靠性要求級(jí)別等角度調(diào)研了業(yè)界一些通用解決辦法。
為了給用戶良好的業(yè)務(wù)體驗(yàn),筆者主要使用服務(wù)端數(shù)據(jù)冗余、客戶端數(shù)據(jù)冗余、熔斷機(jī)制等方法,來確保用戶對閑魚App流暢的業(yè)務(wù)體驗(yàn)。筆者主要服務(wù)端數(shù)據(jù)冗余聊聊本地緩存,根據(jù)筆者在阿里斷網(wǎng)演練的經(jīng)驗(yàn),斷網(wǎng)演練時(shí),某個(gè)區(qū)域的所有服務(wù)不可用,所以筆者在技術(shù)選型的時(shí)候沒有考慮分布式緩存Redis,Memcache之類等。目前就業(yè)界本地緩存庫有Guava、Caffeine、Ehcache、Cache2K、ConcurrentHashMap、Varnish、JackRabbit等,筆者選取了幾個(gè)性能比較優(yōu)越的緩存庫比較,下面筆者從功能上、性能上、易用性、集群能力、可視化報(bào)表上等分別比較。 筆者對照目前業(yè)務(wù)需求對比了上述四個(gè)組件,在定時(shí)失效策略能力上,除了ConcurrentHashMap都是使用定時(shí)失效能力,并且三個(gè)組件時(shí)間復(fù)雜度都是O(n)。在集群能力上,Ehcache依賴自身網(wǎng)絡(luò)協(xié)議 保證集群數(shù)據(jù)一致性,不能使用現(xiàn)有集團(tuán)內(nèi)部組件保證數(shù)據(jù)一致性。在本地緩存能力上, Caffeine的寫能力優(yōu)于Guava 。在組件通用性上,Guava組件更加通用。最終筆者選用了Guava組件作為本地緩存組件,因?yàn)镚uava 組件更加通用,并且很方便與 阿里內(nèi)部中間件集成配合使用。在集群數(shù)據(jù)同步能力,通過配置中心中間件實(shí)現(xiàn)數(shù)據(jù)同步,在可視化報(bào)表能力,通過定時(shí)任務(wù)打印日志,日志采集系統(tǒng)采集展示數(shù)據(jù)報(bào)表。接下來筆者介紹如何添加上述三種能力和優(yōu)化Guava本地緩存能力。
我的集群Cache組件
Guava Caching提供了定時(shí)失效、最后訪問失效、最后寫入失效策略等能力,筆者主要使用了定時(shí)失效能力,在首次寫入Key后,指定時(shí)間過后,該Key會(huì)失效,業(yè)務(wù)獲取該Key時(shí),會(huì)調(diào)用reload方法重新同步加載該Key。如果使用invalid方法使該Key無效,業(yè)務(wù)并發(fā)再次獲取該Key,多線程加載該Key時(shí),只有一個(gè)業(yè)務(wù)線程調(diào)用load方法加載該Key,其他線程等待該Key,加載完成后重新進(jìn)入指定時(shí)間后流程。筆者在原來Guava Cache本地緩存能力上結(jié)合Spring自動(dòng) 注入能力,進(jìn)行工程化,添加了業(yè)務(wù)所需的如下三種能力
當(dāng)key失效,本地緩存reload異步加載
失效本地緩存key,整個(gè)集群機(jī)器上key失效能力
定時(shí)上報(bào)本機(jī)Cache內(nèi)各個(gè)Key在本地緩存大小
根據(jù)上述業(yè)務(wù)能力,整體流程圖如下所示 集群本機(jī)Cache組件的整體結(jié)構(gòu)類圖如下:
-
AbstractCacheLoader重寫父類CacheLoader的reload方法,添加異步加載能力
-
LocalCacheManager管理所有實(shí)現(xiàn)AbstractCacheConfig的子類,并上報(bào)各自本地緩存大小。
-
實(shí)現(xiàn)AbstractCacheConfig的業(yè)務(wù)配置子類,例如CurrentCacheConfig等,調(diào)用invalidate方法時(shí),會(huì)通知集群本機(jī)Cache中Key消息。
業(yè)務(wù)同學(xué)在使用集群本機(jī)Cache組件時(shí),只需要繼承AbstractCacheConfig抽象類,聲明為Bean,即用集群本機(jī)Cache組件,業(yè)務(wù)同學(xué)無需關(guān)心集群環(huán)境問題等。相比Guava cache組件,提供了集群本機(jī)Cache Key失效能力,以及對Key集中管理和監(jiān)控,減少了單獨(dú)使用Guava cache帶來內(nèi)存無法管理的問題。
接下來筆者介紹使用集群本機(jī)Cache組件能力的典型案例:自動(dòng)置備兜底組件。 典型栗子:自動(dòng)置備兜底組件
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場,如有問題,請聯(lián)系我們,謝謝!