ServiceComb开放性设计
和很多微服務(wù)開(kāi)發(fā)框架類(lèi)似,ServiceComb的早期版本,為了追求高性能,做過(guò)非常多的嘗試,比如改善編碼效率,改進(jìn)通信協(xié)議等。隨著業(yè)務(wù)規(guī)模的遞增,問(wèn)題隨之而來(lái)。首先面對(duì)的是和遺留系統(tǒng)的通信,接著是各種不同的接入終端,然后就涉及到一些更加復(fù)雜的問(wèn)題,協(xié)議健壯性、防攻擊等。ServiceComb準(zhǔn)備開(kāi)源的前期,用戶對(duì)于與業(yè)界其他開(kāi)源組件和開(kāi)發(fā)框架的集成的述求又源源的涌來(lái)。在這些問(wèn)題的驅(qū)動(dòng)下,ServiceComb設(shè)計(jì)團(tuán)隊(duì)慢慢的達(dá)成了共識(shí),系統(tǒng)應(yīng)該全開(kāi)放,使用標(biāo)準(zhǔn)協(xié)議,容易拆分和擴(kuò)展,對(duì)開(kāi)發(fā)人員友好,并和業(yè)界其他系統(tǒng)良好集成。本文將分享這些方面的設(shè)計(jì)考慮。????
開(kāi)放和標(biāo)準(zhǔn)
開(kāi)放和標(biāo)準(zhǔn)應(yīng)用到設(shè)計(jì)的不同的層面。一方面是連接組織和開(kāi)發(fā)人員,一方面是連接異構(gòu)系統(tǒng)。組織和開(kāi)發(fā)人員的復(fù)雜性來(lái)源于技能的多樣性,大家使用不同的開(kāi)發(fā)語(yǔ)言,同一種開(kāi)發(fā)語(yǔ)言存在多樣的開(kāi)發(fā)習(xí)慣;系統(tǒng)的多樣性來(lái)源于系統(tǒng)之間的通信協(xié)議,為了實(shí)現(xiàn)與異構(gòu)系統(tǒng)的通信,必須具備良好的適配不同通信協(xié)議的能力。
連接組織和開(kāi)發(fā)人員
l??代碼風(fēng)格
每個(gè)開(kāi)發(fā)人員都有自己熟練的技術(shù)和寫(xiě)代碼的方式,使用熟悉的方式寫(xiě)代碼往往更加高效。ServiceComb的早期版本實(shí)現(xiàn)了gRPC協(xié)議,推廣的過(guò)程中發(fā)現(xiàn)大量開(kāi)發(fā)人員不能熟練的書(shū)寫(xiě)IDL,對(duì)IDL支持哪些特性不清楚,碰到一個(gè)場(chǎng)景就需要翻開(kāi)協(xié)議規(guī)范看一遍。加上接口語(yǔ)言一般缺少配套的編輯和語(yǔ)法檢查工具,開(kāi)發(fā)效率非常低。如果開(kāi)發(fā)人員能夠以熟悉的開(kāi)發(fā)方式馬上開(kāi)始工作,將是一件美妙的事情,新進(jìn)來(lái)的人沒(méi)門(mén)檻,老系統(tǒng)也能快速切過(guò)來(lái),一舉兩得。在JAVA世界里開(kāi)發(fā)框架不勝枚舉,我們從這些方式中找到了很多的共性,能夠涵蓋到90%以上的習(xí)慣:1.?使用RPC的方式描述對(duì)外接口。這個(gè)在gRPC、Corba、WebService等開(kāi)發(fā)人員面前非常熟悉,?是最直接和有效的寫(xiě)代碼方式;?2.?使用JAX-RS或者Spring MVC風(fēng)格開(kāi)發(fā)REST接口。REST風(fēng)格開(kāi)發(fā)隨著微服務(wù)架構(gòu)興起,JAX-RS是JAVA REST開(kāi)發(fā)標(biāo)準(zhǔn),Spring MVC是JAVA開(kāi)發(fā)的事實(shí)標(biāo)準(zhǔn),Spring擁護(hù)者很熟悉。? ServiceComb選擇這幾種缺省的開(kāi)發(fā)風(fēng)格,擁抱90%的開(kāi)發(fā)者,讓大家能夠快速開(kāi)始工作。???
在下面的例子中,呈現(xiàn)了Provider和Consumer代碼的各種實(shí)現(xiàn),在同一個(gè)微服務(wù)中,這些呈現(xiàn)方式可以同時(shí)出現(xiàn);同一段Consumer代碼,可以訪問(wèn)各種不同的Provider實(shí)現(xiàn),非常靈活。
代碼:RPC形式的Provider.
@RpcSchema(schemaId???=?"hello") public?class???HelloImpl?implements?Hello?{@Overridepublic?String?sayHi(String?name)?{return?"Hello?"?+?name;}@Overridepublic?String?sayHello(Person?person)?{return?"Hello?person?"?+???person.getName();} }代碼:JAX-RS形式的Provider.
?
@RestSchema(schemaId???=?"jaxrsHello") @Path("/jaxrshello") @Produces(MediaType.APPLICATION_JSON) public?class???JaxrsHelloImpl?implements?Hello?{@Path("/sayhi")@POST@Overridepublic?String?sayHi(String?name)?{return?"Hello?"?+?name;}@Path("/sayhello")@POST@Overridepublic?String?sayHello(Person?person)?{return?"Hello?person?"?+???person.getName();} }代碼:Spring MVC形式的Provider.
?
@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?"Hello?person?"?+???person.getName();} }代碼:RPC方式訪問(wèn)上述三種服務(wù)的Consumer.
?
@RpcReference(microserviceName???=?"hello",?schemaId?=?"hello") private?Hello???hello; System.out.println(hello.sayHi("Java???Chassis"));看到這里,開(kāi)發(fā)者或者有個(gè)疑問(wèn),Consumer既然可以通過(guò)一致的API方式訪問(wèn)不同的Provider,為什么還需要額外的JAX-RS和SpringMVC標(biāo)簽了?這里的主要考量并不僅僅是SDK的Consumer,還有瀏覽器等非SDK的Consumer,他們識(shí)別的是HTTP形式的消息,通過(guò)這些標(biāo)簽,可以更加精細(xì)的指定瀏覽器如何訪問(wèn)后臺(tái)接口。這一點(diǎn)非常類(lèi)似于Web Service的WSDL描述語(yǔ)言,ServiceComb稱(chēng)之為契約。服務(wù)契約會(huì)在運(yùn)行時(shí)通過(guò)代碼定義生成,并注冊(cè)到服務(wù)中心。契約在運(yùn)行時(shí)可以用于獨(dú)立的服務(wù)治理邏輯開(kāi)發(fā),生成Consumer代碼。也可以作為文檔對(duì)外發(fā)布,供非SDK的Consumer參考。
l??契約
微服務(wù)強(qiáng)調(diào)服務(wù)自治,對(duì)外體現(xiàn)的功能,全部以接口提供,而且只能以通信的方式相互訪問(wèn)。這個(gè)原則給團(tuán)隊(duì)協(xié)作帶來(lái)了根本的變革,一個(gè)團(tuán)隊(duì)通常由5~6個(gè)人的全功能團(tuán)隊(duì)組成,端到端的完成功能設(shè)計(jì)、開(kāi)發(fā)和運(yùn)維,系統(tǒng)的結(jié)構(gòu)和組織的結(jié)構(gòu)是匹配的。小團(tuán)隊(duì)以后的核心問(wèn)題就是團(tuán)隊(duì)之間如何進(jìn)行高效的溝通。為了更好的連接開(kāi)發(fā)人員,我們讓不同的開(kāi)發(fā)人員能夠使用自己熟悉的語(yǔ)言和編程習(xí)慣寫(xiě)代碼,這樣就需要一種中立的機(jī)制讓每個(gè)功能團(tuán)隊(duì)進(jìn)行有效協(xié)作。在RPC的世界里,有Corda IDL,WSDL,ProtoBuffer等可以參考的優(yōu)秀實(shí)踐。REST風(fēng)格的接口讓團(tuán)隊(duì)成員之間可以通過(guò)HTTP的語(yǔ)義進(jìn)行溝通,但是不能像IDL一樣描述跨語(yǔ)言時(shí)的數(shù)據(jù)格式。Open API的出現(xiàn)很好的解決了這些問(wèn)題。Open API首先是一個(gè)開(kāi)放的標(biāo)準(zhǔn),并且在不斷的發(fā)展壯大。Open API對(duì)于RPC、REST等不同的開(kāi)發(fā)方式都完整的兼顧到了,并且吸收了大量的跨語(yǔ)言經(jīng)驗(yàn),能夠在不同的語(yǔ)言之間解析。?對(duì)于JAVA開(kāi)發(fā)者,下面的類(lèi)型定義已經(jīng)是毫無(wú)疑問(wèn)的:
?
User:type:?objectproperties:age:type:?integer如果開(kāi)發(fā)人員有豐富的跨語(yǔ)言開(kāi)發(fā)經(jīng)驗(yàn),可以看出Swagger在解決跨語(yǔ)言編程方面的努力,swagger通過(guò)format來(lái)定義數(shù)據(jù)類(lèi)型的存儲(chǔ)格式,以解決不同的語(yǔ)言在數(shù)據(jù)類(lèi)型表示上的差異:
?
User:type:?objectproperties:age:type:?integerformat:?int32SerivceComb兼顧開(kāi)發(fā)效率和開(kāi)發(fā)規(guī)范。開(kāi)發(fā)者可以先寫(xiě)接口定義,再寫(xiě)代碼的方式來(lái)完成自己的開(kāi)發(fā)過(guò)程,也可以直接通過(guò)自己熟悉的方式寫(xiě)代碼。兩種方式都會(huì)生成服務(wù)的契約(Open API描述文件),并且將內(nèi)容注冊(cè)到服務(wù)中心。使用者可以從服務(wù)中心下載相關(guān)的契約進(jìn)行開(kāi)發(fā)。ServiceComb的各種治理結(jié)構(gòu)也是基于契約的,可以讓開(kāi)發(fā)者獨(dú)立于業(yè)務(wù)實(shí)現(xiàn)對(duì)系統(tǒng)進(jìn)行統(tǒng)一的管控。
連接異構(gòu)系統(tǒng)
ServiceComb早期版本提供了gRPC、REST、SOAP等多種協(xié)議。gRPC相對(duì)于REST的最大好處就是性能,采用長(zhǎng)連接,高效的二進(jìn)制序列化方式,并提供多種語(yǔ)言支持。在接口定義方面,提供了IDL語(yǔ)言約束開(kāi)發(fā)者按照標(biāo)準(zhǔn)的方式工作。一切看起來(lái)是那么的完美,實(shí)際上ServiceComb的第一輪重構(gòu),首選的也是gRPC的方式。系統(tǒng)上線以后,首要的問(wèn)題來(lái)源于網(wǎng)關(guān)的壓力。網(wǎng)關(guān)作為所有業(yè)務(wù)的接入端,必須高效的管理連接和保證公平,長(zhǎng)連接非常容易導(dǎo)致拒絕服務(wù)。gRPC程序開(kāi)發(fā)完成后,開(kāi)發(fā)聯(lián)調(diào)也變得不方便起來(lái),特別是生產(chǎn)環(huán)境。開(kāi)發(fā)人員無(wú)法利用系統(tǒng)提供的各種工具進(jìn)行測(cè)試,網(wǎng)絡(luò)包分析也變得困難。隨著系統(tǒng)規(guī)模的擴(kuò)大,gRPC再次面對(duì)更加嚴(yán)峻的問(wèn)題,其他系統(tǒng)如何與它直接通信,如何跨網(wǎng)關(guān)與它間接通信,解決這些問(wèn)題,意味著我們需要擴(kuò)展和改善老的協(xié)議和程序,提供gRPC客戶端支持,開(kāi)發(fā)者需要提供一個(gè)額外的表示層用于業(yè)務(wù)接口的邏輯轉(zhuǎn)換,造成大量的重復(fù)代碼。同時(shí)由于gRPC依賴于接口定義,并根據(jù)定義生成代碼,一套代碼只能跑在gRPC協(xié)議上,希望業(yè)務(wù)代碼使用其他更加靈活的方式,比如REST訪問(wèn)的時(shí)候,就得重新寫(xiě)一套代碼。面對(duì)以上問(wèn)題,gRPC在選擇上,最終被定義為只能在中小型系統(tǒng)內(nèi)部之間使用,并通過(guò)協(xié)議網(wǎng)關(guān)與外部系統(tǒng)進(jìn)行溝通。???
接著就是REST了。業(yè)界可用的REST實(shí)現(xiàn),和gRPC比較起來(lái),最大的痛點(diǎn)就是性能。有一個(gè)觀點(diǎn)在很多設(shè)計(jì)人員和開(kāi)發(fā)人員腦海里根深蒂固:”二進(jìn)制編碼效率遠(yuǎn)高于文本協(xié)議,采用二進(jìn)制編碼的系統(tǒng)的性能遠(yuǎn)高于采用文本的HTTP”。這個(gè)觀點(diǎn)甚至?xí)尪鄶?shù)決策止步于理論,大家甚至不愿意嘗試去優(yōu)化REST。可喜的是ServiceComb走出了重構(gòu)REST底層通信實(shí)現(xiàn)的第一步,基于Netty的異步框架來(lái)替換Tomcat實(shí)現(xiàn),效果大大超出我們的預(yù)期。一些基準(zhǔn)測(cè)試數(shù)據(jù)的結(jié)果顯示比gRPC還要好,gRPC最終輸在了HTTP2協(xié)議上的額外報(bào)文。同時(shí)優(yōu)化后的REST和業(yè)界開(kāi)源的其他基于二進(jìn)制的RPC實(shí)現(xiàn)的性能也基本持平,只有微小的差異。在一個(gè)簡(jiǎn)單的提供數(shù)據(jù)庫(kù)查詢的代碼邏輯中,REST通信框架處理時(shí)間,占用總的處理時(shí)間遠(yuǎn)小于千分之一。這意味著在系統(tǒng)框架層面的大量?jī)?yōu)化,抵不上業(yè)務(wù)系統(tǒng)最簡(jiǎn)單的一筆操作,為了優(yōu)化性能放棄的其他好處就不值得了。最終,ServiceComb選擇了REST作為首選和缺省協(xié)議(http + json)。
使用REST也存在和其他系統(tǒng)對(duì)接,通過(guò)網(wǎng)關(guān)對(duì)接的場(chǎng)景,但是問(wèn)題已經(jīng)好了很多。
但是我們遠(yuǎn)沒(méi)有止步于此。隨著需要遷移到系統(tǒng)平臺(tái)的服務(wù)越來(lái)越多,早期的一些遺留系統(tǒng)也需要進(jìn)行對(duì)接。我們提供的每一種通信協(xié)議,都對(duì)應(yīng)著不同的開(kāi)發(fā)者接口,增加通信協(xié)議,意味著需要對(duì)業(yè)務(wù)代碼進(jìn)行大量的重復(fù)構(gòu)建。為了進(jìn)一步滿足更多的場(chǎng)景,通信協(xié)議層被剝離了出來(lái),做到和業(yè)務(wù)代碼分離,系統(tǒng)運(yùn)行基于契約,實(shí)現(xiàn)通信協(xié)議的擴(kuò)展。利用協(xié)議擴(kuò)展機(jī)制,用戶解決了與老的gRPC框架、自定義二進(jìn)制框架等很多遺留系統(tǒng)的通信問(wèn)題。??????
在ServiceComb框架中,切換協(xié)議非常簡(jiǎn)單,不需要修改一行業(yè)務(wù)代碼。多個(gè)協(xié)議共存也是允許的。
?
cse:rest:address:?0.0.0.0:8084highway:address:?0.0.0.0:8094關(guān)于協(xié)議擴(kuò)展的更多內(nèi)容,將在下面的章節(jié)進(jìn)行介紹。
擴(kuò)展性
擴(kuò)展性是系統(tǒng)進(jìn)一步發(fā)展的基石。ServiceComb創(chuàng)造性的將擴(kuò)展性拓展到Provider和Consumer,讓它們擁有一致的開(kāi)發(fā)體驗(yàn)。這個(gè)在現(xiàn)有的各種開(kāi)發(fā)框架里面是獨(dú)有的。
內(nèi)部系統(tǒng)結(jié)構(gòu)
連接開(kāi)發(fā)者和通信協(xié)議層面已經(jīng)讓系統(tǒng)具備了很大的擴(kuò)展性。微服務(wù)化給系統(tǒng)解耦、團(tuán)隊(duì)自治帶來(lái)了很大的靈活性,加快了生產(chǎn)效率;同時(shí)也帶來(lái)了服務(wù)管控的復(fù)雜性。需要用通用的管控機(jī)制來(lái)解決雪崩效應(yīng)、調(diào)用跟蹤、性能監(jiān)控與分析等問(wèn)題。基于服務(wù)契約,ServiceComb提供了動(dòng)態(tài)插拔擴(kuò)展的處理鏈機(jī)制,并且為應(yīng)對(duì)這些管控,提供了默認(rèn)實(shí)現(xiàn),開(kāi)發(fā)者可以靈活插拔這些處理模塊,或者調(diào)整他們的順序以應(yīng)對(duì)不同的處理場(chǎng)景,增加新的處理模塊等。不管Provider,還是Consumer,都會(huì)經(jīng)過(guò)該處理鏈,這給客戶端治理功能開(kāi)發(fā)帶來(lái)了非常大的便利,這是其他現(xiàn)有的微服務(wù)框架不具備的特性。ServiceComb的運(yùn)行結(jié)構(gòu)如下圖:
?
ServiceComb在用戶編程接口上,支持同步和異步兩種方式。在通信實(shí)現(xiàn)上,采用了純異步的方式,對(duì)于運(yùn)行模型的擴(kuò)展,也是基于異步回調(diào)接口的。這種方式提供了比同步模式(比如Filter)更加優(yōu)雅和靈活的擴(kuò)展方式。
在這個(gè)系統(tǒng)結(jié)構(gòu)中,有幾個(gè)核心的接口,這些接口均在core模塊進(jìn)行定義:
ProducerProvider:Provider編程模型的擴(kuò)展,通過(guò)實(shí)現(xiàn)這個(gè)接口,可以適配不同的Provider編程風(fēng)格;目前實(shí)現(xiàn)了RPC、SpringMVC、JAX-RS三種風(fēng)格。
ConsumerProvider:Consumer編程模型的擴(kuò)展,通過(guò)實(shí)現(xiàn)這個(gè)接口,可以適配不同的Consumer編程風(fēng)格;目前實(shí)現(xiàn)了RPC、RestTemplate兩種風(fēng)格。RestTemplate是Spring MVC提供了REST編程接口,可以在服務(wù)層方面解除接口依賴,只需要依賴數(shù)據(jù)模型。
Handler:處理鏈的接口。通過(guò)擴(kuò)展該接口,可以在處理過(guò)程中插入任意的邏輯。目前實(shí)現(xiàn)了負(fù)載均衡、服務(wù)治理、流量控制等多個(gè)處理鏈。開(kāi)發(fā)者可以針對(duì)Consumer和Provider定義不同的處理鏈,并且為訪問(wèn)不同的微服務(wù)定制不同的處理鏈。
Transport:通信協(xié)議擴(kuò)展。目前實(shí)現(xiàn)了REST over Vertx,Rest over Servlet,Highway等多個(gè)協(xié)議。
Invocation:中立的對(duì)象。所有的運(yùn)行模型都面對(duì)這個(gè)中立的對(duì)象進(jìn)行編程,當(dāng)定義好服務(wù)接口后,對(duì)服務(wù)的治理和服務(wù)業(yè)務(wù)邏輯的開(kāi)發(fā)可以并行。在編程模型和通信模型里面,也面對(duì)這個(gè)模型進(jìn)行編解碼。
對(duì)接外部系統(tǒng)
運(yùn)行框架涉及到的外部系統(tǒng)包括服務(wù)注冊(cè)發(fā)現(xiàn)的服務(wù)中心、配置管控和治理的配置中心、運(yùn)行監(jiān)控和運(yùn)維的治理中心等。這些功能也預(yù)留了接口,能夠讓開(kāi)發(fā)者靈活切換使用第三方提供的服務(wù)。?下圖是不同的開(kāi)發(fā)框架支持和運(yùn)行的第三方系統(tǒng)情況,這些基礎(chǔ)服務(wù)都給開(kāi)發(fā)者預(yù)留了可以進(jìn)行支持接入的接口。
?
下面是幾個(gè)重要的擴(kuò)展:
ServiceRegistryClient:?實(shí)現(xiàn)這個(gè)接口以對(duì)接不同的注冊(cè)服務(wù)。
ConfigCenterConfigurationSource:?實(shí)現(xiàn)這個(gè)接口以對(duì)接不同的配置服務(wù)。
此外,ServiceComb還提供了對(duì)接Zipkin、Servo等開(kāi)源系統(tǒng)的功能,這些可以從github官網(wǎng)代碼中查找到對(duì)應(yīng)的例子。
運(yùn)行環(huán)境集成
一個(gè)完整的業(yè)務(wù)系統(tǒng)不是使用RPC框架就算完成了,它們還需要其他的計(jì)算資源。對(duì)于一般的業(yè)務(wù)系統(tǒng)都需要訪問(wèn)數(shù)據(jù)庫(kù),或者基于J2EE的設(shè)施進(jìn)行工作。ServiceComb可以以非常輕量級(jí)的方式運(yùn)行,也可以集成到其他系統(tǒng)框架里面工作。下面的示意圖說(shuō)明了ServiceComb的一些工作環(huán)境。
?
如果業(yè)務(wù)只需要提供REST接口,可以以輕量級(jí)的方式運(yùn)行ServiceComb。所有的REST接口運(yùn)行于ServiceComb提供的Netty HTTP之上。
如果業(yè)務(wù)是基于J2EE來(lái)構(gòu)建,那么ServiceComb可以作為一個(gè)Servlet,運(yùn)行于WEB容器里面(比如Tomcat、Jetty等)。
如果業(yè)務(wù)要基于Spring Boot生態(tài)構(gòu)建,ServiceComb可以作為一個(gè)starter對(duì)外提供REST服務(wù),開(kāi)發(fā)者可以自由使用其他基于Spring Boot的功能。
由于ServiceComb使用了Spring,因此也能夠和很多通用的組件很好的集成,比如mybatis、JPA等。各種集成方式,都可以從ServiceComb官網(wǎng)或者CSE示例庫(kù)找到對(duì)應(yīng)的例子。
總結(jié)
本文簡(jiǎn)單的介紹了一下ServiceComb開(kāi)發(fā)框架開(kāi)發(fā)性設(shè)計(jì)的一些考慮。除了這些特性之外,ServicComb還提供了Edge Service網(wǎng)關(guān)服務(wù)、Saga分布式事務(wù)等特性。
參考文獻(xiàn):
1. ServiceComb官網(wǎng)包括源碼:https://github.com/apache/incubator-servicecomb-java-chassis和文檔資料:http://servicecomb.incubator.apache.org/
2.?華為云使用ServiceComb作為首選微服務(wù)開(kāi)發(fā)框架,商用支持參考幫助網(wǎng)站:http://support.huaweicloud.com/cse_dld/index.html?和資料的Preview版本:https://java.huaweicse.com/
【版權(quán)聲明】本文為華為云社區(qū)用戶原創(chuàng)內(nèi)容,轉(zhuǎn)載時(shí)必須標(biāo)注文章的來(lái)源(華為云社區(qū)),文章鏈接,文章作者等基本信息,否則作者和本社區(qū)有權(quán)追究責(zé)任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,歡迎發(fā)送郵件至:huaweicloud.bbs@huawei.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),本社區(qū)將立刻刪除涉嫌侵權(quán)內(nèi)容。轉(zhuǎn)載于:https://www.cnblogs.com/Bkxk/p/10382938.html
總結(jié)
以上是生活随笔為你收集整理的ServiceComb开放性设计的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 极限编程阅读笔记--第二篇
- 下一篇: sqlalchemy 基操,勿6