1. 程式人生 > >胡忠想|微博微服務架構的Service Mesh實踐之路

胡忠想|微博微服務架構的Service Mesh實踐之路

前言

說到Service Mesh,在如今的微服務領域可謂是無人不知、無人不曉,被很多人定義為下一代的微服務架構

Service Mesh在誕生不到兩年的時間裡取得令人矚目的發展,在國內外都湧現出一批具有代表性的新產品,最著名的莫過於GoogleIBM領導的Istio,也是Service Mesh技術的代表之作。

而國內在這一方面也不遑多讓,秉承了Service Mesh的思想也走出了各自的實踐之路,並且已經開始在線上的核心業務中大規模使用,比如微博的Weibo Mesh華為公有云Service Mesh以及螞蟻金服的SOFA Mesh等。

今天我就來帶給大家詳細介紹下微博的微服務架構是如何一步步走向Service Mesh之路的

跨語言服務呼叫的需求

微博最早服務化框架採用的是自研的Motan,Motan誕生於2013年,出於微博平臺業務單體化架構拆分為微服務改造的需求,在結合當時的開源服務化框架和自身實際的需求,選擇了採用自研的方式。

而且由於微博平臺的業務採用的是Java語言開發,所以Motan早期只支援Java語言。後期隨著微博業務的高速發展,越來越多的PHP業務開始登上舞臺,於是在微博的流量體系中。

主要是三股服務之間的相互呼叫:

一個是Java與Java語言,一個是PHP和Java語言,一個是PHP和PHP語言

Java應用之間的呼叫採用的是Motan協議,而Java應用與PHP、PHP與PHP應用之間採用的都是HTTP協議

我回憶了一下當時一次PHP與Java之間的HTTP呼叫過程,大致需要經過DNS解析、四層LVS負載均衡、七層Nginx負載均衡,最後才能呼叫Java應用本身。

bc5712b39d1d999453dc3ea67ee1a5356114cb22

從上面這張圖可以看出,一次HTTP呼叫的鏈路相當長,從我的實踐來看,經常會遇到好幾個問題。

第一個問題:中間鏈路損耗大

由於一次HTTP呼叫要經過DNS、LVS、Nginx這三個基礎設施,每一層都會帶來相應的損耗。

我曾經在線上就碰到過因為DNS解析延遲、LVS頻寬打滿引起的網路延遲,以及Nginx本地磁碟寫滿引起的轉發延遲等各種情況,造成介面響應在中間鏈路的損耗甚至超過了介面本身業務邏輯執行的時間。

第二個問題:全鏈路擴容難

由於微博業務經常要面臨突發熱點事件帶來的流量衝擊,所以需要能夠隨時隨地動態擴縮容。

其實在應用本身這一層擴容並不是難點,比較麻煩的是四七層負載均衡裝置的動態擴縮容,它涉及如何評估容量、如何動態申請節點並及時修改生效等,要完成一次全鏈路擴容的話,複雜度非常高。

所以最後往往採取的辦法是給四七層負載均衡裝置預備足夠的冗餘度,在峰值流量到來時,只擴容應用本身。

第三個問題:混合雲部署難

微博的業務目前採用的是混合雲部署,也就是在內網私有云和公有云上都有業務部署,同樣也需要部署四七層負載均衡裝置。

並且要支援公有云上的請求經過DNS解析後要能夠轉發到公有云上的負載均衡裝置上去,避免跨專線訪問帶來不必要的網路延遲和專線頻寬佔用。

因此,迫切需要一種支援跨語言呼叫的服務化框架,使得跨語言應用之間的呼叫能夠像Java應用之間的呼叫一樣,不需要經過其他中間鏈路轉發,做到直接互動,就像下圖描述的那樣。

60f4b37180eb72c8d8d3aecfb0e9dd08769d2115

Yar協議的初步嘗試

為此,微博最開始考慮基於Motan框架進行擴充套件,使其支援PHP語言的Yar協議,下面是擴充套件後的架構圖。

5566b29e52f18dfc1168e90b81e703d80f866946

這個架構的思路是PHP客戶端的服務發現通過Nginx來支援經過Nginx把PHP的Yar協議請求轉發給服務端

由於Motan框架中了適配Yar協議,服務端會把PHP的Yar協議請求轉換成Motan請求來處理,處理完後再轉成Yar協議的返回值經過Nginx返回給客戶端。

但這種架構主要存在兩個問題

第一個問題:Motan協議與Yar協議在基本資料結構和序列化方式的支援有所不同,需要經過複雜的協議轉換。

第二個問題:服務呼叫還必須依賴Nginx,所以呼叫鏈路多了一層,在應用部署和擴容時都要考慮Nginx。

gRPC會是救命稻草嗎

時間往後推演,gRPC橫空出世,它良好的跨語言特性,以及高效的序列化格式的特性吸引了我們,於是便開始考慮在Motan中整合gRPC,來作為跨語言通訊的協議。

當時設計了下圖的架構,這個架構的思路是利用gRPC來生成PHP語言的Client然後在Motan框架中加入對gRPC協議的支援,這樣的話PHP語言的Client就可以通過gRPC請求來呼叫Java服務。

8343303fde6850427f5cbf14f9f7e5f11aaa2963

但在我們的實際測試中,發現微博的業務場景並不適合gRPC協議,因為gRPC協議高度依賴PB序列化,而PHP對PB的相容性不是很好,在微博的業務場景下一個介面返回值有可能超過幾十KB。

此時在PHP Client端PB資料結構解析成JSON物件的耗時甚至達到幾十毫秒,這對業務來說是不可接受的。

而且gRPC當時還不支援PHP作為Server對外提供服務,也不滿足微博這部分業務場景的需要。

代理才是出路

考慮到PHP語言本身沒有常駐記憶體控制的能力,在實現服務註冊和發現以及其他各種服務框架功能時,僅靠PHP-FPM程序本身難以實現,因此需要一個統一常駐記憶體的程序來幫助完成服務框架的各種功能

一開始我們考慮過使用本地守護程序OpenResty的Timer來實現服務發現,但其他服務框架的功能不太好實現,比如專欄前面提到的各種複雜的負載均衡策略、雙發、熔斷等。

為此,我們希望通過一個Agent也就是代理,來幫助PHP程序來完成服務框架的各種功能,PHP程序本身只需要負責執行業務邏輯的程式碼,以及最簡單的Motan協議解析。

基於這個思路,當時我們設計了下面這個架構,它的思路就是在PHP程序的本地也部署一個Agent,PHP程序發出去的請求都經過Agent進行處理後,再發給對應的Java應用。

765411764f9dd21fe28bd108846087970ca07899

向Service Mesh邁進

2017年,就在我們開始採用Agent方案對業務進行改造,以支援PHP應用呼叫Java應用服務化的時候,Service Mesh的概念突然火熱起來,並隨著Istio的釋出風靡業界。

相信經過我前面對Service Mesh的講解,你一定會發現這裡的Agent不恰恰就是Service Mesh中的SideCar嗎?

沒錯,我們跨語言呼叫的解決方案竟然與Service Mesh的理念不謀而合

借鑑Service Mesh的思想,我們也對Agent方案進一步演化,不僅客戶端的呼叫需要經過本地的Agent處理後再轉發給服務端,服務端在處理前也需要經過本地的Agent,最後再由服務端業務邏輯處理,下面是它的架構圖。

bf7c5ec280a0aa70cef06678754223c1fee6510c

如此一來,業務只需要進行整合最簡單的Motan協議解析,而不需要關心其他服務框架功能,可以理解為業務只需要整合一個輕量級的Client用於Motan協議解析,而繁雜的服務框架功能全都由Agent來實現,從而實現業務與框架功能的解耦。

Motan-go Agent

考慮到Motan-go Agent要與PHP程序部署在一起,為了減少對本機資源的佔用,這裡Motan-go Agent採用了Go語言來實現,它包含的功能模組請看下圖。

6739bf79d16512688839733164fe8ca9527848c0

我們拆解一下圖中Motan-go Agent主要的模組,看看它們的作用是什麼。

Filter Chain模組是以請求處理鏈的組合方式,來實現AccessLog(請求日誌記錄)、Metric(監控統計)、CircuitBreaker(熔斷)、Switcher(降級)、Tracing(服務追蹤)、Mock(單元測試)、ActiveLimit(限流)等功能。

0f865e3dbf122fd9e7d6f1cb2929aca5bcb7ef7e

High Available模組是用來保證高可用性,預設集成了Failover、Backup Request等故障處理手段。

Load Balance模組負載均衡,預設集成了Random、Roundrobin等負載均衡演算法。

EndPoint模組的作用是封裝請求來呼叫遠端的Server端,預設可以封裝Motan請求和gRPC請求。

Serialize模組負責實現不同型別的序列化方式,預設支援Simple序列化。

Server模組實現不同型別的Server,要麼是採用Motan協議實現,要麼是採用gRPC協議。

Motan-go Agent每個模組都是功能可擴充套件的,你可以在Filter Chain模組加上自己實現的Trace功能,這樣請求在經過Filter Chain處理時,就會自動載入你加上的Trace功能。

當然,你也可以在High Available模組新增自己實現的故障處理手段,在Load Balance模組裡實現自己的負載均衡演算法,在EndPoint模組封裝HTTP協議的請求,在Serialize模組新增PB序列化,在Server模組實現HTTP協議等。

另外Motan-go Agent之間的通訊採用的是自定義的Motan2協議,它把請求中的Meta資訊與請求引數資訊進行了分離,更適合對請求進行代理轉發,並且預設使用了Simple序列化來對不同語言的資料進行編碼,以實現跨語言服務通訊。

更多關於Motan2協議和Simple序列化的介紹,你可以點選這裡檢視。

統一服務治理中心

在Weibo Mesh中是通過統一服務治理平臺與Motan-go Agent互動來實現服務治理功能的。

對著下面這張Weibo Mesh的架構圖,我們一起看一下統一服務治理平臺SGCenter具體是如何與Motan-go Agent互動,來實現服務治理的各項功能的。

8446a4ed3531cc55497f9dffbf119e74a1230753

1.動態服務註冊與發現

首先來看下統一服務治理平臺是如何實現服務註冊與發現的。

如下圖所示,在Motan-go Agent中實現了具體的服務註冊與發現的邏輯,Server端程序啟動時,會通過Motan-go Agent向Vintage註冊中心發起註冊請求,把服務註冊到Vintage中。

Client端發起服務呼叫時,會經過Motan-go Agent轉發,Motan-go Agent會呼叫Vintage查詢該服務在Vintage中的註冊資訊,獲取到服務節點列表後,按照某一種負載均衡演算法選擇一個服務節點,向這個服務節點發起呼叫。

可以通過統一服務治理平臺SGCenter,呼叫Vintage的管理介面,執行新增或者刪除服務節點等操作,Motan-go Agent會感知到服務節點的變化,獲取最新的服務節點。

一般在業務開發或者運維人員需要手工擴容或者縮容一批服務節點時,才會執行這個操作。

87bfbf31a090748575f84411bd73cd50ca5aa2a1

2.監控上報

再看下面這張圖,Client端發起的請求經過Motan-go Agent轉發時,Motan-go Agent就會在記憶體中統計每一次呼叫的耗時、成功率等資訊。

並且每隔固定的時間間隔將這段時間內各個服務呼叫的QPS、平均耗時、成功率以及P999等metric資訊傳送給Graphite監控系統。

這樣的話,通過SGCenter呼叫Graphite的Web API就可以獲取到服務呼叫的資訊了。

68a3cef66709c2df639bb97cff4e50d64966a9a9

3.動態流量切換與降級

動態流量切換與降級的過程請看下面這張圖。

Motan-go Agent在查詢Vintage中某個服務節點資訊的同時也會訂閱該服務的變更,這樣的話就可以通過SGCenter向Vintage下發服務的切流量或者降級指令。

訂閱了這個服務的Motan-go Agent就會收到變更通知,如果是切流量指令,比如把呼叫永豐機房服務的流量都切換到土城機房,那麼Motan-go Agent就會把原本發給永豐機房的請求都發給土城機房。

如果是降級指令,Motan-go Agent就會停止呼叫這個服務。

711924022079efbcb65e7e7a70a66c71bc019920

4.自動擴縮容

服務呼叫時Motan-go Agent會把Server端服務呼叫的監控資訊上報給Graphite監控系統,同時Diviner容量評估系統會實時呼叫Graphite以獲取服務在不同區間的QPS資訊以計算服務池的水位線。

然後SGCenter會每隔一段時間呼叫Diviner來獲取各個服務池的冗餘度以決定是否需要擴容。

假如此時服務池的冗餘度不足的話,SGCenter就會呼叫DCP容器運維平臺給服務池進行擴容,DCP完成擴容後新的服務節點就會註冊到Vintage當中,這樣的話訂閱了該服務的Motan-go Agent就會感知到服務節點的變化。

從Vintage中獲取最新的服務節點資訊,這就是一個服務自動擴縮容的整個流程,你可以參考下面這張圖。

2db21ba0c9d83270613e97042173428bbb5bd843

Weibo Mesh的收益

經過前面的講解,相信你已經對Weibo Mesh的實現方案有了一定的瞭解。Weibo Mesh是在微博的業務場景下,一步步進化到今天這個架構的,它給微博的業務帶來的巨大的收益,總結起來主要有以下幾點:

 ●  跨語言服務化呼叫的能力

Weibo Mesh發展之初最首要的目的,就是想讓微博內部的Motan服務化框架能夠支援PHP應用與Java應用之間呼叫,因而開發了Motan-go Agent,並在此基礎上演變成今天的Weibo Mesh。

支援多種語言之間的服務化呼叫,有助於統一公司內部業務不同語言所採用的服務化框架,達到統一技術體系的目的。

 ●  統一服務治理能力

以微博應對突發熱點事件帶來的峰值流量衝擊為例,為了確保首頁資訊流業務的穩定性,我們有針對性的研發了自動擴縮容系統。

而隨著微博的不斷髮展,不斷湧現出新的業務線,比如熱門微博和熱搜,也同樣面臨著突發熱點事件帶來的流量衝擊壓力。

而開發一套穩定可用的自動擴縮容系統並非一朝一夕之事,如何能夠把資訊流業務研發的自動擴縮容系統推廣到各個業務線,是個比較棘手的問題。

因為資訊流業務的後端主要採用了Java語言實現,而熱門微博和熱搜主要採用的是PHP語言,無法直接接入自動擴縮容系統。

而Weibo Mesh可以支援多種語言,將熱門微博和熱搜業務進行服務化改造,就可以統一接入到自動擴縮容系統,實現了公司級的統一服務治理能力。

 ●  業務無感知的持續功能更新能力

採用Motan或者Dubbo類似的傳統服務化框架,一旦服務框架功能有升級就需要業務同步進行程式碼升級,這對大部分業務來說都是一種不願承受的負擔。

而採用Weibo Mesh,新增新功能只需要升級Motan-go Agent即可,業務程式碼不需要做任何變更,對於業務開發人員更友好。

尤其是作為公司級的服務化框架時,服務框架的升級如果跟業務系統升級繫結在一起,從我的實踐經驗來看,將是一件耗時費力的工作,需要協調各個業務方配合才能完成。

而Weibo Mesh可以看作是伺服器上部署的基礎元件,它的升級與維護不需要各個業務方的參與,這樣才能具備作為公司級的服務化框架推廣到各個業務線的前提。

Weibo Mesh的發展規劃

在微博的業務場景下,存在大量服務對快取、資料庫以及訊息佇列等資源的呼叫,如果把資源也看作是一種服務

那麼Weibo Mesh不僅可以管理服務與服務之間的呼叫,還可以管理服務與資源之間的呼叫,這樣的話Weibo Mesh強大的服務治理能力也能延伸到對資源的治理上,對業務來說又將解決資源治理這一大難題。

另一方面,隨著Weibo Mesh治理的服務越來越多,收集的資料也越來越多,利用這些資料可以挖掘一些更深層次的東西,也是Weibo Mesh未來的發展方向之一。

比如,引入機器學習演算法,對採集的資料進行分析,進行監控報警的優化等。

2058414eb6f204e40d4b4f8b81002241806c64be

總結

從微博一步步走向Service Mesh之路的過程,你可以看出微博的Weibo Mesh並不是一開始就是設計成這樣的,它是隨著業務的發展,對跨語言服務呼叫的需求日趨強烈,才開始探索如何使得原有僅支援Java語言的服務化框架Motan支援多語言。

在這個過程中又不斷嘗試了各種解決方案之後,才篤定了走Agent代理這條路,並實際應用到線上。

而隨著Service Mesh概念的興起,微博所採用的Agent代理的解決方案與Service Mesh理念不謀而合,於是在Agent代理的方案中吸納Service Mesh的思想,進一步演變成如今的Weibo Mesh。所以說一個可靠的架構從來都不是設計出來的,是逐步演進而來的。


原文釋出時間為:2018-11-16

本文作者:胡忠想

本文來自雲棲社群合作伙伴“中生代技術”,瞭解相關資訊可以關注“中生代技術”。