Service Mesh如此火熱,背後的技術細節你了解多少?

在 Kubernetes 稱為容器編排的標準之後,Service Mesh 開始火了起來,但是很多文章講概念的多,講技術細節的少,所以專門寫一篇文章,來解析 Service Mesh 背後的技術細節。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

Service Mesh 是 Kubernetes 支撐微服務能力拼圖的最後一塊

Kubernetes 是一個奇葩所在,它的組件複雜,概念複雜。在沒有實施微服務之前,你可能會覺得為什麼 Kubernetes 要設計的這麼複雜,但是一旦你要實施微服務,你會發現 Kubernetes 中的所有概念,都是有用的。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

在我們微服務設計的十個要點中,我們會發現 Kubernetes 都能夠有相應的組件和概念,提供相應的支持。

其中最後的一塊拼圖就是服務發現,與熔斷限流降級。

眾所周知,Kubernetes 的服務發現是通過 Service 來實現的,服務之間的轉發是通過 kube-proxy 下發 iptables 規則來實現的。

這個只能實現最基本的服務發現和轉發能力,不能滿足高併發應用下的高級的服務特性,比較 Spring Cloud 和 Dubbo 有一定的差距,於是 Service Mesh 誕生了。

它期望講熔斷,限流,降級等特性,從應用層,下沉到基礎設施層去實現,從而使得 Kubernetes 和容器全面接管微服務。

以 Istio 為例講述 Service Mesh 中的技術關鍵點

Service Mesh如此火熱,背後的技術細節你瞭解多少?

就如 SDN 一樣,Service Mesh 將服務請求的轉發分為控制面和數據面,因而分析它,也是從數據面先分析轉發的能力,然後再分析控制面如何下發命令。今天這篇文章重點講述兩個組件 Envoy 和 Pilot。

一切從 Envoy 開始

我們首先來看,如果沒有融入 Service Mesh,Envoy 本身能夠做什麼事情呢?

Envoy 是一個高性能的 C++ 寫的 Proxy 轉發器,那 Envoy 如何轉發請求呢?需要定一些規則,然後按照這些規則進行轉發。

規則可以是靜態的,放在配置文件中的,啟動的時候加載,要想重新加載,一般需要重新啟動,但是 Envoy 支持熱加載和熱重啟,一定程度上緩解了這個問題。

當然最好的方式是規則設置為動態的,放在統一的地方維護,這個統一的地方在 Envoy 眼中看來稱為 Discovery Service,過一段時間去這裡拿一下配置,就修改了轉發策略。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

無論是靜態的,還是動態的,在配置裡面往往會配置如上圖中的四個東西:

  • Listener,也即 Envoy 既然是 Proxy,專門做轉發,就得監聽一個端口,接入請求,然後才能夠根據策略轉發,這個監聽的端口稱為 Listener。
  • Route,有時候多個 Cluster 具有類似的功能,但是是不同的版本號,可以通過 Route 規則,選擇將請求路由到某一個版本號,也即某一個 Cluster。
  • Cluster,一個 Cluster 是具有完全相同行為的多個 Endpoint,也即如果有三個容器在運行,就會有三個 IP 和端口。
  • 但是部署的是完全相同的三個服務,他們組成一個 Cluster,從 Cluster 到 Endpoint 的過程稱為負載均衡,可以輪詢等。
  • Endpoint,是目標的 IP 地址和端口,這個是 Proxy 最終將請求轉發到的地方。

這四個的靜態配置的例子如下:

Service Mesh如此火熱,背後的技術細節你瞭解多少?

如圖所示,Listener 被配置為監聽本地 127.0.0.1 的 10000 接口,Route 配置為某個 URL 的前綴轉發到哪個 Cluster,Cluster 裡面配置負載均衡策略,Hosts 裡面是所有的 Endpoint。

如果你想簡單的將 Envoy 使用起來,不用什麼 Service Mesh,那麼一個進程,加上這個配置文件,就可以了,就能夠轉發請求了。

對於動態配置,也應該配置發現中心,也即 Discovery Service,對於上述四種配置,各對應相應的 DS,所以有 LDS、RDS、CDS、EDS。

動態配置的例子如下:

Service Mesh如此火熱,背後的技術細節你瞭解多少?

控制面 Pilot 的工作模式

數據面 Envoy 可以通過加裝靜態配置文件的方式運行,而動態信息,需要從 Discovery Service 去拿。

Discovery Service 就是部署在控制面的,在 Istio 中,是 Pilot。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

如上圖,為 Pilot 的架構,最下面一層是 Envoy 的 API,就是提供 Discovery Service 的 API。

這個 API 的規則由 Envoy 定,但是不是 Pilot 調用 Envoy,而是 Envoy 去主動調用 Pilot 的這個 API。

Pilot 最上面一層稱為 Platform Adapter,這一層是幹什麼的呢?這一層不是 Kubernetes,Mesos 調用 Pilot,而是 Pilot 通過調用 Kubernetes 來發現服務之間的關係。

這是理解 Istio 比較繞的一個點。也即 Pilot 使用 Kubernetes 的 Service,僅僅使用它的服務發現功能,而不使用它的轉發功能。

Pilot 通過在 Kubernetes 裡面註冊一個 Controller 來監聽事件,從而獲取 Service 和 Kubernetes 的 Endpoint 以及 Pod 的關係。

但是在轉發層面,就不會再使用 kube-proxy 根據 service 下發的 iptables 規則進行轉發了,而是將這些映射關係轉換成為 Pilot 自己的轉發模型,下發到 Envoy 進行轉發,Envoy 不會使用 kube-proxy 的那些 iptables 規則。

這樣就把控制面和數據面徹底分離開來,服務之間的相互關係是管理面的事情,不要和真正的轉發綁定在一起,而是繞到 Pilot 後方。

Pilot 另外一個對外的接口是 Rules API,這是給管理員的接口,管理員通過這個接口設定一些規則,這些規則往往是應用於 Routes、Clusters、Endpoints 的。

而都有哪些 Clusters 和 Endpoints,是由 Platform Adapter 這面通過服務發現得到的。

自動發現的這些 Clusters 和 Endpoints,外加管理員設置的規則,形成了 Pilot 的數據模型,其實就是他自己定義的一系列數據結構,然後通過 Envoy API 暴露出去,等待 Envoy 去拉取這些規則。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

常見的一種人工規則是 Routes,通過服務發現,Pilot 可以從 Kubernetes 那裡知道 Service B 有兩個版本,一般是兩個 Deployment,屬於同一個 Service。

管理員通過調用 Pilot 的 Rules API,來設置兩個版本之間的 Route 規則,一個佔 99% 的流量,另一個佔 1% 的流量。

這兩方面信息形成 Pilot 的數據結構模型,然後通過 Envoy API 下發,Envoy 就會根據這個規則設置轉發策略了。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

另一個常用的場景就是負載均衡,Pilot 通過 Kubernetes 的 Service 發現 Service B 包含一個 Deployment,但是有三個副本。

於是通過 Envoy API 下發規則,使得 Envoy 在這三個副本之間進行負載均衡,而非通過 Kubernetes 本身 Service 的負載均衡機制。

以 Istio 為例解析 Service Mesh 的技術細節

瞭解了 Service Mesh 的大概原理,接下來我們通過一個例子來解析其中的技術細節。

凡是試驗過 Istio 的同學都應該嘗試過下面這個 BookInfo 的例子,不很複雜,但是麻雀雖小五臟俱全。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

在這個例子中,我們重點關注 ProductPage 這個服務,對 Reviews 服務的調用,這裡涉及到路由策略和負載均衡。

Productpage 就是個 Python 程序

Productpage 是一個簡單的用 Python 寫的提供 Restful API 的程序。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

在裡面定義了很多的 Route,來接收 API 請求,並做相應的操作。

在需要請求其他服務,例如 reviews、ratings 的時候,則需要向後方發起 restful 調用。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

從代碼可以看出,Productpage 對於後端的調用,都是通過域名來的。

對於 Productpage 這個程序來講,他覺得很簡單,通過這個域名就可以調用了,既不需要通過服務發現系統獲取這個域名,也不需要關心轉發。

更意識不到自己是部署在 Kubernetes 上的,是否用了 Service Mesh,所以服務之間的通信完全交給了基礎設施層。

通過 Kubernetes 編排 Productpage

有了 Productpage 程序,接下來就是將它部署到 Kubernetes 上,這裡沒有什麼特殊的,用的就是 Kubernetes 默認的編排文件。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

首先定義了一個 Deployment,使用 bookinfo 的容器鏡像,然後定義一個 Service,用於這個 Deployment 的服務發現。

通過 Kubernetes 編排 Reviews

Service Mesh如此火熱,背後的技術細節你瞭解多少?

這個稍微有些複雜,定義了三個 Deployment,但是版本號分別為 V1、V2、V3,但是 Label 都是 app:reviews。

最後定義了一個 Service,對應的 Label 是app:reviews,作為這三個 Deployment 的服務發現。

Istioctl 對 Productpage 進行定製化之一:嵌入 proxy_init 作為 InitContainer。

到目前為止,一切正常,接下來就是見證奇蹟的時刻,也即 Istio 有個工具 Istioctl 可以對於 Yaml 文件進行定製化。

定製化的第一項就是添加了一個 InitContainer,這種類型的 Container 可以做一些初始化的工作後,成功退出,Kubernetes 不會保持它長期運行。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

在這個 InitContainer 裡面做什麼事情呢?

我們登錄進去發現,在這個 InitContainer 裡面運行了一個 Shell 腳本。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

就是這個 Shell 腳本在容器裡面寫入了大量的 iptables 規則。

首先定義的一條規則是 ISTIO_REDIRECT 轉發鏈,這條鏈不分三七二十一,都將網絡包轉發給 Envoy 的 15000 端口。

但是一開始這條鏈沒有被掛到 iptables 默認的幾條鏈中,所以不起作用。

接下來就是在 PREROUTING 規則中,使用這個轉發鏈,從而進入容器的所有流量,都被先轉發到 Envoy 的 15000 端口。

Envoy 作為一個代理,已經被配置好了,將請求轉發給 Productpage 程序。

Productpage 程序接受到請求,會轉向調用外部的 reviews 或者 ratings,從上面的分析我們知道,Productpage 只是做普通的域名調用。

當 Productpage 往後端進行調用的時候,就碰到了 output 鏈,這個鏈會使用轉發鏈,將所有出容器的請求都轉發到 Envoy 的 15000 端口。

這樣無論是入口的流量,還是出口的流量,全部用 Envoy 做成了漢堡包。

Envoy 根據服務發現的配置,知道 reviews 或者 ratings 如何訪問,於是做最終的對外調用。

這個時候 iptables 規則會對從 Envoy 出去的流量做一個特殊處理,允許它發出去,不再使用上面的 output 規則。

Istioctl 對 Productpage 進行定製化之二:嵌入 Proxy 容器作為 Sidecar。

Istioctl 做的第二項定製化是嵌入 Proxy 容器作為 Sidecar,如下圖:

Service Mesh如此火熱,背後的技術細節你瞭解多少?

這個似乎看起來更加複雜,但是進入容器我們可以看到,啟動了兩個進程。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

一個是我們熟悉的 Envoy,它有一個配置文件是 /etc/istio/proxy/envoy-rev0.json。

我們再前面講述 Envoy 的時候說過,有了配置文件,Envoy 就能夠轉發了,我們先來看看配置文件裡面都有啥。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

在這裡面配置了 Envoy 的管理端口,等一下我們會通過這個端口查看 Envoy 被 Pilot 下發了哪些轉發策略。

然後就是動態資源,也即從各種 Discovery Service 去拿轉發策略。

還有就是靜態資源,也即靜態配置的,需要重啟才能加載的。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

這就是 pilot-agent 的作用,它是 Envoy 的一個簡單的管理器,因為有些靜態資源,如果是 TLS 的證書,Envoy 還不支持動態下發,因而需要重新靜態配置,然後 pilot-agent 負責將 Envoy 進行熱重啟加載。

好在 Envoy 有良好的熱重啟機制,重啟的時候,會先啟動一個備用進程,將轉發的統計數據通過 Shared Memory 在兩個進程間共享。

深入解析 Pilot 的工作機制

Service Mesh如此火熱,背後的技術細節你瞭解多少?

Pilot 的工作機制展開後如上圖所示,istio config 是管理員通過管理接口下發的轉發規則。

Service Discovery 模塊對於 Kubernetes 來講,就是創建了一個 Controller 來監聽 Service 創建和刪除的事件。

當 Service 有變化時,會通知 Pilot,Pilot 會根據變化更新下發給 Envoy 的規則。

Pilot 將管理員輸入的轉發策略配置和服務發現的當前狀態,變成 Pilot 自己的數據結構模型,然後暴露成 Envoy 的 API,由於是 Envoy 來調用,因而要實現一個服務端,這裡有 LDS、RDS、CDS、EDS。

接下來我們看,在 Pilot 上配置 Route 之後會發生什麼?

Service Mesh如此火熱,背後的技術細節你瞭解多少?

如上圖,我們將所有的流量都發給版本 1。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

我們查看 Envoy 的管理端口,可以看到只配置了 Reviews 的 V1。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

當我們修改路由為 V1 和 V3 比例是五十比五十。

Service Mesh如此火熱,背後的技術細節你瞭解多少?

可以看到 Envoy 的管理端口,路由有了兩個版本的配置,也對應後端的兩個 IP 地址。


分享到:


相關文章: