1. 程式人生 > >深入解讀Service Mesh背後的技術細節

深入解讀Service Mesh背後的技術細節

調用 數據模型 什麽 比較 正常 應用 ffi gcs dsl

本文由 網易雲 發布。

作者:劉超,網易雲首席解決方案架構師

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

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

在上一篇文章為什麽 kubernetes 天然適合微服務中我們提到,Kubernetes是一個奇葩所在,他的組件復雜,概念復雜,在沒有實施微服務之前,你可能會覺得為什麽Kubernetes要設計的這麽復雜,但是一旦你要實施微服務,你會發現Kubernetes中的所有概念,都是有用的。

技術分享圖片

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

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

眾所周知,Kubernetes的服務發現是通過Service來實現的,服務之間的轉發是通過kube-proxy下發iptables規則來實現的,這個只能實現最基本的服務發現和轉發能力,不能滿足高並發應用下的高級的服務特性,比較SpringCloud和Dubbo有一定的差距,於是Service Mesh誕生了,他期望講熔斷,限流,降級等特性,從應用層,下沈到基礎設施層去實現,從而使得Kubernetes和容器全面接管微服務。

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

技術分享圖片

技術分享圖片

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

一切從Envoy開始

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

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

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

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

無論是靜態的,還是動態的,在配置裏面往往會配置四個東西。

技術分享圖片

技術分享圖片

一是listener,也即envoy既然是proxy,專門做轉發,就得監聽一個端口,接入請求,然後才能夠根據策略轉發,這個監聽的端口稱為listener

二是endpoint,是目標的ip地址和端口,這個是proxy最終將請求轉發到的地方。

三是cluster,一個cluster是具有完全相同行為的多個endpoint,也即如果有三個容器在運行,就會有三個IP和端口,但是部署的是完全相同的三個服務,他們組成一個Cluster,從cluster到endpoint的過程稱為負載均衡,可以輪詢等。

四是route,有時候多個cluster具有類似的功能,但是是不同的版本號,可以通過route規則,選擇將請求路由到某一個版本號,也即某一個cluster。

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

技術分享圖片

技術分享圖片

如圖所示,listener被配置為監聽本地127.0.0.1的10000接口,route配置為某個url的前綴轉發到哪個cluster,cluster裏面配置負載均衡策略,hosts裏面是所有的endpoint。

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

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

動態配置的例子如下:

技術分享圖片

技術分享圖片

控制面Pilot的工作模式

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

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

技術分享圖片

技術分享圖片

如圖為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去拉取這些規則。

技術分享圖片

技術分享圖片

常見的一種人工規則是Routes,通過服務發現,Pilot可以從Kubernetes那裏知道Service B有兩個版本,一般是兩個Deployment,屬於同一個Service,管理員通過調用Pilot的Rules API,來設置兩個版本之間的Route規則,一個占99%的流量,一個占1%的流量,這兩方面信息形成Pilot的數據結構模型,然後通過Envoy API下發,Envoy就會根據這個規則設置轉發策略了。

技術分享圖片

技術分享圖片

另一個常用的場景就是負載均衡,Pilot通過Kubernetes的Service發現Service B包含一個Deployment,但是有三個副本,於是通過Envoy API下發規則,使得Envoy在這三個副本之間進行負載均衡,而非通過Kubernetes本身Service的負載均衡機制。

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

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

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

技術分享圖片

技術分享圖片

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

Productpage就是個Python程序

productpage是一個簡單的用python寫的提供restful API的程序。

技術分享圖片

技術分享圖片

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

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

技術分享圖片

技術分享圖片

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

對於productpage這個程序來講,他覺得很簡單,通過這個域名就可以調用了,既不需要通過服務發現系統獲取這個域名,也不需要關心轉發,更意識不到自己是部署在kubernetes上的,是否用了service mesh,所以服務之間的通信完全交給了基礎設施層。

通過Kubernetes編排productpage

有了productpage程序,接下來就是將他部署到kubernetes上,這裏沒有什麽特殊的,用的就是kubernetes默認的編排文件。

技術分享圖片

技術分享圖片

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

通過Kubernetes編排reviews

技術分享圖片

技術分享圖片

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

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

istioctl對productpage進行定制化之一:嵌入proxy_init作為InitContainer

到目前為止,一切正常,接下來就是見證奇跡的時刻,也即istio有個工具istioctl可以對於yaml文件進行定制化

定制化的第一項就是添加了一個initContainer,這種類型的container可以做一些初始化的工作後,成功退出,kubernetes不會保持他長期運行。

技術分享圖片

技術分享圖片

在這個InitContainer裏面做什麽事情呢?

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

技術分享圖片

技術分享圖片

就是這個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。

技術分享圖片

技術分享圖片

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

技術分享圖片

技術分享圖片

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

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

技術分享圖片

技術分享圖片

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

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

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

技術分享圖片

技術分享圖片

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

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

深入解析pilot的工作機制

技術分享圖片

技術分享圖片

Pilot的工作機制展開後如圖所示。

istio config是管理員通過管理接口下發的轉發規則。

Service Discovery模塊對於Kubernetes來講,就是創建了一個controller來監聽Service創建和刪除的事件,當service有變化時,會通知pilot,pilot會根據變化更新下發給envoy的規則。

pilot將管理員輸入的轉發策略配置和服務發現的當前狀態,變成pilot自己的數據結構模型,然後暴露成envoy的api,由於是envoy來調用,因而要實現一個服務端,這裏有lds, rds, cds, eds。

接下來我們看,在pilot上配置route之後會發生什麽?
技術分享圖片

技術分享圖片

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

技術分享圖片

技術分享圖片

我們查看envoy的管理端口,可以看到只配置了reviews的v1。

技術分享圖片

技術分享圖片

當我們修改路由為v1和v3比例是五十比五十。

技術分享圖片

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

了解 網易雲 :
網易雲官網:https://www.163yun.com/
新用戶大禮包:https://www.163yun.com/gift
網易雲社區:https://sq.163yun.com/

深入解讀Service Mesh背後的技術細節