郭致遠(yuǎn),魏銀珍,
(1.武漢郵電科學(xué)研究院,湖北 武漢 430074;2.武漢大學(xué) 信息管理學(xué)院,湖北 武漢 430074)
隨著互聯(lián)網(wǎng)的不斷發(fā)展,面對(duì)用戶量急速增長(zhǎng)和日益頻繁的需求改動(dòng),傳統(tǒng)的單體應(yīng)用架構(gòu)已經(jīng)難以支撐現(xiàn)有的業(yè)務(wù)體系,于是分布式應(yīng)用架構(gòu)[1]的出現(xiàn)為開發(fā)者提供了一種新思路。微服務(wù)[2]作為一種顆粒度更小的分布式架構(gòu),其思想是通過將一個(gè)系統(tǒng)按某種規(guī)則劃分為多個(gè)功能單一的小型服務(wù),這些服務(wù)運(yùn)行在彼此的進(jìn)程中,服務(wù)之間采用輕量級(jí)通信協(xié)議通信,從而實(shí)現(xiàn)系統(tǒng)功能[3]。微服務(wù)架構(gòu)所面臨的首要問題是如何實(shí)現(xiàn)服務(wù)間的遠(yuǎn)程調(diào)用(Remote Process Call,RPC)[4]。目前實(shí)現(xiàn)RPC主要有兩種方案:基于HTTP和基于TCP協(xié)議實(shí)現(xiàn)。后者的實(shí)現(xiàn)細(xì)節(jié)相對(duì)復(fù)雜,而基于HTTP協(xié)議的應(yīng)用相對(duì)更加廣泛。本文設(shè)計(jì)的服務(wù)調(diào)用框架Spring Cloud Feign基于Netflix組件開發(fā),是一款聲明式、模板化的HTTP客戶端,并且針對(duì)于眾多Spring用戶,Spring Cloud Feign支持Spring MVC[5]注解,使得Feign的使用更加方便。
RPC是一種進(jìn)程間的通信方式,根據(jù)協(xié)議的不同有多種實(shí)現(xiàn)方式,其目的主要是通過屏蔽底層傳輸和序列化的實(shí)現(xiàn)細(xì)節(jié)來簡(jiǎn)化遠(yuǎn)程服務(wù)過程調(diào)用。
RPC框架的調(diào)用原理圖如圖1所示。
圖1 RPC框架原理圖
總結(jié)實(shí)現(xiàn)RPC框架的幾個(gè)核心點(diǎn)如下:
(1)服務(wù)提供方需要以某種形式向調(diào)用方提供調(diào)用相關(guān)信息,如服務(wù)接口、數(shù)據(jù)結(jié)構(gòu)、接口說明文檔等相關(guān)服務(wù)調(diào)用信息。
(2)服務(wù)代理對(duì)象。服務(wù)調(diào)用者調(diào)用遠(yuǎn)程服務(wù)實(shí)際上是通過遠(yuǎn)程服務(wù)的本地代理實(shí)現(xiàn),如Java的JDK動(dòng)態(tài)代理將本地調(diào)用封裝為遠(yuǎn)程調(diào)用。
(3)通信。無論是采用私有二進(jìn)制協(xié)議還是HTTP,只要能實(shí)現(xiàn)進(jìn)程間通信即可。
(4)序列化。遠(yuǎn)程通信需要將對(duì)象轉(zhuǎn)換成二進(jìn)制碼流才能進(jìn)行網(wǎng)絡(luò)傳輸,同時(shí)不同的序列化技術(shù)支持的數(shù)據(jù)類型、數(shù)據(jù)包大小、異常處理等都有很大差別。
目前開源的RPC框架有很多,業(yè)界主流的幾種框架如下:
(1)Apache Thrift。Apache Thrift是由Facebook實(shí)現(xiàn)的一種支持多語言的高效服務(wù)調(diào)用框架,其特點(diǎn)是支持二進(jìn)制和JSON編碼的數(shù)據(jù)傳輸協(xié)議,對(duì)于高并發(fā)、大數(shù)據(jù)量的開發(fā)環(huán)境更合適。
(2)gRPC。這是Google基于HTTP/2協(xié)議開發(fā)的一個(gè)高性能的開源框架,相對(duì)于HTTP/1具有提供頭部壓縮、雙向流等多種特性,從而在移動(dòng)設(shè)備上有更出色的表現(xiàn)。
(3)Hessian。其是由Caucho Technology開發(fā)的一款輕量級(jí)RPC框架,它的遠(yuǎn)程過程調(diào)用基于動(dòng)態(tài)代理實(shí)現(xiàn),因此具備簡(jiǎn)單易用、支持多語言、面向接口編程等特點(diǎn)。
面對(duì)市面上眾多主流RPC架構(gòu),基于Spring Cloud開發(fā)的Feign在許多方面有著不俗的表現(xiàn),總結(jié)如下:
(1)支持多語言。Feign基于Spring Cloud實(shí)現(xiàn),因此不同的模塊可以使用不同的語言開發(fā),可更好地實(shí)現(xiàn)跨平臺(tái)。
(2)與Spring框架兼容性更好。Feign本身屬于Spring框架的一部分,同時(shí)Spring Cloud對(duì)Feign的加強(qiáng)使得Feign支持Spring MVC注解,因此對(duì)于多數(shù)Spring開發(fā)者是更好的選擇。
(3)聲明式服務(wù)調(diào)用。由于Feign基于HTTP協(xié)議實(shí)現(xiàn),因此可以更好地形成RESTful接口風(fēng)格,從而以更簡(jiǎn)潔明了兼具可讀性的方式實(shí)現(xiàn)服務(wù)間的調(diào)用。
在實(shí)際開發(fā)中,使用Feign作為遠(yuǎn)程服務(wù)調(diào)用框架所帶來的好處還有很多,相比大型企業(yè)根據(jù)其自身業(yè)務(wù)定制的開源服務(wù)調(diào)用框架,F(xiàn)eign對(duì)于多數(shù)中小企業(yè)也許是更好的選擇。
Feign基于Netflix Feign實(shí)現(xiàn),整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供這兩者的強(qiáng)大功能之外還提供了一種聲明式的Web服務(wù)客戶端定義方式[6]。在實(shí)際的開發(fā)過程中存在一個(gè)接口被多個(gè)服務(wù)調(diào)用的情況,通常的做法是針對(duì)各個(gè)微服務(wù)自行封裝一些客戶端類來包裝這些依賴服務(wù)的調(diào)用。由于Feign底層對(duì)Ribbon和Eureka進(jìn)行了封裝,使得Feign可以實(shí)現(xiàn)以下多種功能[7]:
(1)繼承:將接口中的定義從Controller剝離,配合Maven[8]私有倉庫實(shí)現(xiàn)接口共享,在代碼構(gòu)建期實(shí)現(xiàn)接口綁定從而減少客戶端接口綁定。
(2)負(fù)載均衡:由于Feign是基于Spring Cloud Ribbon實(shí)現(xiàn)的,因此可以通過自定義Ribbon參數(shù)來實(shí)現(xiàn)客戶端的負(fù)載均衡。
(3)重試機(jī)制:Feign默認(rèn)實(shí)現(xiàn)了請(qǐng)求的重試機(jī)制,使得客戶端在進(jìn)行服務(wù)調(diào)用時(shí)如果出現(xiàn)失敗,可以重復(fù)請(qǐng)求。Feign對(duì)于重試機(jī)制的支持對(duì)于實(shí)現(xiàn)高可用服務(wù)集群有重要意義。
(4)服務(wù)保護(hù)與容錯(cuò):Feign通過引入Spring Cloud Hystrix工具提供服務(wù)的保護(hù)與容錯(cuò)功能,默認(rèn)情況下,F(xiàn)eign會(huì)對(duì)客戶端所有方法進(jìn)行封裝達(dá)到保護(hù)的目的。
(5)服務(wù)降級(jí):服務(wù)降級(jí)是Spring Cloud Hystrix提供的一種服務(wù)容錯(cuò)功能,可以通過配置@FeignClient中的fallback屬性提供一種簡(jiǎn)單的服務(wù)降級(jí)處理方式。
(6)請(qǐng)求壓縮:由于Spring Cloud采用HTTP協(xié)議通信,因此相比TCP性能會(huì)有所限制。為了改進(jìn)服務(wù)間通信的效率,F(xiàn)eign提供GZIP對(duì)請(qǐng)求和響應(yīng)進(jìn)行壓縮從而降低了通信過程中的性能損耗達(dá)到效率的提升。
Feign通過整合Ribbon、Eureka等多個(gè)工具,使用聲明式、模板化的HTTP客戶端以及對(duì)SpringMVC注解的支持使得對(duì)Feign的使用更加便捷。
為了在知識(shí)管理系統(tǒng)[9]中更好地發(fā)揮Feign的功能,需要對(duì)Feign進(jìn)行定制化開發(fā)以及配置服務(wù)路由、負(fù)載均衡、請(qǐng)求壓縮等相關(guān)信息,服務(wù)調(diào)用模塊在微服務(wù)架構(gòu)中如圖2所示。
圖2 微服務(wù)總體架構(gòu)圖
服務(wù)調(diào)用可以分為外部調(diào)用和內(nèi)部調(diào)用,外部調(diào)用需要經(jīng)過網(wǎng)關(guān)的驗(yàn)證、轉(zhuǎn)發(fā)等,內(nèi)部調(diào)用則根據(jù)路由和負(fù)載均衡尋址、GZIP請(qǐng)求壓縮來實(shí)現(xiàn)。具體實(shí)現(xiàn)細(xì)節(jié)如下。
首先創(chuàng)建一個(gè)SpringBoot[10]工程作為服務(wù)調(diào)用方Consumer,然后在pom.xml文件中引入相關(guān)依賴,如下所示:
spring-cloud-starter-eureka
spring-cloud-starter- feign
引入的核心依賴的作用如下:
(1)spring-cloud-starter-eureka:構(gòu)建服務(wù)治理的基礎(chǔ)設(shè)施,包含搭建服務(wù)注冊(cè)中心,提供服務(wù)注冊(cè)與發(fā)現(xiàn)功能。Eureka采用Java[11]實(shí)現(xiàn),適用于Java編寫的分布式系統(tǒng)。
(2) spring-cloud-starter-feign:基于HTTP實(shí)現(xiàn)的RPC框架,提供服務(wù)調(diào)用功能的支持,通過封裝Ribbon和Hystrix提供負(fù)載均衡與熔斷保護(hù)功能。
引入依賴后,在應(yīng)用主類中添加@EnableFeignClients注解開啟Spring Cloud Feign的功能支持;在對(duì)應(yīng)的接口上添加@FeignClient注解,綁定對(duì)應(yīng)的提供服務(wù)的服務(wù)名,然后再用SpringMVC對(duì)應(yīng)的注解綁定該服務(wù)提供的REST接口;創(chuàng)建調(diào)用類,通過@Autowired將定義的接口注入并創(chuàng)建方法調(diào)用;最后在application.properties中指定注冊(cè)中心地址,定義自身服務(wù)的服務(wù)名。
通過Feign只需要定義服務(wù)綁定接口,以聲明式的方法,簡(jiǎn)單而高效地實(shí)現(xiàn)服務(wù)調(diào)用。
搭建完基本的服務(wù)調(diào)用體系后,需要考慮為客戶端配置負(fù)載均衡??梢酝ㄟ^Spring Cloud Ribbon來實(shí)現(xiàn),直接配置Ribbon客戶端的各服務(wù)調(diào)用參數(shù)。全局配置的方式較為簡(jiǎn)單,只需要在配置文件中使用ribbon.
但在多數(shù)實(shí)際問題中,對(duì)于服務(wù)調(diào)用的方式會(huì)做一些調(diào)整,以致全局配置不適用。在使用Spring Cloud Feign時(shí),針對(duì)各個(gè)服務(wù)客戶端進(jìn)行個(gè)性化配置的方式與使用Spring Cloud Ribbon時(shí)的配置方式是一樣的,都采用
為了保證服務(wù)集群[12]的高可用,Spring Cloud Feign默認(rèn)實(shí)現(xiàn)了請(qǐng)求的重試機(jī)制,可以通過設(shè)置MaxAutoRetriesNextServer參數(shù)來決定重試的次數(shù)。需要注意的是Ribbon的超時(shí)與Hystrix的超時(shí)是不同的,所以Hystrix的超時(shí)時(shí)間必須大于Ribbon的超時(shí)時(shí)間,以保證重試機(jī)制存在的意義。
除配置用于客戶端負(fù)載均衡的Ribbon外,要需要對(duì)提供服務(wù)保護(hù)和容錯(cuò)的Hystrix進(jìn)行配置。和Ribbon相似,Hystrix的全局配置默認(rèn)采用hystrix.command.default.
在實(shí)際應(yīng)用中根據(jù)業(yè)務(wù)場(chǎng)景的不同往往需要對(duì)Hystrix進(jìn)行定制化,采用hystrix.command.
另外服務(wù)降級(jí)也是Hystrix提供的重要功能之一,在Spring Cloud Feign中提供了一種簡(jiǎn)單的方式來實(shí)現(xiàn)服務(wù)降級(jí):首先構(gòu)建服務(wù)降級(jí)類,邏輯為服務(wù)降級(jí)邏輯;在服務(wù)綁定接口中,指定@FeignClient注解fallback屬性對(duì)應(yīng)的服務(wù)降級(jí)類。
Spring Cloud Feign支持對(duì)請(qǐng)求和響應(yīng)進(jìn)行GZIP壓縮,以減少通信過程中的性能損耗[13]。詳細(xì)參數(shù)配置如下:
feign.compression.request.enabled=true
feign.compression.response.enabled=true
同時(shí),還可以進(jìn)行更多細(xì)節(jié)的配置,如指定壓縮數(shù)據(jù)類型、數(shù)據(jù)壓縮的上下限等。
為了更好地將Spring Cloud Feign應(yīng)用于實(shí)際,本文在一個(gè)企業(yè)級(jí)的知識(shí)管理系統(tǒng)中應(yīng)用微服務(wù)架構(gòu),系統(tǒng)中各服務(wù)的相互調(diào)用采用Spring Cloud Feign實(shí)現(xiàn)。該系統(tǒng)主要實(shí)現(xiàn)了企業(yè)內(nèi)部重要文檔的存儲(chǔ)和查閱、內(nèi)部消息的快速傳遞以及員工之間更好的交流等功能。
通過合理分配資源,構(gòu)建適用于企業(yè)內(nèi)部體系的應(yīng)用平臺(tái)。Feign提供微服務(wù)架構(gòu)中服務(wù)之間相互調(diào)用,是實(shí)現(xiàn)整個(gè)微服務(wù)架構(gòu)的基礎(chǔ),以及通過數(shù)據(jù)壓縮減少消耗,提高傳輸效率。知識(shí)管理系統(tǒng)總體架構(gòu)圖如圖3所示。
圖3 知識(shí)庫系統(tǒng)架構(gòu)圖
在完成Feign的相關(guān)配置后就可以從代碼層面實(shí)現(xiàn)服務(wù)的跨進(jìn)程調(diào)用了,由于Feign是基于應(yīng)用層協(xié)議HTTP實(shí)現(xiàn)的,對(duì)于開發(fā)者來說無需處理丟包補(bǔ)發(fā)、數(shù)據(jù)分段與重組等,從而可以專注于上層應(yīng)用的設(shè)計(jì)。由于后臺(tái)代碼量較大且調(diào)用其他接口的方式基本相同,因此此處只展示業(yè)務(wù)的部分代碼,具體細(xì)節(jié)如下:
(1)通過注解指定服務(wù)名eureka-client以及對(duì)應(yīng)接口名getName。
@FeignClient("eureka-client")
public interfacegetClient {
@GetMapping("/getName")
Stringconsumer();
}
(2)提供服務(wù)的eureka-client以及相應(yīng)的dc接口。
@GetMapping("/getName")
public String getName() throws Exception{
//業(yè)務(wù)細(xì)節(jié)
}
得益于Feign對(duì)Eureka、Ribbon組件的整合以及對(duì)Spring MVC注解的支持,只需要使用Feign綁定對(duì)應(yīng)服務(wù)及接口,便能夠以簡(jiǎn)潔的方式實(shí)現(xiàn)服務(wù)的跨進(jìn)程調(diào)用。
如何確定微服務(wù)邊界以及劃分一直是構(gòu)建微服務(wù)系統(tǒng)的重要環(huán)節(jié)[14]。在本系統(tǒng)中,通過業(yè)務(wù)劃分將系統(tǒng)分為4個(gè)模塊:后臺(tái)管理模塊、資源共享模塊、員工交流模塊和基礎(chǔ)服務(wù)模塊[15]。在微服務(wù)架構(gòu)中,這些服務(wù)各自承擔(dān)自己的功能以及作為服務(wù)提供者向外提供服務(wù)從而實(shí)現(xiàn)系統(tǒng)的整體功能。
后臺(tái)管理服務(wù)。此服務(wù)的使用者主要面向后臺(tái)管理員,管理員具備對(duì)用戶權(quán)限、角色、所屬部門等的修改權(quán)限。通過對(duì)用戶賦予不同的角色與權(quán)限,從而決定該知識(shí)庫對(duì)用戶的開放級(jí)別,這樣的做法能夠保證公司內(nèi)部知識(shí)的安全性。另外后臺(tái)管理服務(wù)中還加入了審批流程,當(dāng)涉及公司內(nèi)部重要信息時(shí),管理員的一系列操作需要向上匯報(bào)審批,上層通過決策該操作才能生效,否則請(qǐng)求被駁回。
資源共享服務(wù)。此服務(wù)主要用于公司員工上傳下載文檔資源,用戶在通過權(quán)限驗(yàn)證后可以采用不同的文件形式上傳或下載對(duì)應(yīng)的資源文件,經(jīng)過后臺(tái)審核成功后完成。為了方便用戶更好地查找對(duì)應(yīng)資源,該模塊提供了全站搜索,用戶可通過輸入關(guān)鍵字在數(shù)據(jù)庫中匹配到相關(guān)資源,最后的結(jié)果經(jīng)過權(quán)限過濾后呈現(xiàn)給用戶。
員工交流服務(wù)。此服務(wù)分為論壇和貼吧兩部分[16],論壇部分主要提供員工交流功能,員工在此處發(fā)表帖子,其他人可以評(píng)論點(diǎn)贊等;貼吧部分是給員工提供企業(yè)答疑,對(duì)于企業(yè)存在疑問的部分可以提出問題,其他用戶看到給予答復(fù)。通過這種方式可以有效完善公司的知識(shí)管理系統(tǒng)以及方便公司管理人員發(fā)表公告、活動(dòng)等。
基礎(chǔ)服務(wù)。此服務(wù)是系統(tǒng)的基礎(chǔ)部分,負(fù)責(zé)為系統(tǒng)提供工作流服務(wù)、郵件短信服務(wù)、報(bào)表輸出等。工作流用于流程審批,報(bào)表用于統(tǒng)計(jì)結(jié)果的收集與導(dǎo)出,短信郵件用于系統(tǒng)通知或安全驗(yàn)證。
最后所有的服務(wù)模塊經(jīng)由API網(wǎng)關(guān)按照內(nèi)部和外部對(duì)應(yīng)規(guī)則對(duì)接口進(jìn)行統(tǒng)一封裝,然后對(duì)外提供服務(wù)。
本文首先介紹了RPC及其原理,其次通過對(duì)比市面上的主流RPC框架以及其實(shí)現(xiàn)難易程度最終確定本次服務(wù)調(diào)用方案設(shè)計(jì)采用的技術(shù),即基于Spring Cloud實(shí)現(xiàn)一種聲明式服務(wù)調(diào)用方案,隨后將其應(yīng)用在一個(gè)企業(yè)級(jí)知識(shí)管理系統(tǒng)中,實(shí)現(xiàn)了Feign定制化開發(fā)。
結(jié)果表明,只需創(chuàng)建接口以及加入注解便可以完成對(duì)提供服務(wù)接口的綁定,很好地解決了一個(gè)接口被多個(gè)服務(wù)調(diào)用的多重依賴情況,有效簡(jiǎn)化了服務(wù)調(diào)用客戶端的開發(fā)流程,提升了系統(tǒng)的開發(fā)效率和后期可維護(hù)性,基本達(dá)到了服務(wù)調(diào)用框架的預(yù)期設(shè)計(jì)與應(yīng)用。當(dāng)然,Spring Cloud Feign作為一款基于HTTP協(xié)議實(shí)現(xiàn)的RESTful風(fēng)格的服務(wù)調(diào)用組件,雖然保證了其簡(jiǎn)潔明了的調(diào)用風(fēng)格和較高的可讀性,但在性能方面與私有的二進(jìn)制協(xié)議實(shí)現(xiàn)的RPC框架相比仍然存在較大差距,因此在后續(xù)的研究中會(huì)考慮在通信協(xié)議進(jìn)行更多的優(yōu)化或者選擇可以兼顧性能與可讀性的通信協(xié)議。