Service Mesh 初體驗
- 2019 年 10 月 25 日
- 筆記
前言
電腦軟體技術發展到現在,軟體架構的演進無不朝著讓開發者能夠更加輕鬆快捷地構建大型複雜應用的方向發展。容器技術最初是為了解決運行環境的不一致問題而產生的,隨著不斷地發展,圍繞容器技術衍生出來越來越多的新方向。
最近幾年,雲計算領域不斷地出現很多新的軟體架構模式,其中有一些很熱門的概念名詞如:雲原生、函數計算、Serverless、Service Mesh 等等,而本文將初窺一下 Service Mesh 的面紗。下面結合自己的理解盡量以通俗的話進行敘述。
背景和定義
微服務及服務治理
在微服務之前的軟體開發中,往往通過一個應用的方式將所有的模組都包括進去,並一起編譯、打包、部署、運維。這種方式存在很多問題,由於單個應用包含的東西太多,其中某個模組出現問題或者需要更新那麼整個應用就需要重新部署。這種方式給開發和運維帶來了很大的麻煩。隨著應用的逐漸複雜,單個應用涉及的東西就會越來越多,慢慢地大家發現了其中很多的缺點,開始對服務進行劃分,將一個大的應用按照不同的維度進行劃分從而產生很多個小的應用,各應用之間會形成一個調用關係,每個小的應用由不同的開發負責,大家各自部署和運維,這樣微服務就出現了。
由於微服務中各應用部署在不同的機器上,服務之間需要進行通訊和協調,相比單個應用來說會麻煩很多。在同一個應用內不同方法之間的調用由於在相同的記憶體中,在程式碼編譯打包時已經進行了鏈接,因此調用是可定址且快速的。微服務下不同服務之間的調用涉及到不同進程或者機器之間的通訊,一般需要通過第三方中間件的方式作為中介和協調,由於種種這些,面向微服務出現了很多中間件包括服務治理的框架。通過服務治理工具可以管理其接入的所有應用,使得服務之間的通訊和協調更加簡單高效。
容器及容器編排
最初容器技術是為了解決應用運行環境不一致的問題而出現的,避免在本地環境或者測試環境能夠跑通,等發到生產環境卻出現問題。通過容器將程式及其依賴一起打包到鏡像中去,將程式的鏡像在任何安裝並運行了容器軟體的機器上啟動若干的容器,每個容器就是應用運行時的實例,這些實例一般擁有完全相同的運行環境和參數。使得不管在任何機器上應用都可以表現出一樣的效果。這給開發、測試、運維帶來了極大的便利,不再需要為不同機器上構建相同的運行環境而頭大。且鏡像可以 Push 到鏡像倉庫,這使得應用可以進行很方便的遷移和部署。 Docker 就是一個應用廣泛的容器技術。目前越來越多的應用以微服務的方式並通過容器進行部署,給了軟體開發極大的活力。
與微服務和服務治理的關係類似,越來越多的應用通過容器進行部署,使得集群上的容器數量急劇增加,通過人工的管理和運維這些容器已經變得很艱難且低效,為了解決諸多容器及容器之間的關係出現了很多編排工具,容器編排工具能夠管理容器的整個生命周期。如 Docker 官方出的 docker-compose 和 docker swarm ,這兩個工具能實現批量容器的啟動和編排,但功能較為簡單,不足以支撐大型的容器集群。 Google 基於內部大量的容器管理經驗,開源出了 Kubernetes 項目, Kubernetes(K8s) 是針對 Google 集群上每周億級別的容器而設計的,具有很強大的容器編排能力和豐富的功能。 K8s 通過定義了很多資源,這些資源以聲明式的方式進行創建,可以通過 JSON 或者 YAML 文件表示一個資源, K8s 支援多種容器,但主流的是 Docker 容器, K8s 提供了容器接入的相關標準,只要容器實現了該標準就可以被 K8s 所編排。由於 K8s 的功能較多,不在此一一敘述,有興趣可以參考官方文檔。
當某個公司的應用已經完全微服務化後,選擇以容器的方式部署應用,此時可以在集群上部署 K8s ,通過 K8s 提供的能力進行應用容器的管理,運維可以也可以面向 K8s 進行工作。由於 K8s 是目前使用最廣泛的容器編排工具,因此成為了容器編排的一個標準了,目前集團內部也有自己的容器和容器編排工具。
面向以 K8s 為代表的容器管理方式衍生出了一些新的技術。
雲原生
最近兩年雲原生被炒的很火,可以在各處看到很多大佬對雲原生的高談闊論,下面直接拋出 CNCF 對雲原生的定義:
雲原生技術有利於各組織在公有雲、私有雲和混合雲等新型動態環境中,構建和運行可彈性擴展的應用。雲原生的代表技術包括容器、服務網格、微服務、不可變基礎設施和聲明式 API 。這些技術能夠構建容錯性好、易於管理和便於觀察的松耦合系統。結合可靠的自動化手段,雲原生技術使工程師能夠輕鬆地對系統作出頻繁和可預測的重大變更。
在我看來,通過微服務的方式開發應用,以容器進行部署,使用 K8s 等容器編排工具進行容器集群的管理,使得開發運維都面向 K8s ,這就是雲原生。雲原生可以方便的構建應用,並對應用進行完整的監控,以及在應用針對不同流量時能進行快速的擴容和縮容。如下圖:
雲原生主要包括四個部分:
- 微服務
- 容器
- 持續集成和交付
- DevOps
PS:總是覺得雲原生這個叫法太抽象了,很難讓人通過名字想到這是個啥東西。
ServiceMesh的定義
前面講了微服務、容器、容器編排、雲原生等,其實就是為了得出什麼是 Service Mesh ,自己總結了一下: Sevice Mesh 是雲原生下的微服務治理方案。
當我們通過微服務的方式將應用以容器的形式部署在 K8s上後,服務之間調用和治理其實有新的方案,可以不需要依賴傳統的微服務治理框架。 Service Mesh 通過對每個應用在其 Pod 中啟動一個 Sidecar (邊車)實現對應用的透明代理,所有出入應用的流量都先經過該應用的 Sidecar ,服務之間的調用轉變成了 Sidecar 之間的調用,服務的治理轉變成了對 Sidecar 的治理。在 Service Mesh 中 Sidecar 是透明的,開發無感知的,之前一直覺得奇怪,總覺得一個應用要讓別人發現它從而調用它,總得引入一些庫然後進行主動的服務註冊,不然啥都不做,別人咋知道這個應用的存在,為什麼在 Service Mesh 中就可以省去這些,做到對開發者完全地透明呢?這個的實現依賴於容器編排工具,通過 K8s 進行應用的持續集成和交付時,在啟動應用 Pod 後,其實已經通過 Yaml 文件的形式向 K8s 註冊了自己的服務以及聲明了服務之間的關係,Service Mesh 通過和 K8s 進行通訊獲取集群上所有的服務資訊,通過 K8s 這個中間者實現了對開發者的透明。如下圖所示,是 Service Mesh的一個基本結構,包括數據平面和控制平面。
這種方式存在很多好處,我們可以發現在這種模式下應用的語言其實不會對整個服務治理過程有什麼影響,對於 Service Mesh 來說,它只關心 Pod 或者說是 Pod 中的容器實例,並不需要在乎容器中應用的實現語言是啥,Sidecar 和其負責的容器在同一個 Pod 中。這樣 Service Mesh 就可以實現跨語言,這也是目前很多傳統的服務治理框架的一大缺點,而且採用傳統的服務治理,需要對應用引入大量的依賴,這樣就會造成依賴之間的各種衝突,集團通過 Pandora 對應用的各種依賴進行隔離。再者傳統的服務治理門檻較高,需要開發者對整個架構有一定的了解,且發現問題排查較為麻煩。這也造成了開發和運維之間的界限不清,在 Service Mesh 中開發只需要交付程式碼,運維可以基於K8S去維護整個容器集群。
發展現狀
通過目前查閱的資料來看, Service Mesh 一詞最早出現在 2016 年,最近兩年被炒的很火,螞蟻金服已經有了自己的一套完整的 Service Mesh 服務框架– Sofa Mesh ,集團很多團隊也在進行相應的跟進。
從歷史發展的路線來看,程式的開發方式經歷了很多的變化,但總的方向是變得越來越簡單了,現在我們在集團內進行開發,可以很簡單的構建一個支撐較大 QPS 的服務,這得益於集團的整個技術體系的完整和豐富以及強大的技術積澱。
我們下面來看看應用開發到底經歷了啥?
發展歷史
主機直接階段
如上圖,這一階段應該是最古老的階段,兩台機器通過網線直接連接,一個應用包含了你能想到的所有的功能,包括兩台機器的連接管理,這時還沒有網路的概念,畢竟只能和通過網線直接連接在一起的機器進行通訊。
網路層的出現
如上圖,隨著技術的發展,網路層出現了,機器可以和通過網路連接的其他所有機器進行通訊,不再限制於必須要網線直連兩台機器。
集成到應用程式內部的流量控制
如上圖,由於每個應用所在環境和機器配置不一樣,接受流量的能力也不相同,當A應用發送的流量大於了 B 應用的接受能力時,那麼無法接收的數據包必定會被丟棄,這時就需要對流量進行控制,最開始流量的控制需要應用自己去實現,網路層只負責接收應用下發的數據包並進行傳輸。
流量控制轉移到網路層
如上圖,慢慢地大家發應用中的網路流量控制是可以轉移到網路層的,所以網路層中的流量控制出現了,我想大概就是指 TCP 的流量控制吧,這樣還能保證可靠的網路通訊。
應用程式的中集成服務發現和斷路器
如上圖,開發者通過在自己的程式碼模組中實現服務發現和斷路器。
專門用於服務發現和斷路器的軟體包/庫
如上圖,開發者通過引用第三方依賴去實現服務發現和斷路器。
出現了專門用於服務發現和斷路器的開源軟體
如上圖,基於各種中間件去實現服務發現和斷路器。
ServiceMesh出現
最終到了現在, ServiceMesh 大法誕生,進一步解放了生產力,提高了軟體整個生命周期的效率。
ServiceMesh市場競爭
雖然直到 2017 年底,ServiceMesh 才開始較大規模被世人了解,這場微服務市場之爭也才顯現,但是其實 ServiceMesh 這股微服務的新勢力,早在 2016 年初就開始萌芽:
2016 年 1 月,離開 Twitter 的基礎設施工程師 William Morgan 和 Oliver Gould ,在 GitHub 上發布了 Linkerd 0.0.7 版本,業界第一個 ServiceMesh 項目就此誕生。 Linkerd 基於 Twitter 的 Finagle 開源項目,大量重用了 Finagle 的類庫,但是實現了通用性,成為了業界第一個 Service Mesh 項目。而 Envoy 是第二個 Service Mesh 項目,兩者的開發時間差不多,在 2017 年都相繼成為 CNCF 項目。2017 年 5 月 24 日,Istio 0.1 release 版本發布, Google 和 IBM 高調宣講,社區反響熱烈,很多公司在這時就紛紛站隊表示支援 Istio 。Linkerd 的風光瞬間被蓋過,從意氣風發的少年一夜之間變成過氣網紅。當然,從產品成熟度上來說, linkerd 作為業界僅有的兩個生產級 Service Mesh 實現之一,暫時還可以在 Istio 成熟前繼續保持市場。但是,隨著 Istio 的穩步推進和日益成熟,外加第二代 Service Mesh 的天然優勢, Istio 取代第一代的 Linkerd 只是個時間問題。自從在2016年決定委身於 Istio 之後, Envoy 就開始了一條波瀾不驚的平穩發展之路,和 Linkerd 的跌宕起伏完全不同。在功能方面,由於定位在數據平面,因此 Envoy 無需考慮太多,很多工作在 Istio 的控制平面完成就好, Envoy 從此專心於將數據平面做好,完善各種細節。在市場方面, Envoy 和 Linkerd 性質不同,不存在生存和發展的戰略選擇,也沒有正面對抗生死大敵的巨大壓力。
從 Google 和 IBM 聯手決定推出 Istio 開始, Istio 就註定永遠處於風頭浪尖,無論成敗, Istio 面世之後,讚譽不斷,尤其是 Service Mesh 技術的愛好者,可以說是為之一振:以新一代 Service Mesh 之名橫空出世的 Istio ,對比 Linkerd ,優勢明顯。同時產品路線圖上有一大堆令人眼花繚亂的功能。假以時日,如果 Istio 能順利地完成開發,穩定可靠,那麼這會是一個非常美好、值得憧憬的大事件,
Istio介紹
Istio 是目前最熱的 Service Mesh 開源項目, Istio 主要分為兩個部分:數據平面和控制平面。 Istio 實現了雲原生下的微服務治理,能實現服務發現,流量控制,監控安全等。 Istio 通過在一個 Pod 里啟動一個應用和 Sidecar 方式實現透明代理。 Istio 是一個拓展性較高的框架,其不僅可以支援 K8S ,還可以支援其他如 Mesos 等資源調度器。如下圖所示,為 Istio 的整體架構:
- 邏輯上分為數據平面(上圖中的上半部分)和控制平面(上圖中的下半部分)。
- 數據平面由一組以 Sidecar 方式部署的智慧代理(Envoy)組成。這些代理可以調節和控制微服務及 Mixer 之間所有的網路通訊。
- 控制平面負責管理和配置代理來路由流量。此外控制平面配置 Mixer 以實施策略和收集遙測數據。
- Pilot 是整個架構中的抽象層,將對接 K8s 等資源調度器的步驟進行抽象並以適配器的形式展現,並和用戶以及 Sidecar 交互。
- Galley 負責資源配置為驗證。
- Citadel 用於生成身份,及密鑰和證書管理
- 核心功能包括流量控制、安全控制、可觀測性、多平台支援、可訂製化。
Mixer
Mixer 同樣是一個可拓展的模組,其負責遙感數據的採集以及集成了一些後端服務(BAAS),Sidecar 會不斷向 Mixer 報告自己的流量情況, Mixer 對流量情況進行匯總,以可視化的形式展現,此外 Sidecar 可以調用 Mixer 提供的一些後端服務能力,例如鑒權、登錄、日誌等等, Mixer 通過適配器的方式對接各種後端服務。
In-process Adapter形式
之前版本的 Isito 採用這種將後端服務適配器集成在 Mixer 內部的形式,這種方式會有一個問題,就是某個後端服務適配器出現問題即會影響整個 Mixer 模組,但由於適配器和 Mixer 集成在一起,在同一個進程內,方法的調用會很快。
Out-of-process Adapter 形式
目前版本的 Istio 將 Adapter 移到 Mixer 外部,這樣可以實現 Mixer 與 Adapter 的解耦,當 Adapter 出現問題並不會影響 Mixer ,但這種方式同樣也存在問題,即 Adapter 在 Mixer 外,是兩個不同的進程,二者之間的調用是通過 RPC 的方式,這種方式比同進程內部的方法調用會慢很多,因此性能會受到影響。
Pilot
- Envoy API 負責和 Envoy 的通訊, 主要是發送服務發現資訊和流量控制規則給 Envoy 。
- Abstract Model 是 Pilot 定義的服務的抽象模型, 以從特定平台細節中解耦, 為跨平台提供基礎。
- Platform Adapter 則是這個抽象模型的實現版本, 用於對接外部的不同平台如 K8s/mesos 等。
- Rules API 提供介面給外部調用以管理 Pilot, 包括命令行工具 Istioctl 以及未來可能出現的第三方管理介面。
Galley
Galley 原來僅負責進行配置驗證, 1.1 後升級為整個控制面的配置管理中心, 除了繼續提供配置驗證功能外, Galley 還負責配置的管理和分發, Galley 使用 網格配置協議( Mesh Configuration Protocol ) 和其他組件進行配置的交互。
- Istio 創造了 50 多個 CRD , 其複雜度可見一斑, 所以有人說面向k8s編程近似於面向 yaml 編程.早期的 Galley 僅僅負責對配置進行運行時驗證, Istio 控制面各個組件各自去list/watch -各自關注的配置。越來越多且複雜的配置給 Istio 用戶帶來了諸多不便, 主要體現在:
- 配置的缺乏統一管理, 組件各自訂閱, 缺乏統一回滾機制, 配置問題難以定位。
- 配置可復用度低, 比如在1.1之前, 每個 Mixer adpater 就需要定義個新的CRD。
- 配置的隔離, ACL 控制, 一致性, 抽象程度, 序列化等等問題都還不太令人滿意
隨著 Istio 功能的演進, 可預見的 Istio CRD 數量還會繼續增加, 社區計劃將 Galley 強化為 Istio 配置控制層, Galley 除了繼續提供配置驗證功能外, 還將提供配置管理流水線, 包括輸入, 轉換, 分發, 以及適合 Istio 控制面的配置分發協議( MCP )。
Citadel
將服務拆分為微服務之後,在帶來各種好處的同時,在安全方面也帶來了比單體時代更多的需求,畢竟不同功能模組之間的調用方式從原來單體架構中的方法調用變成了微服務之間的遠程調用:
- 加密:為了不泄露資訊,為了抵禦中間人攻擊,需要對服務間通訊進行加密。
- 訪問控制:不是每個服務都容許被任意訪問,因此需要提供靈活的訪問控制,如雙向 TLS 和細粒度的訪問策略。
- 審計:如果需要審核系統中哪些用戶做了什麼,則需要提供審計功能。
Citadel 是 Istio 中負責安全性的組件,但是 Citadel 需要和其他多個組件配合才能完成工作:
- Citadel:用於密鑰管理和證書管理,下發到 Envoy 等負責通訊轉發的組件。
- Envoy:使用從 Citadel 下發而來的密鑰和證書,實現服務間通訊的安全,注意在應用和 Envoy 之間是走 Localhost ,通常不用加密。
- Pilot:將授權策略和安全命名資訊分發給 Envoy 。
- Mixer:負責管理授權,完成審計等。
Istio 支援的安全類功能有:
- 流量加密:加密服務間的通訊流量。
- 身份認證:通過內置身份和憑證管理可以提供強大的服務間和最終用戶身份驗證,包括傳輸身份認證和來源身份認證,支援雙向 TLS 。
- 授權和鑒權:提供基於角色的訪問控制( RBAC ),提供命名空間級別,服務級別和方法級別的訪問控制。
mPass 微服務開發平台 基於SpringBoot2.x、SpringCloud並採用前後端分離的多租戶系統架構微服務開發平台 mPaaS(Microservice PaaS)為租戶業務開發、測試、運營及運維開源框架,能有效降低技術門檻、減少研發成本、提升開發效率,協助企業快速搭建穩定高品質的微服務應用
喜歡閱讀Spring、SpringBoot、SpringCloud等底層源碼的可以關注下mPass 微服務開發平台,期待您的寶貴意見!