作者 | 顧海洋 攜程框架架構研發部技術專家
導讀:本文整理自作者於 2020 年雲原生微服務大會上的分享《攜程微服務框架實踐及思考》,主要介紹了從攜程自研框架遇到的問題,轉到落地 Dubbo 微服務框架,攜程是如何實踐的,以及實踐過程中遇到的問題;未來轉型 service mesh 的道路上,dubbo 協議存在的問題,我們需要怎麼樣的協議層以及微服務 SDK 的定位。
阿里巴巴雲原生公眾號後臺回覆 818 即可獲取直播回看地址和大會 PPT 合集。參與文末互動,還有機會得《攜程架構實踐》一書!
攜程從 .Net 技術棧的時代就已經開始微服務領域的探索,轉入 Java 技術棧之後,更是經歷了自研微服務框架,到現在高性能的 dubbo,目前我們正在 Service Mesh 的道路上探索,希望能夠實現微服務框架的全面標準化、以及雲原生。
過去(自研服務框架)
攜程從 .Net 技術棧開始,最開始是基於 ESB 總線,雖然解決了內網服務調用的治理問題,但是集中式的服務架構,經常會出現單個服務把整個總線拖垮的情況,進而導致全網癱瘓的現象。基於註冊中心的 SOA 服務架構,通過分佈式的服務調用,解決了單點故障帶來的巨大影響。目前,攜程主要是以 Java 技術棧為主,考慮到兼容歷史 .Net 技術棧,所以現在的框架以自研為主,但是對比開源的高性能服務框架,自研的框架可能又存在下述提到的幾個問題。
現在(CDubbo 服務框架)
CDubbo 名字裡的 C 代表攜程的治理,Dubbo 代表阿里開源的 Dubbo SDK。縱觀過去兩年的實踐和探索,從 2018 年 4 月的第一個版本落地,到現在的近萬服務實例,我們大致可以總結為下面的幾個主要里程碑。
1. 註冊發現
註冊發現是分佈式服務框架的核心要素,為了支持現有的服務互通,所以需要接入攜程的註冊中心。
服務註冊支持健康檢測擴展機制,業務可以根據業務場景自定義健康檢測擴展,例如當依賴的數據庫不可用時不再對外提供服務。服務端通過 5s 一次的心跳保持服務的可用性,當連續 N 次沒有發送心跳時就會自動通知客戶端。
客戶端發起對服務的訂閱,通過推拉結合的模式,保證節點在客戶端的最終一致性。通過 Dubbo 的擴展機制,實現了自定義的路由策略,比如根據方法名指定路由策略,以及根據請求參數決定不同的路由策略,同時也能夠支持就近訪問,優先訪問本機房的服務。
2. 監控 - CAT
對微服務來說,沒有了監控就好比瞎子一樣,什麼也不清楚。CAT 提供了分佈式鏈路追蹤的能力,可以提供很好的報表,以及場景化的問題分析。
有時,需要了解服務總的請求量以及單機的請求分佈和 QPS,或者還要知道服務的執行耗時及 99 線。CAT 的聚合報表可以幫助我們更好的瞭解服務的健康狀況。
對於超時,可能需要知道哪個階段變慢,客戶端還是服務端,序列化階段還是服務執行過程太慢。對於異常報錯,可以看到哪個過程出現的異常,同時會打印異常堆棧信息,幫助問題的定位。
3. 監控-Metrics
框架人員需要了解公司服務的宏觀情況,比如各機房都有哪些服務,哪些服務使用了 protobuf 序列化格式,哪些服務使用了 SOA 協議等,以及平均執行耗時等情況。業務同事可能也想知道自己服務具體情況,比如有哪些調用方,線程池是否已經跑滿了。
通過接入攜程的 Dashboard,可以提供全局的總量、錯誤量、線程池統計信息,也可以根據機房、協議、序列化格式等聚合數據。還能夠自定義告警規則,在問題發生時能夠儘早的介入。
4. 動態配置
對業務同事來說,有可能會存在依賴的服務突然變慢導致客戶端超時的情況。框架人員可能需要在機房故障時,需要全局調整 check 為 false,以解決 A B 服務循環依賴誰都無法啟動的問題。動態配置提供了配置熱生效的能力,不需要為了一個配置重新發布,成本很高。
服務端的多個方法,可能執行耗時也會有所不同,通過多級別的參數配置,可以設置服務默認超時為 1s,單獨為執行較慢的方法設置獨立的超時時間為 5s。
服務 Owner 可能更清楚自己服務的耗時,通過服務端對客戶端的參數設置,不需要每個調用方都設置一次超時,設置的時間也會更合理一些。為了避免配置出錯帶來的損失,我們提供了友好的可視化界面。
5. SOA 協議及互通
為了支持現有客戶端遷移到 CDubbo,需要考慮支持現有的 SOA 協議。除了要確保兼容 HTTP 1.1 協議不變,其次要保證跟客戶端的序列化器一致。
CDubbo 會通過 Tomcat 端口接收 SOA 協議的請求,利用現有的序列化器執行請求對象的轉換,並保證 Dubbo 內部調用和 Filter 鏈路的一致性,確保業務邏輯的統一,也就是業務代碼不需要改動,就可以啟動兩個協議。
6. 測試平臺
對於私有的二進制協議來說,沒有現成的 Postman 等工具可以使用。有時,開發人員需要在本地驗證測試環境的服務,也可能要驗證本地啟動的服務端,每個開發人員都構造一個客戶端顯得成本比較高。
通過 VI(github 開源叫 coreStone),以及利用 Dubbo 2.7.3 提供的元數據中心和泛化調用能力,我們實現了類似 postman 的調用工具。不但可以支持直連,也能夠支持本地測試,同時還可以支持 protobuf 序列化格式。關於 protobuf 序列化的測試方案,已經貢獻到 dubbo 社區,感興趣的同學可以自行了解。
7. 升級 Dubbo 2.7.3
關於 Dubbo 2.7.3 的詳細升級歷程,可以參考:https://www.infoq.cn/article/kOxdaV3y9fMZ0Bzs0jb2
現在回顧下升級的最終結果如何。目前,攜程 99% 的服務已經跑在 dubbo 2.7.3 之上,迄今為止 0 故障,只有一些不兼容的小問題,對於不兼容的問題也是確保了編譯時提前暴露,運行時沒有任何問題。
在發佈後,也陸續的出現了一些小的問題,比如預熱能力不生效,異常情況下不會回調 onError 等問題,支持服務端異步的 Trace 埋點等,這些問題已經在開源版本徹底修復了。
8. Threadless
業務同事反饋,需要把線程控制在理想的範圍之內。但是,dubbo 的線程數量太多,一方面是服務級獨享線程池,當調用方依賴了 10 個服務,每個服務的 QPS 為 1,lantency 可能只有 10ms 的情況下,由於每個服務獨立線程池,至少也需要 10 個線程了。如果多服務共享一個線程池,由於客戶端默認是 Cached 的線程池模式,那麼在這個場景下可能只要 1 個線程就足夠了。另一方面,對同步服務來說,dubbo 2.7.5 的 threadless 可以省去 DubboClientHandler 線程,Netty IO 線程直接把響應交給業務線程,從而節省了一次線程切換。
通過實踐,業務線程數量有了很大程度的下降,在高 QPS 以及依賴服務數量較多的情況下,甚至可以下降 60-70%。
9. CDubbo 服務體系
現有 CDubbo 的服務體系,同時支持 Dubbo 和 SOA 協議,對於 Dubbo 客戶端能夠支持 TCP 協議的傳輸,對於現有的 SOA 客戶端,能夠兼容現有的 SOA 協議。
同時,也能夠支持內網和外網 gateway 的請求,保證了多協議的配置統一,以及兼容了 SOA 的序列化格式。
10. 性能表現
從協議層面來看,Dubbo 協議的響應較 SOA 協議有所提升,平均耗時從之前的 1ms 降低到了 0.3ms 左右,當然具體提升也要根據服務的報文及請求量有所差異。
可能有些人會覺得幾毫秒的性能提升不足以掛齒,但是性能的穩定性對服務來說會很重要。我們觀察了服務流量突增 3-4 倍的情況下,客戶端還能保持 0 異常。長連接的多路複用,提供了很好的抗衝擊能力。
11. 擴展性
微服務框架跟業務代碼耦合比較重,框架人員主要是用 20% 的時間解決業務 80% 的需求,另外 20% 的需求卻需要 80% 時間的問題,更適合留給業務自己去解決,能夠提供這個能力的唯有擴展性,dubbo 無論橫向和縱向的擴展能力都很好。
通過實踐,發現業務的確在各個層級都有自己的擴展。例如:業務擴展了 Router 層,支持自己的路由規則,擴展了負載均衡策略,機票同事甚至擴展了 Transport 層換成了適合自己的傳輸協議。
12. 生態
好的生態,可以降低開發成本,例如利用現有的開源 dubbo admin,dubbo go 等組件。另外,也可以降低業務的學習成本,在其他公司學習的 dubbo 框架,到了攜程還可以接著用,不需要重新學習私有的服務框架。技術支持也比較少,很多業務同事甚至比我們還熟悉 dubbo 框架。
13. Dubbo 協議現有問題 & Dubbo 3.0 規劃
除了前面提到的 Dubbo 框架得到業界廣泛認可的優點,在我們實踐的過程中,也發現了現有的 Dubbo 2.x 版本協議存在的一些不足,比如在雲原生大背景下,協議對網關不夠友好,缺乏移動端的輕量級 SDK 等。據我們與 Dubbo 官方維護團隊的深度交流,這些點也都是當前 Dubbo 3.0 在重點突破的方向,如下一代協議、應用級服務發現、雲原生基礎設施支持等,攜程作為 Dubbo 深度用戶也將持續的參與到 Dubbo 3.0 的建設與落地過程中。
未來(Service Mesh)
網上關於 Service Mesh 的意義講了很多,眾說紛紜,個人認為可能最主要還是以下幾點。
- 標準化意味著更低的成本,比如研發成本低,學習成本也比較低,其他公司學習的微服務框架,到攜程還可以繼續用,省去了學習和踩坑的成本;
- 進程解耦,框架同學可能比較感興趣,中間件無法獨立升級的問題一直困擾著框架研發同學,在這個問題上,envoy 可以獨立升級也是值得期待的;
- 通過下沉,複用了雲基礎設施的一些能力,一方面,能夠更好的支持多語言,業務根據自己的場景選擇合適的語言,另一方面,通過下沉也能夠讓 SDK 更簡單,減少Jar依賴的兼容性問題;
- 因為更加標準以及下沉,能夠帶來更好的雲部署能力,業務出海時可以根據實際情況部署需要的組件,不再依賴框架全家桶了。
1. Service Mesh SDK
下圖是 Istio 官網提供的 Service Mesh 架構圖,如果說 Istio 解決了控制平面的標準化,envoy 或者 sofa-mosn 解決了數據平面的標準化,那麼對於 SDK 來說,是否需要有個標準化的組件,或者是否存在適合我們的標準的 SDK 呢?
對於部分中小公司,沒有自己的中間件團隊,可能會選擇商業版 SDK。但是,對於攜程這樣的規模,對擴展性要求很強,同時已經存在上千 dubbo 服務的公司來說,我們可能更期待 3.0 的標準協議。
2. 現有協議不適合下沉
現有的 SOA 協議可能不太適合作為標準協議,基於 Http 1.1 的文本協議,跟 TCP 協議相比,建連帶來的成本,很大程度上會導致長尾,影響服務的穩定性。
Dubbo 協議由於對網關不太友好,同時存在著跨語言和協議穿透性等問題,envoy 本身也可以理解為單機網關代理,所以也不太適合作為標準協議。
其次,存在的跨語言和協議穿透性問題,阿里劉軍同學有過分享,感興趣的同學可以參考:https://www.infoq.cn/article/y5HC2JjtAvMWYILmVILU
3. 新協議
既然現有的協議都不太適合,是否可以考慮雲原生的標準協議 gRPC。沒錯,從協議層面來看,這個選擇沒有問題,但是 gRPC 跟 proto 強綁定的問題,需要攜程現有的幾千個服務重寫業務邏輯代碼,這個成本可是無法被接受的。
我們對於新的協議的期待,應該是能夠基於 POJO 對象,同時還要符合 gRPC 協議規範。一方面,能夠很好的利用雲原生的基礎能力。另一方面,對於小眾語言,也可以利用現有的 gRPC 框架實現與主流 SDK 的互通。
對於新的 SDK,不但要有標準的傳輸協議,同時考慮到服務框架與業務的緊密耦合,擴展性也是要保留的主要的特性,還需要考慮 API 的標準化,利用統一的監控組件。
4. 總結
現在,我們實現了 SDK 的部分標準化。未來,我們一定會在雲原生的道路上走的更快,更穩,更標準。
有獎互動
9 月 4 日 11:00 前在阿里巴巴公眾號留言區寫下你關於微服務架構的思考或問題,點贊前 5 名即可獲得《攜程架構實踐》圖書一本!
“阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的公眾號。”