張金玲 王天人 蔣 成 張正明 許 翀
中國(guó)聯(lián)通研究院 北京 100176
當(dāng)微服務(wù)的數(shù)量隨著業(yè)務(wù)數(shù)量的增加而增加時(shí),封裝和運(yùn)行微服務(wù)程序的容器管理和編排難度相應(yīng)的增加,微服務(wù)項(xiàng)目融合容器編排體系非常有必要。同時(shí)微服務(wù)支持的技術(shù)比較復(fù)雜且支持多種技術(shù)開(kāi)發(fā)語(yǔ)言,因此開(kāi)發(fā)語(yǔ)言之間如何調(diào)用、如何替換其他技術(shù)語(yǔ)言、如何降低技術(shù)升級(jí)替換成本等問(wèn)題亟需解決,加之業(yè)務(wù)邏輯的復(fù)雜性需要項(xiàng)目研發(fā)人員的精力集中在業(yè)務(wù)的開(kāi)發(fā)上,項(xiàng)目中服務(wù)的治理和運(yùn)維需要分離開(kāi)來(lái),服務(wù)網(wǎng)格的引入很好地解決了這些難題[1]。服務(wù)網(wǎng)格將服務(wù)管理功能從整體項(xiàng)目中獨(dú)立出來(lái),將服務(wù)治理功能提到微服務(wù)的底層部署端,在微服務(wù)底層部署端以獨(dú)立的方式部署,這種獨(dú)立服務(wù)治理方式敏捷地完成了項(xiàng)目的迭代演進(jìn),保障了系統(tǒng)的高可靠性,實(shí)現(xiàn)了支持多種語(yǔ)言的開(kāi)發(fā)。
本文以現(xiàn)有的單體微服務(wù)項(xiàng)目為改造背景,介紹如何將容器編排技術(shù)、服務(wù)網(wǎng)格技術(shù)應(yīng)用到微服務(wù)項(xiàng)目改造中。
現(xiàn)有微服務(wù)項(xiàng)目融合了業(yè)務(wù)與分布式系統(tǒng)的服務(wù)管理功能,服務(wù)管理包括服務(wù)注冊(cè)、服務(wù)發(fā)現(xiàn)、配置管理、熔斷限流、路由分發(fā)等功能,目前存在的問(wèn)題有以下四點(diǎn)。
1)微服務(wù)數(shù)量隨業(yè)務(wù)量增加而增多,部署的容器數(shù)量級(jí)隨之變大,對(duì)于大量容器的編排問(wèn)題需要解決。
2)業(yè)務(wù)復(fù)雜性帶來(lái)業(yè)務(wù)垂直深度的增強(qiáng),共享能力和業(yè)務(wù)分工問(wèn)題開(kāi)始凸顯。
3)業(yè)務(wù)問(wèn)題方面,業(yè)務(wù)邏輯與服務(wù)治理相關(guān)功能結(jié)合緊密,使得開(kāi)發(fā)人員在開(kāi)發(fā)業(yè)務(wù)邏輯的同時(shí)需要完成運(yùn)維功能的開(kāi)發(fā),工作量巨大,開(kāi)發(fā)人員不能專心投入于業(yè)務(wù)的研發(fā)。
4)原項(xiàng)目的運(yùn)維部分功能支持多種語(yǔ)言開(kāi)發(fā)的靈活性不高。
因此現(xiàn)有項(xiàng)目改造為基于容器編排技術(shù)和服務(wù)網(wǎng)格技術(shù)的項(xiàng)目非常有必要。整體改造方案首先完成容器的自動(dòng)化部署運(yùn)維,接下來(lái)進(jìn)行業(yè)務(wù)間的逐步松耦合,業(yè)務(wù)邏輯與服務(wù)治理間的逐步松耦合,繼而形成專業(yè)分工的松耦合團(tuán)隊(duì),最終使得應(yīng)用得以敏捷開(kāi)發(fā)、快速增長(zhǎng)[2]。
基于服務(wù)網(wǎng)格的微服務(wù)項(xiàng)目通過(guò)將原項(xiàng)目融合容器編排系統(tǒng)和服務(wù)治理框架,改造成為將服務(wù)治理功能從整個(gè)項(xiàng)目中獨(dú)立出來(lái),將服務(wù)治理功能提到微服務(wù)底層部署端,在微服務(wù)部署端以獨(dú)立方式部署,容器部署運(yùn)維自動(dòng)化的體系。
整體的改造項(xiàng)目的技術(shù)架構(gòu)圖如圖1所示,在服務(wù)治理與業(yè)務(wù)邏輯分離的實(shí)現(xiàn)上,服務(wù)網(wǎng)格采用了Sidecar模式,由圖中的Envoy實(shí)現(xiàn),相較于將服務(wù)發(fā)現(xiàn)、服務(wù)路由等能力嵌入到應(yīng)用內(nèi)部的普通微服務(wù)框架更加靈活,做到了對(duì)應(yīng)用完全無(wú)侵入性[3]。微服務(wù)與其代理之間相互通信,代理完成微服務(wù)輸入和輸出流量的控制,代理也可以作為網(wǎng)關(guān),根據(jù)從Polit獲取的規(guī)則對(duì)外部的訪問(wèn)進(jìn)行接收并轉(zhuǎn)發(fā)到應(yīng)用系統(tǒng)中。所有微服務(wù)部署在容器編排系統(tǒng)上,每個(gè)Node有一個(gè)或多個(gè)Pod,微服務(wù)所有的相關(guān)信息存儲(chǔ)于etcd中,對(duì)微服務(wù)信息的操作都經(jīng)由API Server的調(diào)用并訪問(wèn)etcd完成。
圖1 改造項(xiàng)目技術(shù)架構(gòu)圖
整體的改造項(xiàng)目的技術(shù)功能如圖2所示,共分為三個(gè)部分。
圖2 改造項(xiàng)目技術(shù)功能圖
1)在業(yè)務(wù)應(yīng)用部分:改造后的業(yè)務(wù)應(yīng)用只保留業(yè)務(wù)相關(guān)邏輯,并包裝為多個(gè)微服務(wù)。
2)在服務(wù)治理部分:改造項(xiàng)目將業(yè)務(wù)邏輯和服務(wù)治理功能分離,項(xiàng)目中動(dòng)態(tài)路由、熔斷限流、安全訪問(wèn)、流量攔截、負(fù)載均衡、服務(wù)發(fā)現(xiàn)、流量治理、服務(wù)監(jiān)測(cè)等運(yùn)維功能分離出來(lái)。
3)在容器編排部分:業(yè)務(wù)層微服務(wù)的部署于容器中,容器管理部分包含自動(dòng)化部署、擴(kuò)縮容、狀態(tài)監(jiān)控、故障遷移、資源調(diào)度、資源隔離、容器運(yùn)維等功能。
整個(gè)項(xiàng)目的服務(wù)運(yùn)維層面功能由服務(wù)網(wǎng)格提供實(shí)現(xiàn),包括服務(wù)可視化監(jiān)控和豐富的服務(wù)治理能力,由此很好地解決了系統(tǒng)微服務(wù)化后的維護(hù)難題。
原微服務(wù)項(xiàng)目以容器化技術(shù)解決部署配置的問(wèn)題,但隨著細(xì)粒度的微服務(wù)越來(lái)越多,進(jìn)而存在容器管理和編排上的困難。為應(yīng)對(duì)以上問(wèn)題,將項(xiàng)目原有Spring-Cloud框架結(jié)合Kubenetes容器編排系統(tǒng)的技術(shù)架構(gòu),即改造為使用spring-cloud-kubenetes框架,底層使用Kubenetes環(huán)境實(shí)現(xiàn)自動(dòng)化部署、容器擴(kuò)縮容、容器的健康狀態(tài)管理、自動(dòng)運(yùn)維和跨集群調(diào)度等。
SpringCloud項(xiàng)目在改造為容器自動(dòng)化編排時(shí),結(jié)合spring-cloud-kubernetes框架,調(diào)用Kubernetes能力,服務(wù)注冊(cè)后微服務(wù)相關(guān)數(shù)據(jù)存儲(chǔ)在etcd中實(shí)現(xiàn),其架構(gòu)如圖3所示。
圖3中,Spring-Cloud環(huán)境下運(yùn)行的serviceA和serviceB分別部署在Kubernetes的不同Node節(jié)點(diǎn)不同的Pod上,Kubernetes對(duì)應(yīng)用服務(wù)提供了自動(dòng)化部署以及后續(xù)容器的運(yùn)維工作,同時(shí)部署時(shí)將服務(wù)的各個(gè)實(shí)例的地址通過(guò)API Server存儲(chǔ)在Kubernetes的etcd中。
圖3 服務(wù)注冊(cè)技術(shù)架構(gòu)圖
改造項(xiàng)目將SpringCloud應(yīng)用中業(yè)務(wù)功能與服務(wù)發(fā)現(xiàn)、負(fù)載均衡、熔斷限流、智能路由等運(yùn)維功能分離開(kāi)來(lái),由服務(wù)網(wǎng)格Istio框架實(shí)現(xiàn)業(yè)務(wù)邏輯與運(yùn)維功能間的剝離,在保持原有的應(yīng)用管理功能上融合Istio服務(wù)網(wǎng)格能力。由Istio組件中的Adapter實(shí)現(xiàn)與Kubernetes引擎的融合,有效調(diào)用容器編排相關(guān)的功能,完成對(duì)Kubernetes引擎提供服務(wù)治理能力的調(diào)用。
通過(guò)把服務(wù)治理功能從整體項(xiàng)目中獨(dú)立出來(lái),將服務(wù)治理功能提到微服務(wù)底層部署端,在微服務(wù)部署端以獨(dú)立部署的方式,實(shí)現(xiàn)了去中心化,實(shí)現(xiàn)了服務(wù)治理功能的獨(dú)立,便利地完成服務(wù)管理和業(yè)務(wù)邏輯分開(kāi)的迭代升級(jí)。同時(shí)服務(wù)網(wǎng)格架構(gòu)將服務(wù)管理功能分離,大幅度的降低了對(duì)業(yè)務(wù)邏輯關(guān)聯(lián)度,實(shí)現(xiàn)了支持多技術(shù)語(yǔ)言的開(kāi)發(fā)[4]。
SpringCloud項(xiàng)目在改造后,通過(guò)結(jié)合Istio框架與spring-cloud-kubernetes框架,與微服務(wù)同節(jié)點(diǎn)獨(dú)立部署的服務(wù)代理調(diào)用kubernetes能力,通過(guò)API Server訪問(wèn)etcd中內(nèi)容實(shí)現(xiàn)。具體的服務(wù)發(fā)現(xiàn)功能由服務(wù)代理發(fā)起,調(diào)用應(yīng)用控制面Pilot的接口,應(yīng)用控制面Pilot中的adapter與Kubernetes里adapter相結(jié)合進(jìn)行關(guān)聯(lián)通信,調(diào)用kube-apiserver,查找etcd中數(shù)據(jù),發(fā)現(xiàn)kubernetes中服務(wù)與部署pod之間的對(duì)應(yīng)關(guān)系并返回。Pilot將返回結(jié)果處理為服務(wù)代理Envoy可識(shí)別的轉(zhuǎn)發(fā)模型并下發(fā)到服務(wù)代理中,將kube-proxy的轉(zhuǎn)發(fā)功能由服務(wù)代理Envoy實(shí)現(xiàn),完成服務(wù)發(fā)現(xiàn)功能,其架構(gòu)如圖4所示。
圖4 服務(wù)發(fā)現(xiàn)技術(shù)架構(gòu)圖
圖4中,一個(gè)應(yīng)用服務(wù)在調(diào)用另一個(gè)應(yīng)用服務(wù)時(shí),首先代理調(diào)用應(yīng)用控制面Pilot中的接口,Pilot調(diào)用kubenetes API Server的接口,最終查詢etcd中的服務(wù)相關(guān)的信息,將目的應(yīng)用服務(wù)的相關(guān)信息返回至服務(wù)代理,服務(wù)代理向目標(biāo)服務(wù)的多個(gè)Pod輪詢發(fā)起請(qǐng)求。具體流程如下。
1)ServiceA的服務(wù)代理訪問(wèn)Pilot 的接口,發(fā)起服務(wù)訪問(wèn)需求。
2)Pilot 的服務(wù)發(fā)現(xiàn)接口調(diào)用kubenetes API Server中的請(qǐng)求服務(wù)列表接口。
3)所有服務(wù)數(shù)據(jù)存儲(chǔ)在etcd中,由API Server調(diào)用,API Server的請(qǐng)求服務(wù)列表接口獲得數(shù)據(jù)庫(kù)中相關(guān)服務(wù)信息,最終獲取目標(biāo)服務(wù)serviceB的實(shí)例列表。
4)ServiceA的 Envoy根據(jù)獲得的目標(biāo)服務(wù)serviceB的實(shí)例列表,向ServiceB的多個(gè)Pod發(fā)起輪詢的訪問(wèn)。
Istio框架可以有效的實(shí)現(xiàn)當(dāng)服務(wù)出現(xiàn)訪問(wèn)異常情況時(shí),對(duì)服務(wù)進(jìn)行限制訪問(wèn)流量操作或者將服務(wù)從負(fù)載均衡池中移除,以達(dá)到調(diào)用此服務(wù)或者多級(jí)調(diào)用此服務(wù)的服務(wù)能夠正常運(yùn)行,防止出現(xiàn)系統(tǒng)癱瘓的現(xiàn)象[5]。主要通過(guò)熔斷限流規(guī)則的配置完成對(duì)應(yīng)功能,包括異常點(diǎn)檢測(cè)規(guī)則和連接池配置規(guī)則。異常點(diǎn)檢測(cè)是指當(dāng)某個(gè)服務(wù)實(shí)例不斷出錯(cuò)或者超時(shí)響應(yīng)時(shí),對(duì)其進(jìn)行切斷操作,防止對(duì)此服務(wù)實(shí)例進(jìn)行多級(jí)調(diào)用者產(chǎn)生類似“雪崩”效應(yīng)。連接池配置規(guī)則包括對(duì)服務(wù)提供者進(jìn)行連接的數(shù)量、請(qǐng)求數(shù)、出錯(cuò)后的允許重試的次數(shù)等,通過(guò)這些參數(shù)的設(shè)置,達(dá)到超過(guò)預(yù)設(shè)的訪問(wèn)數(shù)量則斷開(kāi)連接和限定重新連接的次數(shù)的效果,防止出現(xiàn)訪問(wèn)數(shù)量劇增系統(tǒng)癱瘓的問(wèn)題,實(shí)現(xiàn)系統(tǒng)的高可靠性。具體的步驟如下。
在應(yīng)用控制面:
1)管理員通過(guò)命令行或接口創(chuàng)建熔斷限流的規(guī)則,包括基于連接池大小、連接請(qǐng)求數(shù)量和異常值參數(shù),在DestinationRule中設(shè)置TrafficPolicy參數(shù),連接池限流方式為ConnectionPool參數(shù),異常檢測(cè)熔斷方式為OutlierDetection參數(shù);
2)Pilot組件將熔斷限流規(guī)則進(jìn)行轉(zhuǎn)換,轉(zhuǎn)換為代理Envoy可以識(shí)別的格式;
3)Polot組件將轉(zhuǎn)換后的規(guī)則下發(fā)給代理Envoy。
在應(yīng)用數(shù)據(jù)面:
Envoy接收Polit的熔斷限流設(shè)置規(guī)則后,轉(zhuǎn)換為Cluster的配置對(duì)象,每個(gè)代理Envoy之間根據(jù)Cluster的配置信息進(jìn)行通訊。配置規(guī)則中有具體的負(fù)載均衡池的設(shè)定、連接池和滿足故障檢測(cè)情況的參數(shù)。若滿足配置中的情況,則將有問(wèn)題的服務(wù)實(shí)例撤離出負(fù)載均衡池,通過(guò)優(yōu)化負(fù)載均衡的方法啟動(dòng)熔斷機(jī)制。
請(qǐng)求路由可以根據(jù)不同需求,如按照百分比或按照請(qǐng)求內(nèi)容等,將請(qǐng)求路由至不同的版本,將請(qǐng)求的訪問(wèn)分配到對(duì)應(yīng)的版本上[6],具體步驟如下。
1)首先完成Pilot中的路由分配規(guī)則設(shè)置,包括流量與故障相關(guān)的配置。路由的請(qǐng)求設(shè)置由VirtualService中參數(shù)實(shí)現(xiàn),完成路由轉(zhuǎn)發(fā)后對(duì)其他服務(wù)的訪問(wèn)規(guī)則由DestinationRule設(shè)置,包括服務(wù)輪詢規(guī)則方法、連接配置和異常檢測(cè)等參數(shù)。
2)流量導(dǎo)向規(guī)則在Polit中改變成代理Envoy可辨別的形式,轉(zhuǎn)變后發(fā)送給Envoy。
3)Envoy首先從Pilot接收到路由規(guī)則,與此同時(shí)定期進(jìn)行異常檢索并將檢索結(jié)果與當(dāng)前運(yùn)行情況發(fā)送給所有其他的代理。Envoy根據(jù)路由規(guī)則即負(fù)載均衡與系統(tǒng)中所有代理的異常檢索結(jié)果、當(dāng)前運(yùn)行結(jié)果,對(duì)流量進(jìn)行分配,完成智能路由的功能[7]。
智能路由實(shí)現(xiàn)了pod訪問(wèn)量均衡分配的效果,由Envoy按照配置與其他代理運(yùn)行情況完成了流量的分配。如圖5所示,Polit設(shè)置了路由規(guī)則,ServiceB與ServiceB1訪問(wèn)流量分配比例為4:1,ServiceA的服務(wù)代理Envoy接收了路由設(shè)置規(guī)則后,當(dāng)外部訪問(wèn)ServiceA時(shí),其服務(wù)代理Envoy將訪問(wèn)流量進(jìn)行分配,80%的流量訪問(wèn)ServiceB,其余的流量分配給ServiceB1。
圖5 服務(wù)智能路由
在項(xiàng)目迭代升級(jí)時(shí),為防止項(xiàng)目整體上線時(shí)項(xiàng)目使用效果不佳,將少量的生產(chǎn)環(huán)境的流量分配到最新項(xiàng)目版本中,其余流量則留在原版本中,測(cè)試更新項(xiàng)目使用情況,是否存在問(wèn)題,沒(méi)有問(wèn)題后進(jìn)而不斷增加新版本的流量使用占比,最終完成整體上線,通過(guò)此方法漸變、嘗試地完成項(xiàng)目版本的更新,保證項(xiàng)目使用效果[8]。
基于Spring-Cloud環(huán)境開(kāi)發(fā)的微服務(wù)運(yùn)行于Kubernetes的pod中,istio適配器與K8s控制節(jié)點(diǎn)相結(jié)合,使得與K8s有效融合,項(xiàng)目開(kāi)發(fā)人員對(duì)路由策略進(jìn)行配置進(jìn)而完成灰度版本控制。其策略靈活的制定與對(duì)流量的管理有效實(shí)現(xiàn)了灰度發(fā)布,同時(shí)達(dá)到新老版本同時(shí)存在,且對(duì)不同版本敏捷的進(jìn)行訪問(wèn)流量配置的效果。
首先在應(yīng)用控制層Polit中完成訪問(wèn)流量配置的設(shè)置,所有代理Envoy接收對(duì)應(yīng)的配置規(guī)則,每個(gè)代理在對(duì)目標(biāo)服務(wù)進(jìn)行訪問(wèn)前,都需要按照流量配置的規(guī)則進(jìn)行流量分發(fā),達(dá)到版本迭代灰度發(fā)布的效果[9]。
灰度發(fā)布有多種規(guī)則,大多數(shù)以訪問(wèn)流量比例為主,除此之外,還可以對(duì)訪問(wèn)內(nèi)容進(jìn)行控制,包括服務(wù)請(qǐng)求方的操作系統(tǒng)、訪問(wèn)時(shí)使用的瀏覽器和請(qǐng)求頭等。如圖6所示,為基于流量比例進(jìn)行分配的服務(wù)灰度發(fā)布。
圖6 服務(wù)灰度發(fā)布
1)Pilot中設(shè)置灰度發(fā)布規(guī)則,為訪問(wèn)serviceC的v1版本設(shè)置70%的流量,訪問(wèn)serviceC的v2版本設(shè)置為30%的流量。Pilot將規(guī)則下發(fā)至各個(gè)服務(wù)代理Envoy中。
2)各微服務(wù)的代理Envoy接收到灰度發(fā)布的規(guī)則。
3)Spring-cloud serviceA調(diào)用Spring-cloud serviceC服務(wù)時(shí),serviceA的Envoy設(shè)置分流,將流量的70%分發(fā)給serviceC的V1版本,將流量的30%分發(fā)給serviceC的V 2 版本。當(dāng)S p r i n g-c l o u d serviceB服務(wù)調(diào)用Spring-cloud serviceC服務(wù)時(shí),serviceB的服務(wù)代理同樣按照灰度發(fā)布的規(guī)則進(jìn)行分發(fā)流量。
基于istio框架改造的微服務(wù)項(xiàng)目,除了提供服務(wù)發(fā)現(xiàn)、熔斷限流、智能路由功能外,也能敏捷地完成鏈路監(jiān)控、安全策略、性能監(jiān)控等服務(wù)治理功能。改造后的微服務(wù)項(xiàng)目可以更好的實(shí)現(xiàn)復(fù)雜業(yè)務(wù)功能,通過(guò)istio非侵入性的配置,代理基于配置進(jìn)行流量管理來(lái)完成各項(xiàng)運(yùn)維功能,并將運(yùn)維功能有效的融合到業(yè)務(wù)系統(tǒng)中[10]。
基于服務(wù)網(wǎng)格的微服務(wù)項(xiàng)目改造,是通過(guò)應(yīng)用容器編排技術(shù)與服務(wù)網(wǎng)格技術(shù)等,解決實(shí)際原項(xiàng)目中面臨的隨著業(yè)務(wù)量增加而增加的大量細(xì)粒度微服務(wù)的部署、運(yùn)維和治理難題,解決因業(yè)務(wù)邏輯與服務(wù)管理功能緊密結(jié)合導(dǎo)致的局部修改升級(jí)需要整體更新升級(jí)的問(wèn)題。此項(xiàng)目改造實(shí)現(xiàn)了以下四個(gè)創(chuàng)新點(diǎn)。
1)在業(yè)務(wù)應(yīng)用方面,原項(xiàng)目包含了業(yè)務(wù)邏輯與服務(wù)發(fā)現(xiàn)、負(fù)載均衡、熔斷限流和智能路由等運(yùn)維功能,所有代碼聯(lián)系緊密。改造后項(xiàng)目將業(yè)務(wù)邏輯抽離出來(lái),包裝為細(xì)粒度的多個(gè)微服務(wù)。
2)利用服務(wù)網(wǎng)格技術(shù)實(shí)現(xiàn)服務(wù)治理功能,并將服務(wù)治理功能與業(yè)務(wù)層進(jìn)行有效性結(jié)合,實(shí)現(xiàn)業(yè)務(wù)邏輯與服務(wù)管理的剝離。服務(wù)治理實(shí)現(xiàn)方式簡(jiǎn)單,規(guī)則設(shè)置方式敏捷。服務(wù)治理功能部署在底層,減少了對(duì)業(yè)務(wù)代碼的關(guān)聯(lián),使得開(kāi)發(fā)周期短,測(cè)試與運(yùn)維簡(jiǎn)易執(zhí)行,彌補(bǔ)了原項(xiàng)目業(yè)務(wù)與運(yùn)維功能結(jié)合緊密、開(kāi)發(fā)效率低、測(cè)試難度大的一系列問(wèn)題,進(jìn)一步提高業(yè)務(wù)快速迭代升級(jí)效率。
3)容器編排包含自動(dòng)化部署、擴(kuò)縮容、狀態(tài)監(jiān)控、故障遷移、資源調(diào)度、資源隔離、容器運(yùn)維等功能,同時(shí)服務(wù)網(wǎng)格技術(shù)實(shí)現(xiàn)的服務(wù)治理功能與此底層平臺(tái)能夠進(jìn)行有效性的融合,減少服務(wù)治理與容器編排底層路徑重復(fù)的問(wèn)題,提高了服務(wù)治理的精確度與速度。
4)在與業(yè)務(wù)側(cè)的關(guān)系方面,原項(xiàng)目以lib包嵌入到業(yè)務(wù)代碼中,改造后項(xiàng)目為邊車模式,與業(yè)務(wù)松耦合。在語(yǔ)言壁壘方面,改造前的項(xiàng)目只允許Java語(yǔ)言發(fā)開(kāi),改造后項(xiàng)目無(wú)語(yǔ)言壁壘。