不同顏色的處理框表示不同的請求。異步流程需要使用方的兩次請求才能獲取到數(shù)據(jù)。像圖中“用服務(wù)端數(shù)據(jù)更新緩存”(update cache)、“服務(wù)端數(shù)據(jù)與緩存數(shù)據(jù)匯總”(merge data)步驟在異步流程里是在第二次請求中完成的,區(qū)別于同步流程第一次請求就完成所有步驟。將數(shù)據(jù)流程拆分為這些子步驟,同步與異步只是這些步驟的不同順序的組合。因此讀寫緩存(search cache、update cache)這兩個步驟可以抽象出來,與其余邏輯解耦。
數(shù)據(jù)存儲——時間先于空間,客戶端與服務(wù)端分離
客戶端之于服務(wù)端,猶如服務(wù)端之于數(shù)據(jù)庫,其實(shí)數(shù)據(jù)存儲壓縮的思路是完全一樣的。具體的數(shù)據(jù)壓縮與存儲策略在上文數(shù)據(jù)壓縮章節(jié)已經(jīng)做了詳細(xì)介紹,這里主要想說明兩點(diǎn)問題:
客戶端壓縮與服務(wù)端壓縮由于應(yīng)用場景的不同,其目標(biāo)是有差異的。服務(wù)端壓縮使用場景是一次性高吞吐寫入,逐條高并發(fā)低延遲讀取,它主要關(guān)注的是讀取時的解壓時間和數(shù)據(jù)存儲時的壓縮比。而客戶端緩存屬于數(shù)據(jù)存儲分層中最頂端的部分,由于讀寫的場景都是高并發(fā)低延遲的本地內(nèi)存操作,因此對壓縮速度、解壓速度、數(shù)據(jù)量大小都有很高要求,它要做的權(quán)衡更多。
其次,客戶端與服務(wù)端是兩個完全獨(dú)立的模塊,說白了,雖然我們會編寫客戶端代碼,但它不屬于服務(wù)的一部分,而是調(diào)用方服務(wù)的一部分。客戶端的數(shù)據(jù)壓縮應(yīng)該盡量與服務(wù)端解耦,切不可為了貪圖實(shí)現(xiàn)方便,將兩者的數(shù)據(jù)格式耦合在一起,與服務(wù)端的數(shù)據(jù)通信格式應(yīng)該理解為一種獨(dú)立的協(xié)議,正如服務(wù)端與數(shù)據(jù)庫的通信一樣,數(shù)據(jù)通信格式與數(shù)據(jù)庫的存儲格式?jīng)]有任何關(guān)系。
內(nèi)存管理——緩存與分代回收的矛盾
緩存的目標(biāo)是讓熱數(shù)據(jù)(頻繁被訪問的數(shù)據(jù))能夠留在內(nèi)存,以便提高緩存命中率。而JVM垃圾回收(GC)的目標(biāo)是釋放失去引用的對象的內(nèi)存空間。兩者目標(biāo)看上去相似,但細(xì)微的差異讓兩者在高并發(fā)的情景下很難共存。緩存的淘汰會產(chǎn)生大量的內(nèi)存垃圾,使Full GC變得非常頻繁。這種矛盾其實(shí)不限于客戶端,而是所有JVM堆內(nèi)緩存共同面臨的問題。下面我們仔細(xì)分析一個場景:
隨著請求產(chǎn)生的數(shù)據(jù)會不斷加入緩存,QPS較高的情形下,Young GC頻繁發(fā)生,會不斷促使緩存所占用的內(nèi)存從新生代移向老年代。緩存被填滿后開始采用Least Recently Used(LRU)算法淘汰,冷數(shù)據(jù)被踢出緩存,成為垃圾內(nèi)存。然而不幸的是,由于頻繁的Young GC,有很多冷數(shù)據(jù)進(jìn)入了老年代,淘汰老年代的緩存,就會產(chǎn)生老年代的垃圾,從而引發(fā)Full GC。
可以看到,正是由于緩存的淘汰機(jī)制與新生代的GC策略目標(biāo)不一致,導(dǎo)致了緩存淘汰會產(chǎn)生很多老年代的內(nèi)存垃圾,而且產(chǎn)生垃圾的速度與緩存大小沒有太多關(guān)系,而與新生代的GC頻率以及堆緩存的淘汰速度相關(guān)。而這兩個指標(biāo)均與QPS正相關(guān)。因此堆內(nèi)緩存仿佛成了一個通向老年代的垃圾管道,QPS越高,垃圾產(chǎn)生越快!
因此,對于高并發(fā)的緩存應(yīng)用,應(yīng)該避免采用JVM的分帶管理內(nèi)存,或者可以說,GC內(nèi)存回收機(jī)制的開銷和效率并不能滿足高并發(fā)情形下的內(nèi)存管理的需求。由于JVM虛擬機(jī)的強(qiáng)制管理內(nèi)存的限制,此時我們可以將對象序列化存儲到堆外(Off Heap),來達(dá)到繞開JVM管理內(nèi)存的目的,例如Ehcache,BigMemory等第三方技術(shù)便是如此。或者改動JVM底層實(shí)現(xiàn)(類似之前淘寶的做法),做到堆內(nèi)存儲,免于GC。
三、結(jié)束語
本文主要介紹了一些在線特征系統(tǒng)的技術(shù)點(diǎn),從系統(tǒng)的高并發(fā)、高吞吐、大數(shù)據(jù)、低延遲的需求出發(fā),并以一些實(shí)際特征系統(tǒng)為原型,提出在線特征系統(tǒng)的一些設(shè)計思路。正如上文所說,特征系統(tǒng)的邊界并不限于數(shù)據(jù)的存儲與讀取。像數(shù)據(jù)導(dǎo)入作業(yè)調(diào)度、實(shí)時特征、特征計算與生產(chǎn)、數(shù)據(jù)備份、容災(zāi)恢復(fù)等等,都可看作為特征系統(tǒng)的一部分。本文是在線特征系統(tǒng)系列文章的第一篇,我們的特征系統(tǒng)也在需求與挑戰(zhàn)中不斷演進(jìn),后續(xù)會有更多實(shí)踐的經(jīng)驗(yàn)與大家分享。一家之言,難免有遺漏和偏頗之處,但是他山之石可以攻玉,若能為各位架構(gòu)師在面向自己業(yè)務(wù)時提供一些思路,善莫大焉。