架構(gòu)設(shè)計:從分布式到微服務(wù),深入Service Mesh

原文地址:架構(gòu)技術(shù)進(jìn)階

微服務(wù)架構(gòu)是個難題,但解法有多個

微服務(wù)是一個很大的概念,從團(tuán)隊組織到最佳實踐似乎都有實施微服務(wù)的一些指導(dǎo)。我們這里只提構(gòu)建微服務(wù)的架構(gòu)模式,也就是關(guān)乎到你用什么樣的方式來構(gòu)建你以微服務(wù)架構(gòu)來組織的應(yīng)用系統(tǒng)。

近些年隨著微服務(wù)的火熱,越來越多的團(tuán)隊開始進(jìn)行實踐,將微服務(wù)紛紛落地,也許你是從0開始,一步步地完成了單體應(yīng)用向微服務(wù)的改造,讓我們來看看,你解決了多少問題。


微服務(wù)架構(gòu)需要解決的問題

微服務(wù)將原本內(nèi)存中函數(shù)的調(diào)用轉(zhuǎn)換為網(wǎng)絡(luò)中的調(diào)用后,就牽扯到這些問題,而任何一個分支展開,都會涉及一系列的問題。業(yè)務(wù)開發(fā)者也許真的有精力去學(xué)習(xí)架構(gòu)相關(guān)的復(fù)雜問題,然而對于公司來說,真正有價值的是業(yè)務(wù)本身,讓業(yè)務(wù)開發(fā)者解決這些問題需要花費浪費大量的時間精力,導(dǎo)致業(yè)務(wù)上線受到影響。那我們來看看是否有便捷的方式來解決業(yè)務(wù)開發(fā)者的痛點。

Chassis模式

一句話來概括:一種語言開發(fā)框架來作為微服務(wù)開發(fā)的底座,封裝掉復(fù)雜性,幫助你解決跨網(wǎng)絡(luò)帶來的問題,讓用戶聚焦在上層業(yè)務(wù)邏輯的開發(fā)。通常情況下會實現(xiàn)以下功能:

  • 日志、Metrics、分布式追蹤數(shù)據(jù)上報
  • 健康檢查
  • 對接統(tǒng)一的配置中心實現(xiàn)動態(tài)配置
  • 對接注冊中心
  • 實現(xiàn)負(fù)載均衡、熔斷降級、容錯、限流等保證高可靠運(yùn)行的功能

現(xiàn)在我們來看看業(yè)界有哪些可用的Chassis框架

  • Spring Cloud
  • ServiceComb
  • Dubbo
  • Go-Micro
  • Go-Kit

先不細(xì)去糾結(jié)微服務(wù)的嚴(yán)格定義,也先暫且擱置諸如“某些老舊框架是否是真的微服務(wù)框架”這類爭議,從實現(xiàn)方式來看,上述服務(wù)化框架都是將分布式系統(tǒng)開發(fā)的復(fù)雜性進(jìn)行了一定程度的封裝然后提供了簡便的開發(fā)接口供使用者調(diào)用。但是,用這種方式構(gòu)建微服務(wù)還有一些問題:

  • 多語言SDK支持:微服務(wù)提倡不同組件使用最適合它的語言開發(fā),但是這需要每種語言都有開發(fā)框架,不斷實現(xiàn)相同的功能。上面可以看到只有g(shù)o語言和Java語言出現(xiàn)了微服務(wù)開發(fā)框架,其他語言呢?
  • 不論代碼侵入程度,都需要開發(fā)者思考如何與SDK結(jié)合,并從代碼層面做出改變,對于大部分開發(fā)者來說都是一個高曲線的學(xué)習(xí)過程。
  • 綁定了特定技術(shù)棧,一旦想抽身就需要一定程度上的代碼改造。
  • 老舊單體應(yīng)用由于無人維護(hù),耦合程度高等問題無法進(jìn)行改造,在進(jìn)行微服務(wù)拆分的過程中重用遺留代碼變得無比困難。而且微服務(wù)的拆分難以分步進(jìn)行,需要一個相對較長的周期將系統(tǒng)整體拆分后才能上線。

我們知道技術(shù)演進(jìn)來自于在實踐中不斷地將功能抽象,解耦,封裝,服務(wù)化。

  • 云計算技術(shù)出現(xiàn)前是數(shù)據(jù)中心虛擬化,不斷地實踐使技術(shù)發(fā)展形成理論和新的實踐。IaaS是一種封裝,如今開發(fā)者與大部分技術(shù)團(tuán)隊不需要再學(xué)習(xí)虛擬化等技術(shù)以及如何維護(hù)數(shù)據(jù)中心。
  • 沒有TCP/IP的時代,開發(fā)人員需要自己考慮網(wǎng)絡(luò)間數(shù)據(jù)包的傳輸,以及網(wǎng)絡(luò)傳輸代碼與業(yè)務(wù)代碼完全耦合的問題,如今,開發(fā)者已經(jīng)不需要關(guān)心,操作系統(tǒng)和開發(fā)語言已經(jīng)封裝好網(wǎng)絡(luò)傳輸過程。
    是否也可以把語言框架提供的能力抽象,成為服務(wù)?

在引入后面內(nèi)容前,我先介紹下SideCar模式

SideCar模式

  • 在近些年受到Kubernetes對容器調(diào)度方式的啟示而日漸受到關(guān)注的一種功能部署模式,也是一種微服務(wù)的設(shè)計模式。
  • 主要利用了一個Pod中的容器可以共享存儲與網(wǎng)絡(luò)的能力,或者說在一個Host中,這個模式也同樣適用。
  • 一般分為應(yīng)用容器和工具容器,工具容器可以重用。

一個典型的場景如下:


SideCar典型場景

應(yīng)用容器與日志同步工具在同一個Pod下,共享存儲卷,應(yīng)用程序生成的日志文件會由日志同步工具收集并發(fā)送到類似kafka,elasticsearch這樣服務(wù)中。

在這樣的架構(gòu)下我們獲得了什么呢?

  • 以容器作為基礎(chǔ)打包單元,那么就可以分給不同的團(tuán)隊進(jìn)行開發(fā)測試
  • Sidecar容器可重用,可以與不同的容器結(jié)合
  • 以容器作為錯誤邊界,使服務(wù)能夠獨立開發(fā)和測試,比如應(yīng)用服務(wù)在沒有日志保存功能的情況下也可以獨立運(yùn)行
  • 獨立回滾與更新(但需要考慮復(fù)雜的版本組合,建議使用語義版本管理對版本進(jìn)行控制)

在這個模式的基礎(chǔ)之下,我們引入了Service mesh。

Service Mesh 新瓶中的那一杯老酒

什么是Service Mesh

Service mesh最早是由Linkerd給出的定義,我們來看看英文版:

A service mesh is a dedicated infrastructure layer for handling service-to-service communication. It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern, cloud native application. In practice, the service mesh is typically implemented as an array of lightweight network proxies that are deployed alongside application code, without the application needing to be aware. (But there are variations to this idea, as we’ll see.)

The concept of the service mesh as a separate layer is tied to the rise of the cloud native application. In the cloud native model, a single application might consist of hundreds of services; each service might have thousands of instances; and each of those instances might be in a constantly-changing state as they are dynamically scheduled by an orchestrator like Kubernetes. Not only is service communication in this world incredibly complex, it’s a pervasive and fundamental part of runtime behavior. Managing it is vital to ensuring end-to-end performance and reliability.

大致的意思如下:

  • 一種基礎(chǔ)設(shè)施層服務(wù),服務(wù)間的通信通過service mesh進(jìn)行
  • 可靠地傳輸復(fù)雜拓?fù)渲蟹?wù)的請求,將它們變成現(xiàn)代的云原生服務(wù)
  • 一種網(wǎng)絡(luò)代理的實現(xiàn),通常與業(yè)務(wù)服務(wù)部署在一起,業(yè)務(wù)服務(wù)不感知
  • 一種網(wǎng)絡(luò)模型,在TCP/IP之上的抽象層,TCP/IP負(fù)責(zé)將字節(jié)碼可靠地在網(wǎng)絡(luò)節(jié)點間傳遞,Service mesh則復(fù)雜將服務(wù)間的協(xié)議請求可靠地在服務(wù)間進(jìn)行傳輸。它們不關(guān)心傳輸?shù)膬?nèi)容
  • TCP/IP僅僅負(fù)責(zé)傳輸,但Service mesh可對運(yùn)行時進(jìn)行控制,使服務(wù)變得可監(jiān)控,可管理。

為什么使用Service Mesh

  • 無需考慮每種語言都要解決的問題
  • 對業(yè)務(wù)代碼0侵入,開發(fā)者無需關(guān)心分布式架構(gòu)帶來的復(fù)雜性以及引入的技術(shù)問題
  • 對于不適合改造的老舊單體應(yīng)用,提供了一種接入分布式環(huán)境的方式
  • 微服務(wù)化的進(jìn)程通常不是一蹴而就的,很多應(yīng)用選擇了演進(jìn)的方式,就是將單體應(yīng)用一部分一部分地進(jìn)行拆分。而在這個過程中,使用Service Mesh就可以很好地保證未拆分的應(yīng)用與已經(jīng)拆分出來的微服務(wù)之間的互通和統(tǒng)一治理
  • 開發(fā)出的應(yīng)用既是云原生的又具有云獨立性,不將業(yè)務(wù)代碼與任何框架,平臺或者服務(wù)綁定

依然沒有銀彈,我們來看看Service mesh解決不了的問題

  • 無分布式事務(wù)方案
  • Service Mesh組件代理請求轉(zhuǎn)發(fā),會在一定程度上降低系統(tǒng)通信性能
  • 沒有Event Driven的框架
  • 侵入式框架以源碼和業(yè)務(wù)代碼結(jié)合,有較強(qiáng)定制和擴(kuò)展能力,Service mesh相對不易定制擴(kuò)展
  • 在運(yùn)行時,依賴單獨的Service Mesh代理,多了一個故障點。整個系統(tǒng)的運(yùn)行和運(yùn)維也強(qiáng)依賴于Service Mesh組件的能力

Service Mesh的實踐歷程和設(shè)計思路

Service Mesh在華為公司內(nèi)部的發(fā)展歷程

第一代: 基于NGINX的微服務(wù)代理

該平臺是華為公司內(nèi)部使用的微服務(wù)開發(fā)部署運(yùn)行平臺,開發(fā)于2013年,用于公司內(nèi)部某電信業(yè)務(wù)。在這個業(yè)務(wù)系統(tǒng)中有大概400多個左右的微服務(wù),實例數(shù)量根據(jù)局點大小不一樣,一個典型的部署為800多個左右實例的規(guī)模。

整體架構(gòu)如下:

基于NGINX的微服務(wù)代理的平臺整體架構(gòu)

其中的Internal Router組件用來給開發(fā)者解決分布式架構(gòu)中的可靠傳輸問題:

  • 使用高性能nginx及其相應(yīng)的lua擴(kuò)展作為Internal Router,將Http服務(wù)接入
  • 使用RouteAgent負(fù)責(zé)注冊/注銷實例,更新IR的實例信息
  • 使用zookeeper作為注冊中心
  • 以Per-Host的方式部署在微服務(wù)所運(yùn)行的環(huán)境中

用這種方式構(gòu)建的微服務(wù)環(huán)境已經(jīng)在超過200個局點的生產(chǎn)環(huán)境下得到使用,整體運(yùn)行情況良好。但是隨著時間的推移,當(dāng)業(yè)務(wù)對敏捷的要求越來越大,而且容器的使用也越來越廣泛,這種方式帶來了一些問題:

  • 使用lua腳本擴(kuò)展注冊發(fā)現(xiàn),負(fù)載均衡,熔斷,降級,容錯,限流,但lua的擴(kuò)展性有一定的局限
  • 用RouteAgent負(fù)責(zé)服務(wù)的注冊以及每個NGINX上服務(wù)實例路由的刷新,RA需清楚地感知本節(jié)點上的微服務(wù)都有哪些,但是使用Kubernetes做容器調(diào)度后微服務(wù)和實例的分布信息在K8S里面集中記錄
  • 容器的IP更多,變化更頻繁,使用RouteAgent刷新NGINX路由的方式會導(dǎo)致NGINX服務(wù)受到影響,頻繁的路由刷新導(dǎo)致業(yè)務(wù)運(yùn)行收到影響
  • 當(dāng)IR服務(wù)失敗后,整個Host中的服務(wù)都會丟失,無法與外界建立聯(lián)系

為了解決這些問題,出現(xiàn)了第二代的解決方案: HSA Sidecar

HSA Sidecar設(shè)計

HSA是華為內(nèi)部的一套微服務(wù)開發(fā)框架,它提供了注冊中心,配置中心,java開發(fā)框架,以及SideCar等組件

  • 基于Java 微服務(wù)框架開發(fā),非侵入式通信方式,支持RPC與Http,提供SOAP協(xié)議轉(zhuǎn)換,但會導(dǎo)致性能下降
  • 與微服務(wù)部署在一個Pod中即Sidecar模式
  • 作為代理服務(wù),使微服務(wù)自動獲得注冊發(fā)現(xiàn),負(fù)載均衡,熔斷,降級,容錯限流等功能
  • 占用資源很高,一個應(yīng)用實例一個Sidecar實例的部署方式,會占用過高資源

雖然第一代的問題解決了,但是第二代的Sidecar在性能和資源占用上有很大的問題,在少量的技術(shù)項目中試用后,因為資源占用過高的問題無法在大規(guī)模環(huán)境中推廣使用。

CSE Mesher介紹

Service Mesh 模式的一種實現(xiàn)?;谧匝械腉o語言微服務(wù)框架(該框架即將開源)開發(fā),使用ServiceComb注冊中心(已經(jīng)開源)與CSE配置中心,以Sidecar的方式部署在微服務(wù)所運(yùn)行的環(huán)境中,也可以PerHost模式運(yùn)行。在用戶數(shù)據(jù)面使用,提供VM部署、公有云部署、容器部署,占用資源?。ㄩe置10多M,并發(fā)運(yùn)行時30多M)。

基本能力

注冊發(fā)現(xiàn)

注冊中心為插件化模塊,目前對接了ServiceComb、Service Center,未來還會有更多的系統(tǒng)對接進(jìn)來


可插件化的注冊中心

路由規(guī)則管理

根據(jù)預(yù)定義的路由規(guī)則對請求進(jìn)行引流

  • 支持權(quán)重引流:比如將5%的流量引到購物車的1.0版本,20%引到2.0版本
  • 可根據(jù)服務(wù)請求特征進(jìn)行引流:比如消費者的請求中Header帶有的用戶名為Json,那么可以引流到某個服務(wù)的特定版本中
  • 利用讀寫鎖,路由可在運(yùn)行時更新,并且不丟失請求

協(xié)議轉(zhuǎn)換與不同框架的對接與統(tǒng)一治理

使用標(biāo)準(zhǔn)OpenAPI契約,可以實現(xiàn)Dubbo RPC協(xié)議與Http協(xié)議的互轉(zhuǎn),用于透明地接入遺留的Dubbo應(yīng)用并對遺留應(yīng)用進(jìn)行統(tǒng)一的服務(wù)治理

使用負(fù)載均衡與重試策略

  • 負(fù)載均衡器會調(diào)用注冊中心插件進(jìn)行實例查詢
  • 在查詢中的實例里表中,使用Filter進(jìn)行過濾
  • 將過濾后的實例傳入Strategy中進(jìn)行實例選擇
  • 默認(rèn)提供RoundRobin Random,會話粘滯策略
  • 具備容錯能力且加入Backoff算法,增強(qiáng)網(wǎng)絡(luò)穩(wěn)定性

使用熔斷降級

熔斷使用的斷路器對一個執(zhí)行過程進(jìn)行包裝,斷路器負(fù)責(zé)監(jiān)控維護(hù)每個執(zhí)行過程的狀態(tài)、結(jié)果、錯誤、超時。當(dāng)達(dá)到一定閥值時就會熔斷,并觸發(fā)降級。以這樣的機(jī)制來保護(hù)服務(wù)提供者,不會出現(xiàn)級聯(lián)的雪崩式錯誤。

使用限流

提供了消費者端與提供者端限流

用戶可以通過配置來限制每秒只允許多少個請求被發(fā)出或者接受

對接監(jiān)控

Metrics:提供了主動上報到CSE Dashborad的方式。也可與華為公有云APM,Prometeus對接
分布式追蹤:對接Zipkin

架構(gòu)設(shè)計

整體架構(gòu)

CSE Mesher整體架構(gòu)

Mesher背靠CSE組件,使用微服務(wù)引擎中的服務(wù)中心與配置中心等服務(wù)作為控制面,Mesher與業(yè)務(wù)代碼部署在一起運(yùn)行在數(shù)據(jù)面

數(shù)據(jù)面

CSE Mesher數(shù)據(jù)面

即Service mesh組件本身,對所有請求進(jìn)行處理,它有以下功能

  • 發(fā)現(xiàn)服務(wù)
  • 執(zhí)行路由策略
  • 負(fù)載均衡
  • 攔截所有請求并處理,轉(zhuǎn)發(fā)
  • 認(rèn)證鑒權(quán)
  • 生成監(jiān)控數(shù)據(jù)

控制面

CSE Mesher控制面

為管理人員提供統(tǒng)一的管理入口,為所有運(yùn)行的mesher提供配置下發(fā)但不會介入服務(wù)請求

  • 注冊中心:服務(wù)上下線感知
  • 下發(fā)配置:使用Web Console對運(yùn)行時更改,負(fù)載均衡,熔斷容錯,限流等策略
  • 對接監(jiān)控服務(wù)與監(jiān)控頁面
  • 調(diào)度引擎:這里并非是微服務(wù)引擎提供的組件,是可選組件,這個組件負(fù)責(zé)拉起服務(wù),維護(hù)實例數(shù),在資源池中調(diào)度分配實例,這里推薦使用ServiceStage負(fù)責(zé)實例的生命周期管理

運(yùn)行場景

不同的部署方式

與業(yè)務(wù)服務(wù)部署在一起有3種運(yùn)行模式

1.僅消費者使用Mesher,提供者為使用ServiceComb開發(fā)框架的服務(wù)或者裸服務(wù),

下圖為例:

ServiceC為裸服務(wù),它既不用mesher也不用SDK,那么起碼它需要自己注冊到服務(wù)中心中,供其它服務(wù)發(fā)現(xiàn),否則無法進(jìn)行訪問。

僅消費者使用Mesher

2.消費者與提供者均使用Mesher

消費者與提供者均使用Mesher

以這種方式運(yùn)行的服務(wù)可以使用透明TLS傳輸,并且擁有了服務(wù)端限流

3.提供者使用Mesher,消費者A使用ServiceComb SDK進(jìn)行開發(fā)可直接發(fā)現(xiàn)服務(wù)B,但是消費者C作為裸服務(wù)需要自己發(fā)現(xiàn)服務(wù)B


僅提供者使用Mesher

運(yùn)行時請求處理

消費者端請求


消費者端請求

上圖為例:

SockShop服務(wù)將mesher作為代理并使用地址http://order/list訪問訂單服務(wù)

  1. Destination Resolver
    目標(biāo)微服務(wù)名解析,支持插件定制,可根據(jù)請求特征決定微服務(wù)名是什么
  2. Source Resolver
    將IP地址解析為微服務(wù)實體信息
  3. 路由決策
    根據(jù)Source和Destination 信息決定最終要訪問哪個微服務(wù)
  4. 處理鏈
    處理鏈為可隨時插入或減少的模塊,在這里Mesher實現(xiàn)了限流,熔斷,降級,負(fù)載均衡等功能
  5. 傳輸層
    最終請求通過傳輸層發(fā)送到目標(biāo)微服務(wù)實例
    提供者端接收請求


    提供者端接收請求流程

上圖為收到遠(yuǎn)程請求后的處理過程

  1. 服務(wù)端接到請求,將IP地址解析為微服務(wù)信息
  2. 進(jìn)入處理鏈,這一步并沒有負(fù)載均衡而是直接使用local selection 進(jìn)行處理

性能對比

Mesher1.0、Istio 0.1.6 (Envoy)、Linkerd1.1.3性能對比

在性能對比后,我聊下自己的看法

  • Linkerd 作為java實現(xiàn)的service mesh,受到資源占用的拖累,考慮到數(shù)據(jù)中心成本,不適合作為SideCar和應(yīng)用部署在一起,相信它的主要場景在于Kubernetes Ingress和Daemonset,并且由于只有數(shù)據(jù)面,需要和別的生態(tài)系統(tǒng)對接獲得控制面能力,否則,業(yè)務(wù)團(tuán)隊又要考慮自己開發(fā)控制面。
  • 目前Istio已知問題是每次請求都要調(diào)用一次Mixer API來傳送metric數(shù)據(jù),相信未來版本能夠解決,但不能滿足我們內(nèi)部的產(chǎn)品節(jié)奏。
  • 作為對比,Mesher通過Channel與Go協(xié)程機(jī)制主動上報metric數(shù)據(jù),以此獲得更高的性能,機(jī)制如下:模塊將數(shù)據(jù)傳送到channel中,協(xié)程收到信號并主動上報,在這樣的機(jī)制下開啟監(jiān)控,性能只有百分之2左右的下降。


    Metric數(shù)據(jù)上報機(jī)制

一些思考以及未來

華為為什么開發(fā)了自己的Service Mesh

  • Istio的性能問題沒有解決,Envoy每次訪問請求Mixer API導(dǎo)致性能下降
  • Istio強(qiáng)綁定Kubernetes平臺(1.7.4+),雖然有著良好的架構(gòu),對接不同平臺不是問題但需要時間,Mesher貫徹不將開發(fā)者綁定到任何框架和平臺的理念
  • 從成本角度講Linkerd并不適合做SideCar部署,JVM資源占用較多
  • 過去在ServiceComb中的積累:Service center,Config center,Go SDK,Governance UX已經(jīng)提供了大量技術(shù)積累,可用于做Mesher的控制面。
  • 既然非侵入式與侵入式都不是銀彈,侵入式(ServiceComb Java)與Mesher提供的非侵入式框架的無縫結(jié)合,混編就變得有價值了,開發(fā)者可以因地制宜,選擇適合自己的方案。

Service Mesh是個大舞臺

現(xiàn)在已經(jīng)出現(xiàn)了越來越多的Service mesh實現(xiàn):

  • 數(shù)據(jù)面:Linkerd,Nginx,Envoy
  • 控制面:Istio

Linkerd 是在2016年出現(xiàn)的,Envoy在6個月后出現(xiàn),不過Envoy已經(jīng)在2015年就商用了。這兩個項目也是最有名的Service Mesh。

Istio在2017年5月出現(xiàn),它提供了控制面,并使用Envoy作為數(shù)據(jù)面的Service Mesh。目前已經(jīng)開始有些Service Mesh提供者宣布與Istio進(jìn)行集成,比如Linkerd和Nginx。這意味著控制面與數(shù)據(jù)面是解耦的,任何的控制面都可以和數(shù)據(jù)面Service Mesh進(jìn)行集成。CSE Mesher也會考慮與Istio進(jìn)行集成,成為除了Envoy之外的另一種數(shù)據(jù)面選擇。

實際上在開源項目之外,很多公司內(nèi)部也早已用類似的方案進(jìn)行自己系統(tǒng)的構(gòu)建,各自有各自的特點用來解決自己的實際問題。Istio成為CNCF里面一個被認(rèn)為是“Kubernetes之后的第二個爆款”是有理由的,它提供了一種從平臺的角度解決應(yīng)用架構(gòu)的思路,進(jìn)一步簡化了應(yīng)用的開發(fā)。我們也相信在這個大舞臺上會有更多的方案出現(xiàn),而這些方案的出現(xiàn)也會讓微服務(wù)和Cloud Native應(yīng)用的構(gòu)建方式有更多地選擇。

我們團(tuán)隊也已經(jīng)基于多年的實踐經(jīng)驗將當(dāng)前的內(nèi)部Service Mesh方案包含在華為云的“微服務(wù)引擎”中,開放給外部用戶使用。希望可以作為一種參考,可以給正在選擇實施微服務(wù)架構(gòu)方案的讀者一些幫助。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容