Service Mesh 在華為公有云的實踐

GitChat的部落格發表於2018-04-12

Service Mesh 作為新興概念,受到了廣泛的關注,目前已經在華為公有云中上線,正式商用。我將會圍繞 Service Mesh,講解 Service Mesh 的技術演進,以及架構與內部工作機制。我將講述如何實現一個 Service Mesh、如何不改一行程式碼就將一個應用變為雲原生的微服務,以及對比目前流行的 Istio,Linkerd,Envoy 等實現。

我們在構建微服務而構建微服務是困難的

微服務是一個很大的概念,從團隊組織到最佳實踐似乎都有實施微服務的一些指導。我們這裡只提構建微服務的架構模式,也就是關乎到你用什麼樣的方式來構建你以微服務架構來組織的應用系統。

近些年隨著微服務的火熱,越來越多的團隊開始進行實踐,將微服務紛紛落地,也許你是從0開始,一步步地完成了單體應用向微服務的轉型,讓我們來看看,你解決了多少問題。

enter image description here

我相信最難的部分之一就是呼叫你的服務。

微服務將原本記憶體中函式的呼叫轉換為網路中的呼叫後,就牽扯到這些問題,而任何一個分支展開,都會涉及一系列的問題。業務開發者也許真的有精力去學習架構相關的複雜問題,然而對於公司來說,真正有價值的是業務本身,讓業務開發者解決這些問題需要花費浪費大量的時間精力,導致業務上線受到影響。那我們來看看是否有便捷的方式來解決業務開發者的痛點。

Chassis模式

一句話來概括:一種語言開發框架來作為微服務開發的底座,封裝掉複雜性,幫助你解決跨網路帶來的問題,讓使用者聚焦在上層業務邏輯的開發。通常情況下會實現以下功能:

  • 日誌、Metrics、分散式追蹤資料上報

  • 健康檢查

  • 對接統一的配置中心實現動態配置

  • 對接註冊中心

  • 實現負載均衡、熔斷降級、容錯、限流等保證高可靠執行的功能

現在我們來看看業界有哪些可用的Chassis框架:

  • Spring Cloud

  • ServiceComb

  • Dubbo

  • Go-Micro

  • Go-Kit

先不細去糾結微服務的嚴格定義,也先暫且擱置諸如“某些老舊框架是否是真的微服務框架”這類爭議,從實現方式來看,上述服務化框架都是將分散式系統開發的複雜性進行了一定程度的封裝然後提供了簡便的開發介面供使用者呼叫。但是,用這種方式構建微服務還有一些問題:

  • 多語言SDK支援:微服務提倡不同元件使用最適合它的語言開發,但是這需要每種語言都有開發框架,不斷實現相同的功能。上面可以看到只有go語言和Java語言出現了微服務開發框架,其他語言呢?

  • 不論程式碼侵入程度,都需要開發者思考如何與SDK結合,並從程式碼層面做出改變,對於大部分開發者來說都是一個高曲線的學習過程。

  • 繫結了特定技術棧,不容易改造。

  • 老舊單體應用由於無人維護,耦合程度高等問題無法進行改造,在進行微服務拆分的過程中重用遺留程式碼變得無比困難。而且微服務的拆分難以分步進行,需要一個相對較長的週期將系統整體拆分後才能上線。

我們知道技術演進來自於在實踐中不斷地將功能抽象,解耦,封裝,服務化。

  • 雲端計算技術出現前是資料中心虛擬化,不斷地實踐使技術發展形成理論和新的實踐。IaaS是一種封裝,如今開發者與大部分技術團隊不需要再學習虛擬化等技術以及如何維護資料中心。

  • 沒有TCP/IP的時代,開發人員需要自己考慮網路間資料包的傳輸,以及網路傳輸程式碼與業務程式碼完全耦合的問題,如今,開發者已經不需要關心,作業系統和開發語言已經封裝好網路傳輸過程。

是否也可以把語言框架提供的能力抽象,成為服務?很多問題是開放性的解法,上學時大家體會很深一道難題會有很多解法。

在引入後面內容前,我先介紹下SideCar模式。

SideCar模式

  • 在近些年受到Kubernetes對容器排程方式的啟示而日漸受到關注的一種功能部署模式,也是一種微服務的設計模式。

  • 主要利用了容器可以共享儲存與網路的能力,或者說在一個Host中,這個模式也同樣適用。

  • 一般分為應用容器和工具容器,工具容器可以重用。

一個典型的場景如下:

enter image description here

應用容器與日誌同步工具在同一個Pod下,共享儲存卷,應用程式生成的日誌檔案會由日誌同步工具收集併傳送到類似kafka,elasticsearch這樣服務中。

在這樣的架構下我們獲得了什麼呢?

  • 以容器作為基礎打包單元,那麼就可以分給不同的團隊進行開發測試

  • Sidecar容器可重用,可以與不同的容器結合

  • 以容器作為錯誤邊界,使服務能夠獨立開發和測試,比如應用服務在沒有日誌儲存功能的情況下也可以獨立執行

  • 獨立回滾與更新,但需要考慮複雜的版本組合,建議使用語義版本管理對版本進行控制

我們知道侵入式框架是在L7去解決微服務呼叫,管理,監控的問題,那麼是否我們可以將這部分抽象出來,在L5層解決呢。

enter image description here

在這個模式的基礎和思路之下,我們引入了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.

大致的意思如下:

  • 一種基礎設施層,服務間的通訊通過service mesh進行

  • 可靠地傳輸複雜拓撲中服務的請求,將它們變成現代的雲原生服務

  • 一種網路代理的實現,通常與業務服務部署在一起,業務服務不感知

  • 一種網路模型,在TCP/IP之上的抽象層,TCP/IP負責將位元組碼可靠地在網路節點間傳遞,Service mesh則複雜將服務間的協議請求可靠地在服務間進行傳輸。它們不關心傳輸的內容

  • TCP/IP僅僅負責傳輸,但Service mesh可對執行時進行控制,使服務變得可監控,可管理。

    enter image description here

為什麼使用Service Mesh

  • 無需考慮每種語言都要解決的問題

  • 對業務程式碼0侵入,開發者無需關心分散式架構帶來的複雜性以及引入的技術問題

  • 對於不適合改造的老舊單體應用,提供了一種接入分散式環境的方式

  • 微服務化的程式通常不是一蹴而就的,很多應用選擇了演進的方式,就是將單體應用一部分一部分地進行拆分。而在這個過程中,使用Service Mesh就可以很好地保證未拆分的應用與已經拆分出來的微服務之間的互通和統一治理

  • 開發出的應用既是雲原生的又具有獨立性,不將業務程式碼與任何框架,平臺或者服務繫結

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

  • Service Mesh元件代理請求轉發,會在一定程度上降低系統通訊效能

  • 侵入式框架以原始碼和業務程式碼結合,有較強定製和擴充套件能力,Service mesh相對不易定製擴充套件

  • 在執行時,依賴單獨的Service Mesh代理,多了一個故障點。整個系統的執行和運維也強依賴於Service Mesh元件的能力

Service Mesh的實踐歷程和設計思路

Service Mesh在華為公司內部的發展歷程

第一代: 基於NGINX的微服務代理

該平臺是華為公司內部使用的微服務開發部署執行平臺,開發於2013年,用於公司內部某電信業務。在這個業務系統中有大概400多個左右的微服務,例項數量根據局點大小不一樣,一個典型的部署為800多個左右例項的規模。

整體架構如下:

enter image description here

其中的Internal Router元件用來給開發者解決分散式架構中的可靠傳輸問題:

  • 使用高效能nginx及其相應的lua擴充套件作為Internal Router,將Http服務接入

  • 使用RouteAgent負責註冊/登出例項,更新IR的例項資訊

  • 使用zookeeper作為註冊中心

  • 以Per-Host的方式部署在微服務所執行的環境中

用這種方式構建的微服務環境已經在超過200個局點的生產環境下得到使用,整體執行情況良好。但是隨著時間的推移,當業務對敏捷的要求越來越大,而且容器的使用也越來越廣泛,這種方式帶來了一些問題:

  • 使用lua指令碼擴充套件註冊發現,負載均衡,熔斷,降級,容錯,限流,但lua的擴充套件性有一定的侷限

  • 用RouteAgent負責服務的註冊以及每個NGINX上服務例項路由的重新整理,RA需清楚地感知本節點上的微服務都有哪些,但是使用Kubernetes做容器排程後微服務和例項的分佈資訊在K8S裡面集中記錄

  • 容器的IP更多,變化更頻繁,使用RouteAgent重新整理NGINX路由的方式會導致NGINX服務受到影響,頻繁的路由重新整理導致業務執行收到影響

  • 當IR服務失敗後,整個Host中的服務都會丟失,無法與外界建立聯絡

為了解決這些問題,出現了第二代的解決方案: HSA Sidecar。

enter image description here

HSA是華為內部的一套微服務開發框架,它提供了註冊中心,配置中心,java開發框架,以及SideCar等元件。

  • 基於Java 微服務框架開發,非侵入式通訊方式,支援RPC與Http,提供SOAP協議轉換,但會導致效能下降

  • 與微服務部署在一個Pod中即Sidecar模式

  • 作為代理服務,使微服務自動獲得註冊發現,負載均衡,熔斷,降級,容錯限流等功能

  • 佔用資源很高,一個應用例項一個Sidecar例項的部署方式,會佔用過高資源

雖然第一代的問題解決了,但是第二代的Sidecar在效能和資源佔用上有很大的問題,在少量的技術專案中試用後,因為資源佔用過高的問題無法在大規模環境中推廣使用。

CSE Mesher

Service Mesh 模式的一種實現。基於自研的Go語言微服務框架(該框架即將開源)開發,使用ServiceComb註冊中心(開源)與CSE配置中心,以Sidecar的方式部署在微服務所執行的環境中,也可以PerHost模式執行。在使用者資料面使用,提供VM部署、公有云部署、容器部署,佔用資源小(閒置10多M,併發執行時30多M)。

基本特性

註冊發現

註冊中心為外掛化模組,目前對接了ServiceComb Service Center,未來還會有更多的系統對接進來。我個人是Eureka的深入實踐者,相比Eureka解決了簡單的註冊發現(雖然非常輕量,但是大量配置需要調教),Service center提供了大量的特性來支撐更好地治理管理你的微服務,並與Promethues整合,提供自身的執行時Metric監控。

enter image description here

路由規則管理

根據預定義的路由規則對請求進行引流:

  • 支援權重引流:比如將5%的流量引到購物車的1.0版本,20%引到2.0版本

  • 可根據服務請求特徵進行引流:比如消費者的請求中Header帶有的使用者名稱為Json,那麼可以引流到某個服務的特定版本中

  • 利用讀寫鎖,路由可在執行時更新,並且不丟失請求

多協議支援,協議轉換,不同框架的對接與統一治理

  • 使用標準OpenAPI契約,可以實現Dubbo RPC協議與Http協議的互轉,用於透明地接入遺留的Dubbo應用並對遺留應用進行統一的服務治理

  • 任意協議請求都被抽象為Invocation模型進行處理,最終再轉換為協議請求轉發

    enter image description here

使用負載均衡與重試策略

  • 負載均衡器會呼叫註冊中心外掛進行例項查詢

  • 在查詢中的例項裡表中,使用Filter進行過濾

  • 將過濾後的例項傳入Strategy中進行例項選擇

  • 預設提供RoundRobin Random,會話粘滯策略

  • 具備容錯能力且加入Backoff演算法,增強網路穩定性

使用熔斷降級

熔斷使用的斷路器對一個執行過程進行包裝,斷路器負責監控維護每個執行過程的狀態、結果、錯誤、超時。當達到一定閥值時就會熔斷,並觸發降級。以這樣的機制來保護服務提供者,不會出現級聯的雪崩式錯誤。服務雪崩效應是一種因 服務提供者 的不可用導致 服務呼叫者 的不可用,並將不可用 逐漸放大 的過程.如果所示:

enter image description here

使用限流

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

使用者可以通過配置來限制每秒只允許多少個請求被髮出或者接受。

對接監控

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

分散式追蹤:對接Zipkin。

架構設計

整體架構

enter image description here

  • Mesher背靠CSE元件,使用其中的服務中心與配置中心等服務作為控制面
  • Mesher則與業務程式碼部署在一起執行在資料面
  • 監控方面則對接開源方案及華為公有云APM
  • 不繫結任何基礎設施層,可在任何地方進行部署

資料面

enter image description here

即Service mesh元件本身,對所有請求進行處理,它有以下功能:

  • 發現服務

  • 執行路由策略

  • 負載均衡

  • 攔截所有請求並處理,轉發

  • TLS透明傳輸

  • 生成監控資料

控制面

enter image description here

為管理人員提供統一的管理入口,為所有執行的mesher提供配置下發但不會介入服務請求

  • 註冊中心:服務上下線感知

  • 下發配置:使用Web Console對執行時更改,負載均衡,熔斷容錯,限流等策略

  • 對接監控服務與監控頁面

  • 排程引擎:這裡並非是微服務引擎提供的元件,是可選元件,這個元件負責拉起服務,維護例項數,在資源池中排程分配例項

執行場景

與業務服務部署在一起有3種執行模式:

  • 僅消費者使用Mesher,提供者為使用ServiceComb開發框架的服務或者裸服務

    enter image description here

    ServiceC為裸服務,它既不用mesher也不用SDK,那麼起碼它需要自己註冊到服務中心中,供其它服務發現,否則無法進行訪問。

  • 消費者與提供者均使用Mesher

    enter image description here

    以這種方式執行的服務可以使用透明TLS傳輸,並且擁有了服務端限流。

  • 提供者使用Mesher,消費者A使用ServiceComb SDK進行開發可直接發現服務B,但是消費者C作為裸服務需要自己發現服務B

    enter image description here

效能對比

enter image description here

在效能對比後,我聊下自己的看法:

  • Linkerd 作為java實現的service mesh,受到資源佔用的拖累,考慮到資料中心成本,不適合作為SideCar和應用部署在一起,相信它的主要場景在於Kubernetes Ingress和Daemonset,並且由於只有資料面,需要和別的生態系統對接獲得控制面能力,否則,業務團隊又要考慮自己開發控制面。

  • 目前Istio已知問題是每次請求都要呼叫一次Mixer API來傳送metric資料,相信未來版本能夠解決,但不能滿足我們內部的產品節奏。

  • 作為對比,Mesher通過Channel與Go協程機制主動上報metric資料,以此獲得更高的效能,機制如下:模組將資料傳送到channel中,協程收到訊號並主動上報

enter image description here

一些思考以及未來

華為為什麼開發了自己的Service Mesh

  • Istio的效能問題沒有解決,Envoy每次訪問請求Mixer API導致效能下降。

  • Istio強繫結Kubernetes平臺(1.7.4+),雖然有著良好的架構,對接不同平臺不是問題但需要時間,Mesher貫徹不將開發者繫結到任何框架和平臺的理念。

  • 從成本角度講Linkerd並不適合做SideCar部署,JVM資源佔用較多,他的未來場景可能是在Daemonset模式裡,但是升級卻必然會導致例項的失聯,目前定位確實比較尷尬,他們提出Service Mesh的概念,現在最火爆的卻是Istio,有點像Google提出雲端計算,最大受益者是AWS一樣。

  • 過去在ServiceComb中的積累:Service center,Config center,Go SDK,Governance UX已經提供了大量技術積累,可用於做Mesher的控制面。

  • 既然非侵入式與侵入式都不是銀彈,侵入式(ServiceComb Java)與Mesher提供的非侵入式框架的無縫結合,混編就變得有價值了,開發者可以因地制宜,選擇適合自己的方案。對於Java,Go語言可以使用CSE的開發框架,而其餘語言的接入則可以利用Mesher。

Service Mesh是個大舞臺

現在已經出現了越來越多的Service mesh實現:

  • 資料面:Linkerd,Nginx,Envoy

  • 控制面:Istio

Linkerd 是在2016年出現的,Envoy在6個月後出現,不過Envoy已經在2015年就商用了。這兩個專案也是最有名的Service Mesh。

Istio在2017年5月出現,它提供了控制面,並使用Envoy作為資料面的Service Mesh。目前已經開始有些Service Mesh提供者宣佈與Istio進行整合,比如Linkerd和Nginx。這意味著控制面與資料面是解耦的,任何的控制面都可以和資料面Service Mesh進行整合。CSE Mesher也會考慮與Istio進行整合,成為除了Envoy之外的另一種資料面選擇。

實際上在開源專案之外,很多公司內部也早已用類似的方案進行自己系統的構建,各自有各自的特點用來解決自己的實際問題。Istio成為CNCF裡面一個被認為是“Kubernetes之後的第二個爆款”是有理由的,它提供了一種從平臺的角度解決應用架構的思路,進一步簡化了應用的開發。我們也相信在這個大舞臺上會有更多的方案出現,而這些方案的出現也會讓微服務和Cloud Native應用的構建方式有更多地選擇。

我們團隊也已經基於多年的實踐經驗將當前的內部Service Mesh方案包含在華為雲的微服務引擎中,開放給外部使用者使用。

如何用mesher在2分鐘內便快速地將2個普通的Rest 服務變為雲原生的微服務,並彼此呼叫。視訊中的樣例程式碼都可以在這找到。

Takes away


本文首發於GitChat,未經授權不得轉載,轉載需與GitChat聯絡。

閱讀全文: http://gitbook.cn/gitchat/activity/5a1e5e255dc9624efbe0131b

一場場看太麻煩?成為 GitChat 會員,暢享 1000+ 場 Chat !點選檢視

相關文章