作者介紹
HongLiang,攜程進階技術專家,專注系統性能、穩定性、承載能力和交易品質,在技術架構演進、高并發等領域有豐富的實踐經驗。
一、背景
微服務架構在中大型網際網路公司中被廣泛應用,随着業務的發展,應用數越來越多、調用關系也越來越複雜。中台化後,交易系統要支援業務線多,系統複雜性高,原系統雖然能支撐業務量的持續增長,但在穩定性、吞吐力和資源使用率上面,還存在優化空間。
分享的目的
本文站在業務開發角度介紹開發在微服務架構下遇到的相關問題(微服務架構的優缺點這裡不再贅述),以門票活動預訂流程查詢引擎為例,分享微服務治理的實戰經驗,希望能給遇到同樣問題的同學提供一些借鑒思路。
如下圖所示,藍色部分為本文的重點:
圖1 微服務架構關注點
在微服務治理之前,我們先簡單了解一下微服務曆史和陷阱。
二、微服務簡史
微服務概念在2005年被提出,2011年用來代表架構風格。
定義:微服務是一種架構風格,一個大型複雜軟體應用由一個或多個微服務組成,每個微服務僅關注于完成一件任務。
1、微服務與SOA的關系
大家在使用SOA (Service-Oriented Architecture)的時候往往分不清和微服務有什麼關系,總結如下:
- 微服務是SOA的實作方式
- 微服務是去掉ESB後的SOA
- 微服務是一種和SOA相似但是兩種不同的架構設計風格
圖2 微服務與SOA的關系
了解微服務與SOA關系後,再對比一下功能差異:
表1 微服務與SOA對比
2、攜程SOA從1.0到 2.0演進
圖3 攜程SOA演進
攜程微服務:攜程SOA2.0是微服務架構,推薦單機、單應用、單服務。
三、微服務的陷阱
微服務這個話術會将關注點錯誤的聚焦在“微”上,大家會誤以為服務越小越好,實際上大小并不是第一考慮因素。接下來我們來看看開發微服務應用的時候容易踩到的陷阱。
下圖可以看出,服務拆分越細,調用關系越複雜。
調用鍊路理論上有 n * (n-1) 條:
圖4 服務粒度越細調用關系越複雜
應用粒度拆分過細容易帶來以下幾個問題:
1、重複調用
調用路徑 C - >D ->E 和 C ->E, 對于E的一次請求,可能會被調用了多次。
圖5 一次請求中服務E被重複調用
2、循環依賴
一條鍊路出問題,導緻其他鍊路故障。當服務B1或B2 性能變差時,最終導緻鍊路A/B都會被影響,嚴重情況下導緻當機。
圖6 循環依賴
3、鍊路太長
服務層級過深,一次請求鍊路太長會導緻性能下降,每層網絡延時和序列化反序列化時間都有性能損失,層級越深,下遊性能越差。
鍊路太長,定位問題困難(效率低),當服務F出現故障時,下遊A~E 應用 owner 需要排查原因。
圖7 鍊路越長,性能損失越大
以上這些問題,在日常開發中容易遇到,下面我們看看怎麼解決這些問題。
四、微服務治理
從下圖中可以看到應用之間調用關系複雜,并且有嚴重的循環依賴問題。
圖8 應用調用關系圖(雙黃線表示循環依賴)
循環依賴是微服務裡面容易忽視的問題,系統穩定的情況下不會出現問題,由于某些原因,當系統從穩定變成非穩定狀态時,循環依賴容易導緻更嚴重的故障。我們先看1個生産案例:
案例:釋出過程中下遊逾時,訂單下跌
剛接入流量的機器因線程初始化、類加載鎖、JIT等會産生慢請求。
圖9 釋出過程中的慢請求
當流量接入時,請求在剛拉入的機器中多次來回調用,因多次慢請求疊加,導緻接口越來越慢,機器資源耗盡,一台一台被拖垮,最終整個服務不可用,産生雪崩(如下圖)。
圖10 釋出過程中循環依賴導緻應用雪崩
當然如果應用間循環依賴QPS很小,例如單機QPS在10以内,少量慢請求無法将資源耗盡,一般不導緻故障,但是這種“壞味道”會給系統埋下隐患,嚴重的時候會演變為接口級的循環依賴,導緻死循環,并且這種死循環可能在測試環境由于命中緩存沒有被發現,釋出到生産後有些緩存穿透的請求就會導緻循環調用,直到逾時。
如果單機QPS上百,産生的慢請求短時間内耗盡資源,阻塞後續請求,導緻性能下降,産生故障。
故障恢複期間,由于調用關系複雜,分不清上下遊關系,無法根據調用關系來限流,導緻定位困難,恢複時間長。
上述案例主要是由循環依賴引起,像一顆炸彈,為系統埋下隐患。
除了循環依賴,還有下面幾類問題可以優化:
- 層級太深:
透傳字段要改多個應用,需求疊代效率低;
每層網絡延時、序列化和反序列化都有性能損失,導緻終端體驗差。
- 重複緩存:同一個DB不同應用重複建構緩存
- 流量大:
重複調用,直接調用或者間接調用,末尾服務壓力大;
離線任務峰值波動太大。
- 未隔離:核心、非核心流量未隔離
- 效能低:人均應用多/資源使用率低
針對上面的幾類問題,我們制定了微服務治理目标、原則和治理政策。
1、治理目标
1)穩定:故障隔離,提升系統穩定性
2)傳遞:獨立疊代、獨立擴充、快速傳遞
- 橫向拆分:減少耦合,獨立疊代。
- 縱向拆分:減少應用層級,提高開發效率,縮短傳遞周期。
3)重用:相同功能複用
不同系統重複功能複用,減少重複開發,提升一緻性。
2、治理原則
1)避免跨團隊維護一套代碼。
2)服務粒度要與團隊規模比對,人均應用數在3個以内。
根據曆史經驗,一個人在超過3個應用之間來回切換開發,開發效率會降低,日常處理告警繁瑣,業務和性能優化也無法聚焦。
3)應用分層:上一層可以依賴任意下一層級(不可反向依賴)。
4)層級深度:垂直域/小組内,應用層級控制在5層以内。
這裡的“5層”是我們根據實際業務實際情況來定的。一個垂直域/小組内應用層級超過5層,一個需求上下遊依賴太多,開發效率會降低。
3、建構原則
1)業務領域拆分:單一職責,業務模組化(對人員要求高)
2)資料存儲:獨立的資料讀寫API
3)複用性:功能複用(比如基礎資料提供能力,提供給不同小組使用)
- 可靠性
- 核心與非核心隔離
4)穩定規則與易變動規則隔離
5)快速失敗:設定合理的熔斷規則
6)異步通信:将與此次請求無關的操作/調用異步化
4、治理政策
1)去除循環依賴
問題:服務B和服務C 循環依賴
政策:
- 應用分層與定位:第一步劃分應用層級(分層工具有傳統三層架構、泛領域分層等),将應用定位劃分到不同的層級。
- 确認依賴關系:每一層内如果有多個應用,确認上下遊關系。這個根據業務場景來,根據父子關系,包含關系,依賴關系,确認每一層内的依賴關系和應用職責。
圖11 循環依賴治理
2)縮短調用鍊路
問題:服務BCD 鍊路太長(垂直域/小組内)
政策:
- 領域細分:将粗粒度的應用按照業務領域垂直劃分,不同層級負責不同的職責,讓系統更獨立。
- 減少透傳:每個層級職責清晰,減少不必要的透傳,讓開發效率更高。
圖12 縮短調用鍊路
3)複用性
問題:服務BCD 對相同資料重複緩存(存在一緻性問題)
政策:
- 下沉基礎服務,提供基礎資料:将相同的功能下沉為基礎服務,例如:基礎資料服務提供緩存,翻譯等功能。避免不同的使用方重複緩存,重複接入翻譯。
圖13 重複功能下沉
效果:下沉基礎資料服務,統一緩存,翻譯等功能,提供給不同的開發組使用。
4)流量治理
① 重複調用
問題:一次請求,服務C同一個接口被重複調用
政策:
功能内聚:将同一個功能對下遊的依賴放到同一個服務内調用。由于系統自身疊代導緻的不合理調用,可以按照上述方法優化。如果為了解耦将功能拆開,可以根據實際情況評估影響和收益。
圖14 功能内聚合并重複調用
效果:功能内聚,多次調用合并為一次調用。
② 降低調用量
問題:一個服務中,不同的接口功能拆分太細,下遊使用的時候都需要調用多個接口組裝結果。例如:一次請求服務B的a、b、c、d、e接口都被調用,下遊為實作一個功能,需要調用太多小接口。
政策:
合并服務B中同一領域功能:将相同的功能合并到一個接口,減少調用量。
一個接口提供子產品參數,按需調用:
- 支援按需使用,對不同業務場景非必須的功能,提供子產品參數,按需傳參。
- 對于獨立的前端頁面接口,對外透明,内部封裝對應場景需要的子產品參數,例如前端首屏請求。
圖15 請求合并
效果:聚合相同功能,合并小接口,多次調用合并為一次調用。
③流量隔離
問題:非核心流量(例如:Job排程)大于使用者流量
政策:
流量隔離:一套代碼,隔離部署,将核心和非核心流量隔離。核心流量承載使用者請求,保證交易的穩定性,非核心流量承載離線任務排程和非核心場景調用。
圖16 流量隔離
效果:總成本不變,核心鍊路穩定性得到提升,非核心鍊路CPU使用率得到提升。
④離線排程流量消峰
問題:機關時間内排程過于集中(Job)
政策:
合理的延長排程時間:适當延遲排程時間,降低每分鐘的調用峰值,讓每分鐘内調用量更加平穩。
圖17 離線排程流量消峰
效果:排程總時間在可接受範圍内,排程時間拉長,機關時間内調用總量降低,降低服務端峰值壓力。
問題:每秒内排程不均衡(Job),導緻服務穩定性差或為了能承載請求需要備援更多伺服器資源。
圖18 用戶端排程QPS不均衡
政策:
用戶端削峰填谷:排程波動太大,會導緻請求到了服務端被限流或者服務端擴縮容。對于排程不均衡的離線任務,我們在用戶端控制每秒内發送的請求量,讓每秒内請求更加平穩,任務排程總時間不變。
圖19 用戶端排程從不均衡變為均衡
效果:分鐘内總的調用量不變,服務端調用量從波動變為平穩。
⑤降低人均應用數/提升CPU使用率
問題:
- 人均應用過多,開發效率降低
- CPU使用率6%以下應用數占比超過50% 且總核數占比超過30%
政策:
- 短期:縮容,将單邊伺服器數縮容到SRE标準最小配置。
- 長期:合并拆分過細的應用,參考曆史、現狀和将來的規劃,将拆分過細、CPU使用率長期小于6%的應用做合并。
圖20 應用合并
五、實施效果
1、循環依賴(應用分層,解除應用間循環依賴)
- 去掉65條循環依賴鍊路,消除雪崩的風險
- 逾時類告警降低99%
- 排障效率提升至分鐘級别
2、鍊路長(減少應用層級):調用鍊深度縮短 40%
3、複用性(下沉基礎資料服務,減少重複功能)
- 新增基礎資料服務,緩存統一,解決一緻性問題
- 緩存容量減少60%
4、流量治理(降低水位線)
- 重複調用:功能内聚,去除重複調用
- 調用量大:合并小接口、消除調用峰值;離線任務削峰填谷,降低峰值調用量
- 核心應用調用量減少73%,核心系統峰值降低50%
5、開發效率(解耦&減少中間層)
- 水準拆分獨立功能,減少耦合,獨立開發
- 垂直領域減少3層,開發效率提升
6、查詢引擎性能提升65%,QPS從8w提升至24w
- 減少了系統不穩定導緻的服務變慢
- 領域劃分,垂直優化系統,專注使用者端到底層的優化
7、人均應用:人均應用數控制在2個以内
8、資源使用率(應用合并,提升CPU使用率)
- 40+個應用CPU使用率(權重平均)從18%提升至32%
- 治理前後查詢引擎鍊路對比:
圖21 門票活動查詢引擎微服務治理前後對比
六、總結
微服務架構下服務拆分越細,調用關系越複雜,層級越深,性能損耗越大,開發效率越低(垂直域/小組内),是以服務不是越小越好,而是“合适的大小”。
在建構微服務的時候,要根據業務體量、團隊規模、成本等因素綜合考慮,按照合理的原則,建構出适合的大小,以達到預期的目标。
服務治理是一個長期的過程,制定目标持續優化,讓系統更快更穩定,為業務賦能。
作者丨HongLiang
來源丨公衆号:攜程技術(ID:ctriptech)
dbaplus社群歡迎廣大技術人員投稿,投稿郵箱:[email protected]
關于我們
dbaplus社群是圍繞Database、BigData、AIOps的企業級專業社群。資深大咖、技術幹貨,每天精品原創文章推送,每周線上技術分享,每月線下技術沙龍,每季度Gdevops&DAMS行業大會。
關注公衆号【dbaplus社群】,擷取更多原創技術文章和精選工具下載下傳