在LinkedIn,為用戶資料和會(huì)員設(shè)置提供數(shù)據(jù)的身份服務(wù)是一個(gè)非常關(guān)鍵的系統(tǒng)。在本文中,我們將分享我們?nèi)绾瓮ㄟ^合并身份服務(wù)(每秒處理超過50萬個(gè)查詢請求)將延遲減少了10%,并極大降低了年度服務(wù)成本。內(nèi)容將涉及我們所使用的基于數(shù)據(jù)驅(qū)動(dòng)的架構(gòu)、用到的工具以及從舊架構(gòu)總結(jié)出的經(jīng)驗(yàn)教訓(xùn)。
1 背景
LinkedIn的會(huì)員系統(tǒng)采用了面向服務(wù)架構(gòu),以此來提供各種不同的體驗(yàn)。服務(wù)隱藏了內(nèi)部領(lǐng)域模型的復(fù)雜性,并通過定義良好的服務(wù)API把功能暴露出來。這種抽象保證了系統(tǒng)的可演化性和可組合性。
下圖是合并之前的身份服務(wù)的總體架構(gòu)圖,包括服務(wù)、客戶端和下游服務(wù)??蛻舳苏{(diào)用中間層服務(wù)獲取資料和設(shè)置信息,中間層服務(wù)依賴數(shù)據(jù)服務(wù),數(shù)據(jù)服務(wù)對Espresso(LinkedIn的分布式NoSQL數(shù)據(jù)庫)數(shù)據(jù)存儲(chǔ)執(zhí)行CRUD操作。數(shù)據(jù)服務(wù)只實(shí)現(xiàn)了有限的邏輯,比如數(shù)據(jù)驗(yàn)證(例如數(shù)據(jù)類型驗(yàn)證、字符串長度驗(yàn)證等)。中間層服務(wù)還調(diào)用了其他服務(wù),這些服務(wù)由LinkedIn的其他團(tuán)隊(duì)負(fù)責(zé)開發(fā),提供了重要的領(lǐng)域數(shù)據(jù)。這些下游服務(wù)提供了垃圾信息過濾和阻塞、會(huì)員邀請、會(huì)員連接等功能。中間層服務(wù)基于這些信息實(shí)現(xiàn)業(yè)務(wù)邏輯,確保用戶可以自由設(shè)置自己的資料以及與LinkedIn和其他第三方應(yīng)用程序交互。
2 動(dòng)機(jī)
隨著應(yīng)用程序規(guī)模的增長和系統(tǒng)功能不斷增加,開發(fā)團(tuán)隊(duì)開始把關(guān)注點(diǎn)放在了性能、服務(wù)成本和運(yùn)維開銷上。另外,我們也開始重新評估和思考之前的一些設(shè)計(jì)和開發(fā)方式。
我們發(fā)現(xiàn),繼續(xù)讓數(shù)據(jù)服務(wù)和中間層服務(wù)獨(dú)立運(yùn)行存在一些問題:
·將數(shù)據(jù)服務(wù)和中間層服務(wù)分離,這樣的設(shè)計(jì)可能沒有當(dāng)初想象得那么有價(jià)值。我們發(fā)現(xiàn),大部分伸縮性方面的問題都可以在存儲(chǔ)層解決,也就是在Espresso數(shù)據(jù)存儲(chǔ)端。況且,對Espresso讀寫操作實(shí)際上都是來自數(shù)據(jù)服務(wù)。
·將數(shù)據(jù)服務(wù)作為單獨(dú)的服務(wù)增加了運(yùn)維開銷和代碼復(fù)雜性。為此,我們分配了1000個(gè)應(yīng)用程序?qū)嵗A硗猓覀冃枰獑为?dú)為中間層提供API,涉及數(shù)據(jù)建模、API演化和安全等方面的工作。
·數(shù)據(jù)服務(wù)里只有很少的業(yè)務(wù)邏輯,大部分都與數(shù)據(jù)驗(yàn)證有關(guān)。
·對于客戶端來說,中間層服務(wù)和數(shù)據(jù)服務(wù)的分離增加了網(wǎng)絡(luò)跳數(shù)。
基于以上這些考慮,我們打算在保持API不變的情況下把中間層服務(wù)和數(shù)據(jù)服務(wù)合并成一個(gè)服務(wù)。從面相服務(wù)架構(gòu)的角度來看,這樣做有點(diǎn)違反直覺,因?yàn)槊嫦喾?wù)架構(gòu)的意義在于將大系統(tǒng)拆分成小系統(tǒng),以此來解決復(fù)雜性問題。不過,我們相信可以找到一個(gè)平衡點(diǎn),合并服務(wù)從性能、服務(wù)成本和運(yùn)維開銷方面得到的好處比合并服務(wù)帶來的復(fù)雜性要大得多。
3 實(shí)現(xiàn)
得益于微服務(wù)架構(gòu),我們可以在不影響客戶端的情況下把兩個(gè)服務(wù)合并成一個(gè)。我們保持中間層接口不變,把數(shù)據(jù)服務(wù)的代碼合并到中間層,讓中間層直接操作數(shù)據(jù)存儲(chǔ)層。我們的一個(gè)重要的目標(biāo)是盡量讓新舊架構(gòu)的功能和性能保持不變。另外,我們也要注意在合并兩個(gè)重要系統(tǒng)時(shí)可能會(huì)遇到的風(fēng)險(xiǎn),并最小化合并的開發(fā)成本。
我們分四步實(shí)現(xiàn)服務(wù)的合并。
第一步:我們有兩種方式來合并代碼庫。最直接的方式是把數(shù)據(jù)服務(wù)的代碼拷貝到中間層,這樣就可以執(zhí)行數(shù)據(jù)驗(yàn)證和調(diào)用數(shù)據(jù)存儲(chǔ)。不過,雖然這種方式最為直接,但在確定可行之前需要做很多前期的開發(fā)工作。于是,我們選擇了另外一種“取巧”的方式,我們直接將數(shù)據(jù)服務(wù)的REST API作為中間層的一個(gè)本地庫。
第二步:我們逐步執(zhí)行在第一步中定下的方案。LinkedIn有一個(gè)非常厲害的AB測試框架,叫作T-REX,我們用它生成統(tǒng)計(jì)報(bào)告,基于風(fēng)險(xiǎn)等級和變更影響范圍來安排進(jìn)度。我們可以邊觀察邊做出修改,在必要的情況下可以進(jìn)行快速回滾(在幾分鐘內(nèi))。因?yàn)槲覀兒喜⒌氖莾蓚€(gè)非常關(guān)鍵的系統(tǒng),風(fēng)險(xiǎn)較高,影響較大,所以在安排進(jìn)度時(shí)也非常謹(jǐn)慎。我們一個(gè)數(shù)據(jù)中心接一個(gè)數(shù)據(jù)中心地遷移,在每一個(gè)數(shù)據(jù)中心里也是先從小比例開始,再逐漸加大,確保有足夠的時(shí)間生成統(tǒng)計(jì)報(bào)告。
https://engineering.linkedin.com/teams/data/analytics-platform-apps/data-applications/t-rex
第三步:下線數(shù)據(jù)服務(wù)的主機(jī)。
第四步:因?yàn)榈谝徊降姆桨缸吡私輳?,直接將REST API作為本地庫調(diào)用,所以現(xiàn)在需要清理這些代碼。在LinkedIn,工匠精神是我們文化的一個(gè)重要組成部分。我們把暴露REST服務(wù)需要的類和接口移除掉,只保留訪問數(shù)據(jù)存儲(chǔ)需要的類。
下圖顯示了架構(gòu)變更前后的區(qū)別。
4 性能分析
為了比較合并前和合并后的性能,我們采用了一種叫作“Dark Canary”的機(jī)制。我們以一種可控的方式把真實(shí)的生產(chǎn)環(huán)境的只讀流量導(dǎo)給測試主機(jī)。例如,我們可以把一臺(tái)生產(chǎn)主機(jī)的流量加倍并導(dǎo)給一臺(tái)測試主機(jī),這些是在不影響生產(chǎn)主機(jī)的情況下進(jìn)行的。也就是說,我們可以在不影響業(yè)務(wù)的情況下使用生產(chǎn)流量進(jìn)行性能測試。下面是我們的Dark Canary架構(gòu)。
下面的兩張圖顯示了常規(guī)生產(chǎn)流量和測試流量的p90延遲區(qū)別。p90延遲平均從26.67毫秒下降到24.84毫秒(6.9%的下降幅度)。
通常,因?yàn)橛绊懸蛩靥?,p99指標(biāo)是很難提升的。不過,我們確實(shí)做到了??傮w來說,合并后的服務(wù)分別將p50、p90、p99提升了14%、6.9%和9.6%。
5 內(nèi)存分配
為了了解性能的特征,我們基于GC日志分析了內(nèi)存分配情況。這些日志來自三種主機(jī):中間層服務(wù)所在的測試主機(jī)、中間層所在的生產(chǎn)主機(jī)和數(shù)據(jù)服務(wù)主機(jī)。GC日志提供了非常有價(jià)值的有關(guān)對象分配模式的信息,這些信息通??梢哉f明應(yīng)用程序的性能情況以及它們是如何使用內(nèi)存的。下圖顯示了中間層所在的生產(chǎn)主機(jī)的內(nèi)存分配情況,平均內(nèi)存分配率是每秒350MB。
在合并之后,中間層服務(wù)的內(nèi)存分配率比之前每秒減少了100MB左右(28.6%)。這不僅改進(jìn)了性能,也降低了服務(wù)成本。
6 服務(wù)成本
服務(wù)成本是業(yè)務(wù)決策的一個(gè)參考因素。在LinkedIn,我們使用了一種內(nèi)部框架,基于硬件和運(yùn)維成本來計(jì)算服務(wù)成本。我們的團(tuán)隊(duì)也使用這個(gè)框架對合并后的服務(wù)進(jìn)行了分析統(tǒng)計(jì),在將數(shù)據(jù)服務(wù)所在的主機(jī)移除之后,在物理資源方面節(jié)省了超過12000個(gè)核心和13000GB的內(nèi)存,相當(dāng)于每年節(jié)省了相當(dāng)大一筆費(fèi)用。
參考閱讀:
https://engineering.linkedin.com/blog/2020/reducing-latency-and-cost-for-identity-services
作者 | 張翔等
譯者 | 無名
策劃 | 小智