開源微服務框架 Apache ServiceComb 的前身爲華爲雲的 微服務引擎 CSE (Cloud Service Engine) 雲服務, ServiceComb 的早期版本和多數第一批作微服務或分佈式框架先賢同樣,爲了追求高性能,作過很是多如 改善編碼效率 和改進通訊協議等嘗試。然而,隨着業務規模的遞增,需求也逐漸呈現多樣化,單方面經過傳統手段追求高性能致使在面對多樣化需求時遇到了各類挑戰,遺留系統的通訊、接入各類不一樣的終端、協議健壯性、防攻擊等各類挑戰迎面而來。html
Apache ServiceComb,願景是幫助企業快速構建雲原生應用,經過一系列解決方案幫助用戶快速開發微服務應用的同時實現對這些微服務應用的高效運維管理,保持中立性以免廠商LockIn成爲了關鍵任務。對於此, Apache ServiceComb 須要有友好的機制可以對接各微服務主流技術棧技術 或 開發框架。java
在系列挑戰的驅動下, Aapche ServiceComb 設計團隊逐步造成了 「全面開放,使用標準協議,架構易於拆分和擴展,對開發人員友好,能夠與業界其餘主流框架互通集成」 的共識, 本文將着重分享這些共識是如何體如今Apache ServiceComb 的設計中的。git
開放和標準應用到設計的不一樣的層面。一方面是鏈接組織和開發人員,一方面是鏈接異構系統。組織和開發人員的複雜性來源於技能的多樣性,你們使用不一樣的開發語言,同一種開發語言存在多樣的開發習慣;系統的多樣性來源於系統之間的通訊協議,爲了實現與異構系統的通訊,必須具有良好的適配不一樣通訊協議的能力。github
每位技術人員都或多或少擁有本身的 Coding 習慣或愛好的技術, 使用我的熟練的方式從事技術工做每每更加高效和溫馨。spring
開源微服務框架 Apache ServiceComb 的早期版本實現了 gRPC 協議,然而在項目演進過程當中咱們發現大量技術人員並不熟悉書寫 IDL , 對 IDL 具體支持哪些特性也不清楚。 大多數狀況下,用戶每碰到一個場景就須要翻開協議規範看一遍, 而 IDL 缺乏配套的編輯或語法檢查等工具也致使了開發效率的下降。shell
因而 Apache ServiceComb 設計團隊開始思考是否有方法可以在確保保持用戶開發習慣的前提下支持 gRPC 。數據庫
設計團隊結合本身的 Java 編程史,分析當下主流框架,並聽取社區用戶的反饋找到了一些共性:apache
Apache ServiceComb 很快在社區設計層面達成了一致,經過缺省支持以上共性來擁抱90%的開發者, 讓大多數的 Java 開發者們可以快速開始工做。編程
除以上共識外,Apache ServiceComb 還額外作了進一步的優化,以保證不一樣編程風格的兼容性,使用戶或開發者倍感靈活及溫馨。json
在下面的例子中,展現了 Provider和Consumer 代碼的各類實現,在同一個微服務中,這些編程方式能夠同時出現;同一段 Consumer 代碼中能夠訪問各類不一樣的編程風格的 Provider 實現。
RPC 方式的 Provider
@RpcSchema(schemaId="hello") public class HelloImpl implements Hello{ @Override public String sayHi(String name){ return"Hello"+name; } @Override public String sayHello(Person person){ return"Helloperson"+person.getName(); } }
JAX-RS 方式的 Provider
代碼片斷來自於 Apache ServiceComb JAX-RS sample
@RestSchema(schemaId="jaxrsHello") @Path("/jaxrshello") @Produces(MediaType.APPLICATION_JSON) public class JaxrsHelloImpl implements Hello{ @Path("/sayhi") @POST @Override public String sayHi(String name){ return"Hello"+name; } @Path("/sayhello") @POST @Override public String sayHello(Person person){ return"Helloperson"+person.getName(); } }
Spring MVC 方式的 Provider
代碼片斷來自於 Apache ServiceComb Spring MVC sample
@RestSchema(schemaId="springmvcHello") @RequestMapping(path="/springmvchello",produces=MediaType.APPLICATION_JSON) public class SpringmvcHelloImpl implements Hello{ @Override @RequestMapping(path="/sayhi",method=RequestMethod.POST) public String sayHi(@RequestParam(name="name")String name){ return"Hello"+name; } @Override @RequestMapping(path="/sayhello",method=RequestMethod.POST) public String sayHello(@RequestBody Person person){ return"Helloperson"+person.getName(); } }
RPC 方式訪問上述三種服務的 Consumer
@RpcReference(microserviceName="hello",schemaId="hello") private Hello hello; System.out.println(hello.sayHi("JavaChassis"));
以上代碼片斷所有出自 Apache ServiceComb Samples,有興趣者可閱讀了解或貢獻更多的智慧。
直至此處,或許開發者會產生疑問,既然 Consumer 能夠經過一致的 API 方式訪問不一樣的Provider,爲什麼還須要額外的 JAX-RS 和 Spring MVC 標籤?
緣由是,這裏的設計依據是 Apache ServiceComb的 Consumer考慮的不只限於 類SDK 的 Consumer,還有瀏覽器等非 SDK 類的 Consumer,瀏覽器的 Conumer 識別的是 Http 形式的消息。 經過定義和使用這些標籤, 咱們能夠更加精細的指定瀏覽器如何訪問後臺接口。 相似於 Web Service 的 WSDL 描述語言, Apache ServiceComb 稱之爲服務契約。
服務的契約會在服務運行時經過代碼定義自動生成,並註冊到服務中心。契約也可在運行時用於獨立的服務治理邏輯開發,生成 Consumer 代碼。此外,也可做爲 API 文檔對外發布,供非 SDK 的 Consumer 參考。
微服務強調服務自治,對外體現的功能所有以鬆耦合的接口方式提供,而且只能以通訊的方式實現相互訪問。此原則給團隊協做帶來了根本性的變革。
微服務的一個開發團隊一般由5~6我的的全功能團隊組成,端到端的完成 場景需求分析、架構功能設計、開發和運維,團隊組織結構和業務系統的架構相匹配。團隊創建後的核心問題就是團隊之間如何進行高效的協做溝通,以決定不一樣微服務之間的協做通訊。
Apache ServiceComb 經過確保讓開發人員保持本身的固有編程習慣及設計上的鬆耦合靈活性,讓微服務團隊之間能夠進行高效協做,以免在不一樣的微服務團隊討論編程風格受限於歷史舊帳而浪費寶貴的精力和時間。
在 RPC 的世界裏,有 Corda IDL,WSDL,ProtoBuffer 等能夠參考的優秀實踐, REST 風格的接口讓團隊之間能夠經過 HTTP 語義進行溝通,但卻不能像 IDL 同樣描述跨語言的數據格式。Open API 的出現很好地解決了這個問題。
Open API 首先是一個不斷髮展壯大中的開放的標準。Open API 能兼顧 RPC 、REST 等不一樣的開發方式,而且吸取了大量的跨語言經驗,可以在不一樣的語言之間進行解析。
對於 Java 開發者,下面的代碼片斷是平常所打交道的:
User: type:object properties: age: type:integer
若是開發人員有豐富的跨語言開發經驗,能夠看出 Swagger 在解決跨語言編程方面API定義衝突的努力, 如 Swagger 經過 format 來定義數據類型的存儲格式,以解決不一樣的語言在數據類型表示上的差別:
User: type:object properties: age: type:integer format:int32
開源微服務框架 Apache SerivceComb 既遵循常規開發規範也特別關注開發效率。開發者能夠先寫接口定義後寫代碼, 也可直接經過本身熟悉的方式編寫寫代碼, 兩種方式都會生成 服務契約(Open API 描述文件),而且將內容註冊到服務中心。使用者能夠從服務中心下載相關的服務契約進行開發。 Apache ServiceComb 的各類治理結構也是基於契約的,可讓開發者獨立於業務實現對系統進行統一的管控治理。
開源微服務框架 Apache ServiceComb 早期版本提供了gRPC、REST、SOAP等多種協議,當前主要支持 REST 和Highway 高性能私有 RPC 兩種協議。
gRPC 相對於 REST 的最顯著優勢就是性能,它採用長鏈接、高效的二進制序列化方式,提供多種語言支持, 提供了 IDL 語言約束開發者按照標準的方式工做, 一切看起來是那麼的完美。
實際上,Apache ServiceComb 的第一輪重構,首選也是 gRPC 。歷史第一次在華爲雲 微服務引擎 CSE 上線之後,面對了來自網關壓力挑戰。
網關做爲業務接入端,必須高效的管理鏈接和保證公平,長鏈接容易致使拒絕服務。gRPC 程序開發完成後,開發人員沒法利用系統提供的各類工具進行測試,網絡包分析也變得困難,給生產環境上的開發聯調形成了困難。隨着業務規模的增加,gRPC 面臨了諸如「其餘三方系統如何與之直接通訊? 如何跨網關與它間接通訊?」等更嚴峻的挑戰。
解決這些問題,將須要咱們擴展和改善老的協議和程序,提供 gRPC 客戶端支持,開發者需自行提供一個額外的表示層用於業務接口的邏輯轉換,形成大量的重複代碼。同時因爲 gRPC 依賴於接口定義,並根據定義生成代碼,一套代碼只能跑在 gRPC 協議上,若是用戶但願業務應用可使用如 REST等其餘更加靈活的方式, 就需自行從新實現一套新的代碼邏輯。據以上的血淚史, gRPC 最終被 Apache ServiceComb 設計團隊定義爲只能在中小型系統內部之間使用,並經過協議網關與外部系統進行通訊。並實現了 高性能私有協議 Highway 做爲RPC首選默認協議。
REST 相較 gRPC ,最大的痛點是性能。
多數技術人員腦海裏一個不成文的根深蒂固的觀點:」二進制編碼效率遠高於文本協議,採用二進制編碼的系統的性能遠高於採用文本的 HTTP 」。該觀點甚至會讓多數決策止步於理論,多數人甚至不肯嘗試去優化 REST。
可喜的是 開源微服務框架 Apache ServiceComb 邁出了重構 REST 底層通訊實現的第一步,基於 Netty 的異步框架來替換 Tomcat 實現,實踐的效果大大超出預期,部分基準測試數據結果顯示比 gRPC 還好, gRPC最終輸在了HTTP2 協議上的額外報文。
優化後的 REST 和業界開源的其餘基於二進制的 RPC 實現的性能基本持平。在一個簡單的提供數據庫查詢的代碼邏輯中,優化後的REST通訊框架處理時間,佔比總處理時間遠小於千分之一,這意味着再繼續在框架層面進行大量優化也抵不上業務應用層面最簡單的一個操做帶來的消耗,Apache ServiceComb對 REST 的優化已經知足要求,最終也選擇了 REST 做爲首選和缺省協議(HTTP + json)。
咱們並無就此止步。
須要遷移到 華爲雲 微服務引擎 CSE 的業務日益增加,部分歷史遺留系統也需進行對接。通訊協議對應不一樣的開發者接口,往往增長通訊協議,則須要對業務代碼進行大量的重複構建,形成大量無謂消耗。這是當時的華爲雲化轉型以及當下不少雲化轉型企業或者雲原生企業必將面臨的痛點。
因而乎,通訊協議層被剝離了出來,和業務代碼隔離,系統運行基於契約,開源微服務框架 Apache ServiceComb 實現通訊協議擴展機制。通訊協議擴展機制,幫助用戶解決與 gRPC 框架、自定義二進制框架等許多遺留系統的對接通訊問題。
在 Apache ServiceComb 框架中,切換協議很是簡單,不須要修改一行業務代碼。多個協議共存也是容許的。
ServiceComb: rest: address:0.0.0.0:8084 highway: address:0.0.0.0:8094
擴展性是系統進一步發展的基石。開源微服務框架 Apache ServiceComb 創造性地將擴展性拓展到 Provider 和 Consumer,讓開發者擁有一致的開發體驗。
鏈接開發者和通訊協議層面已經讓系統具有了很大的擴展性。微服務化給系統解耦、團隊自治帶來了很大的靈活性,加快了開發生產效率,但同時帶來了服務管控的複雜性,在微服務領域,不得不考慮雪崩效應、調用跟蹤、性能監控與分析等實際管控治理問題。
基於服務契約,開源微服務框架 Apache ServiceComb 提供了動態插拔擴展的處理鏈機制,而且爲這些管控治理能力提供了默認實現,用戶能夠靈活插拔這些處理模塊,或調整它們的順序以應對不一樣的處理場景,或自行實現以增長新的處理模塊。Provider 和 Consumer 都會通過該處理鏈,這給客戶端治理功能開發帶來了極大的便利性。Apache ServiceComb 的運行結構以下:
圖1 Apache ServiceComb 運行時架構
Apache ServiceComb 同時支持同步和異步兩種編程接口,並在通訊實現上採用了純異步方式,對於運行模型的擴展,也是基於異步回調接口的。該方式提供了比同步模式(好比 Filter)更加優雅靈活的擴展方式。
在Apache ServiceComb 結構中,幾個核心的擴展機制均在 core 模塊 進行定義:
Provider 編程模型的擴展,經過實現這個接口,能夠適配不一樣的 Provider編 程風格;默認支持 RPC、Spring MVC 和 JAX-RS 三種風格。
Consumer 編程模型的擴展,經過實現這個接口,能夠適配不一樣的 Consumer 編程風格;默認支持 RPC和RestTemplate 兩種風格。RestTemplate 是 Spring MVC 提供的 REST 編程接口,能夠在服務層解除接口依賴,只依賴數據模型。
處理鏈的接口,經過擴展該接口,能夠在處理過程當中插入任意的邏輯。默認已經支持負載均衡、錯誤注入、流量控制和調用鏈跟蹤等多個處理鏈。開發者能夠針對 Consumer 和 Provider 定義不一樣的處理鏈,而且爲訪問不一樣的微服務定製不一樣的處理鏈。
通訊協議擴展,默認支持REST over Vertx、Rest over Servlet、Highway協議。
Invocation
中立的對象。全部的運行模型都面向這個中立的對象進行編程,當定義好服務接口後,對服務的治理和服務業務邏輯的開發可並行進行。在編程模型和通訊模型裏面,也面向這個對象進行編解碼。
Apache ServiceComb Java-chassis 預留了對接外部系統的接口,以讓開發者或用戶能夠靈活快速切換使用第三方提供的服務,這裏所指的外部系統包括但不限於:服務註冊發現的服務中心、配置管控和治理的配置中心、運行監控和運維的治理中心等。
下圖展現了不一樣的開發框架支持和運行的第三方系統狀況,這些基礎服務都給開發者預留了能夠進行支持接入的接口。
圖2 Apache ServiceComb 外部擴展接入
重要的擴展:
實現這個接口以對接不一樣的註冊服務。
ConfigCenterConfigurationSource
實現這個接口以對接不一樣的配置服務。
此外,ServiceComb還提供了對接Zipkin、Servo等開源系統的功能,這些能夠從github代碼中查找到對應的例子。
一個完整的業務系統不是使用RPC框架就算完成了,它們還須要其餘的計算資源。對於通常的業務系統都須要訪問數據庫,或者基於 J2EE 的設施進行工做。
開源微服務框架 Apache ServiceComb 能夠以輕量級的方式運行,也可集成到其餘系統框架。下面的示意圖說明了 Apache ServiceComb 的一些工做環境。
圖3 Apache ServiceComb 運行環境集成
因爲 Apache ServiceComb 使用了Spring,所以自然繼承了Spring的原有優點,可和不少通用的組件很好的集成,如 mybatis、JPA 等。各類集成方式,均可以從ServiceComb官網或者ServiceComb 示例庫找到對應的例子。
開源微服務框架 Apache ServiceComb 的主體代碼是由華爲雲微服務引擎捐贈給 Apache 軟件基金會的,願景是幫助企業快速構建雲原生應用,經過一系列解決方案幫助用戶快速開發微服務應用的同時實現對這些微服務應用的高效運維管理。本次設計團隊將開放性設計部分細節點點滴滴分享出來也是爲了可以對解放微服務開發者和用戶能有所幫助。
當前愈來愈多的貢獻者已加入到 社區行列,Apache ServiceComb 會和這些志願者們一塊兒一如既往堅持這個理念,爭取給業界帶來更多好的技術和分享。也指望有更多有志者一塊兒行動。
參考文獻
[1] 開源微服務框架 Apache ServiceComb 官網
http://servicecomb.incubator.apache.org/cn/
[2] 開源微服務框架 Apache ServiceComb 代碼
https://github.com/apache/incubator-servicecomb-java-chassis
https://github.com/apache/incubator-servicecomb-service-center
https://github.com/apache/incubator-servicecomb-saga
[3] 華爲雲微服務引擎 CSE(Cloud Service Engine)
入口 https://www.huaweicloud.com/product/cse.html
資料 http://support.huaweicloud.com/cse_dld/index.html
[4] Apahce ServiceComb OSC 碼雲地址