前言
如你所知,已經有不少關於服務網格的資料,但這是另一篇。是的!可是爲何會有這篇文章呢?由於我想給大家一些不一樣的視角,他們但願服務網格在10年前就已經存在,遠早於Docker和Kubernetes這樣的容器平臺的興起。我並非說這個視角比其餘視角更好或更差,可是因爲服務網格是至關複雜的「野獸」,因此我相信多種視角有助於更好地理解它們。
前端
我將討論dotCloud平臺,這是一個創建在100多個微服務之上的平臺,支持數千個運行在容器中的生產應用程序;我將解釋在構建和運行它時所面臨的挑戰;以及服務網格會(或不會)提供幫助。git
我已經寫過關於dotCloud平臺的歷史和它的一些設計選擇,可是我沒有過多地討論它的網絡層。若是你不想深刻了解我以前關於dotCloud的博客,你須要知道的是它是一個PaaS,容許客戶運行各類應用程序(Java、PHP、Python等),支持普遍的數據服務(MongoDB、MySQL、Redis等)以及相似於Heroku的工做流程:你能夠將代碼推送到平臺,平臺將構建容器鏡像,並部署這些容器鏡像。
我將告訴你流量是如何在dotCloud平臺上路由的;不是由於它是特別棒或其餘什麼(我認爲如今是比較合適的時間),但主要是由於,若是一個普通的團隊須要一種在一個微服務羣或一個應用程序羣之間路由流量的方法,那麼這種設計能夠在短期內用如今已有的工具輕鬆實現。所以,它將爲咱們提供一個很好的比較點,「若是咱們破解它,咱們會獲得什麼」和「若是咱們使用現有的服務網格,咱們會獲得什麼」,也就是老生常談的「構建與購買」的困境。
部署在dotCloud上的應用程序會暴露HTTP和TCP端點。
HTTP端點被動態地添加到負載平衡器集羣的配置中。這與咱們今天使用Kubernetes Ingress資源和Traefik這樣的負載平衡器能夠實現的功能相似。
只要域名指向dotCloud的負載平衡器,客戶端就可使用它們的關聯域名鏈接到HTTP端點。這裏沒有什麼特別的。
TCP端點與端口號相關聯,而後端口號經過環境變量與該堆棧上的全部容器通訊。
客戶端可使用指定的主機名(相似於gateway-X.dotcloud.com)和端口號鏈接到TCP端點。
該主機名將解析爲一個「nats」服務器集羣(與NATS沒有任何關係),該集羣將把傳入的TCP鏈接路由到正確的容器(或者,在負載平衡服務的狀況下,路由到正確的容器)。
若是你熟悉Kubernetes,這可能會讓你想起NodePort服務。
dotCloud平臺沒有集羣IP服務的等價物:爲了簡單起見,從內部和外部訪問服務的方式是相同的。
這很是簡單,最初的HTTP和TCP路由網格的實現可能都是幾百行Python代碼,使用至關簡單(我敢說,很天真)的算法,可是隨着時間的推移,它們不斷髮展,以處理平臺的增加和額外的需求。
它不須要對現有應用程序代碼進行大量重構。十二因素應用程序尤爲能夠直接使用經過環境變量提供的地址信息。
可觀察性有限。對於TCP路由網格根本沒有度量標準。至於HTTP路由網格,後來的版本提供了詳細的HTTP度量,顯示錯誤狀態碼和響應時間;可是現代服務網格的功能遠遠不止於此,它還提供了與度量收集系統(例如Prometheus)的集成。
可觀察性很是重要,不只從操做角度(幫助咱們解決問題),還能夠提供安全的藍/綠部署或金絲雀部署等功能。
路由效率也受到限制。在dotCloud路由網格中,全部流量都必須通過一組專用路由節點。這意味着可能跨越幾個AZ(可用性區域)邊界,並顯著增長延遲。我記得對一些代碼進行故障排除,這些代碼發出100多個SQL請求來顯示給定的頁面,併爲每一個請求打開了到SQL服務器的新鏈接。在本地運行時,頁面會當即加載,但在dotCloud上運行時,須要幾秒鐘,由於每一個TCP鏈接(以及隨後的SQL請求)都須要幾十毫秒才能完成。在這種特定的狀況下,使用持久鏈接起了做用。
現代服務網絡作得更好。首先,經過確保鏈接在源位置路由。邏輯流仍然是客戶端-->網格-->服務,可是如今網格在本地運行,而不是在遠程節點上運行,所以客戶端-->網格鏈接是本地鏈接,所以速度很是快(微秒而不是毫秒)。
現代服務網格還實現了更智能的負載平衡算法。經過監控後端的運行及健康情況,它們能夠在更快的後端上發送更多的流量,從而提升總體性能。
隨着現代服務網絡的出現,安全性也愈來愈強。dotCloud路由網格徹底在EC2 Classic上運行,而且沒有加密流量(假設若是有人設法嗅探EC2上的網絡流量,那麼不管如何都會遇到更大的問題)。現代服務網格能夠透明地保護咱們全部的通訊,例如經過相互的TLS身份驗證和隨後的加密。
OK,咱們已經討論了應用程序是如何通訊的,可是dotCloud平臺自己呢?
平臺自己由大約100個微服務組成,負責各類功能。其中一些服務接受來自其餘服務的請求,而其中一些服務是後臺工做應用,它們將鏈接到其餘服務,但不能本身接收鏈接。不管哪一種方式,每一個服務都須要知道它須要鏈接到的地址的端點。
許多高級服務均可以使用上面描述的路由網格。事實上,dotCloud平臺的100多個微服務中有很大一部分是做爲常規應用程序部署在dotCloud平臺上的。可是少數低級服務(特別是那些實現路由網格的服務)須要一些更簡單的東西,須要更少的依賴關係(由於它們不能依靠本身來運行;這是一個老生常談的「先有雞仍是先有蛋」的問題)。
經過直接在幾個關鍵節點上啓動容器,而不是依賴於平臺的構建器、調度程序和運行器服務,部署了這些底層的基本平臺服務。若是你想要與現代容器平臺進行比較,這就像直接在節點上運行Docker來啓動咱們的控制平面,而不是讓Kubernetes爲咱們作這件事。這與kubeadm或bootkube在引導自託管集羣時使用的靜態Pod的概念很是類似。
這些服務以一種很是簡單和粗糙的方式被公開:有一個YAML文件列出了這些服務,將它們的名稱映射到它們的地址;做爲其部署的一部分,這些服務的每一個使用者都須要一份該YAML文件的副本。
一方面,這是很是強大的,由於它不涉及像ZooKeeper那樣維護外部鍵值存儲(記住,etcd或Consul在那個時候不存在)。另外一方面,這使得服務難以移動。每次移動服務時,它的全部消費者都須要接收更新的YAML文件(而且可能會從新啓動)。不太方便!
咱們開始實現的解決方案是讓每一個消費者都鏈接到一個本地代理。使用者不須要知道服務的完整地址+端口,只須要知道它的端口號,並經過localhost進行鏈接。本地代理將處理該鏈接,並將其路由到實際後端。如今,當一個後端須要移動到另外一臺機器上,或按比例放大或縮小,而不是更新它的全部消費者,咱們只須要更新全部這些本地代理;咱們再也不須要從新啓動消費者。
還計劃將流量封裝在TLS鏈接中,並在接收端使用另外一個代理來打開TLS並驗證證書,而不涉及接收服務,該服務將被設置爲僅在本地主機上接受鏈接。稍後會詳細介紹。
這與AirBNB的SmartStack很是類似;與SmartStack實現並部署到生產環境的顯著區別是,當dotCloud轉向Docker時,它的新的內部路由網格被擱置了。
我我的認爲SmartStack是諸如Istio、Linkerd、Consul Connect等系統的先驅之一,由於全部這些系統都遵循這種模式:
在每一個節點上運行代理github
消費者鏈接到代理web
後端改變時,控制平面更新代理的配置算法
若是咱們今天必須實現相似的網格,咱們可使用相似的原則。例如,咱們能夠設置一個內部域名系統區域,將服務名映射到127.0.0.0/8空間中的地址。而後在集羣的每一個節點上運行HAProxy,接受每一個服務地址(在127.0.0.0/8子網中)上的鏈接,並將它們轉發/負載平衡到適當的後端。HAProxy配置能夠由confd管理,容許在etcd或Consul中存儲後端信息,並在須要時自動將更新的配置推送到HAProxy。
這就是Istio的工做原理!可是有一些不一樣之處:
它使用Envoy Proxy而不是HAProxy數據庫
它使用Kubernetes API而不是etcd或Consul來存儲後端配置後端
服務在內部子網中分配地址(Kubernetes集羣IP地址),而不是127.0.0.0/8api
它有一個額外的組件(Citadel),用於在客戶機和服務器之間添加相互的TLS身份驗證安全
它增長了對諸如斷路、分佈式跟蹤、金絲雀部署等新特性的支持服務器
Envoy Proxy由Lyft撰寫。它與其餘代理(如HAProxy、NGINX、Traefik)有許多類似之處,但Lyft編寫它是由於它們須要當時這些代理中不存在的功能,並且構建一個新的代理比擴展示有代理更有意義。
Envoy能夠單獨使用。若是有一組給定的服務須要鏈接到其餘服務,能夠把它鏈接到Envoy,而後動態地配置和從新配置其餘服務的Envoy的位置,而獲得不少漂亮的額外的功能,好比域的可觀測性。這裏,沒有使用定製的客戶端庫,也沒有在代碼中添加跟蹤調用,而是將流量定向到Envoy,讓它爲我收集指標。
但Envoy也能夠用做服務網格的數據平面。這意味着如今將由該服務網格的控制平面配置Envoy。
說到控制平面,Istio依賴於Kubernetes API。這與使用confd沒有太大的不一樣。confd依賴etcd或Consul來監視數據存儲中的一組密鑰。Istio依賴Kubernetes API來監視一組Kubernetes資源。
Aparte:我我的認爲閱讀Kubernetes API描述[1]很是有幫助。
Kubernetes API服務器是一個「啞服務器」,它提供API資源上的存儲、版本控制、驗證、更新和監視語義。
Istio是爲與Kubernetes合做而設計的;若是你想在Kubernetes以外使用它,則須要運行Kubernetes API服務器的實例(以及支持的etcd服務)。
Istio依賴Kubernetes分配的集羣IP地址,所以Istio獲得一個內部地址(不在127.0.0.1/8範圍)。
在沒有Istio的Kubernetes集羣上,前往給定服務的ClusterIP地址的流量被kube-proxy攔截,併發送到該代理的後端。更具體地說,若是你想肯定技術細節:kube-proxy設置iptables規則(或IPVS負載平衡器,取決於它是如何設置的)來重寫鏈接到集羣IP地址的目標IP地址。
一旦Istio安裝在Kubernetes集羣上,就不會發生任何變化,直到經過將sidecar容器注入到使用者Pod中,顯式地爲給定的使用者甚至整個名稱空間啓用Istio。sidecar將運行一個Envoy實例,並設置一些iptables規則來攔截到其餘服務的流量,並將這些流量重定向到Envoy。
結合Kubernetes DNS集成,這意味着咱們的代碼能夠鏈接到一個服務名,一切均可以正常工做。換句話說,好比咱們的代碼向 http://api/v1/users/4242發起一個請求, api將解析到10.97.105.48,一條iptables規則將解釋鏈接到10.97.105.48並重定向到本地Envoy代理,本地代理將這個請求路由到實際的API後端。
Istio還能夠經過名爲Citadel的組件經過mTLS(雙向TLS)提供端到端加密和身份驗證。
它還包括混合器,Envoy組件能夠查詢每個請求,對請求進行一個臨時的決定取決於各類因素,例如請求頭、後端負載(別擔憂,有豐富的規定以確保混合高度可用,即便它休息,Envoy能夠繼續代理流量)。
固然,我提到了可觀察性。Envoy在提供分佈式跟蹤的同時收集大量的度量指標。微服務架構,若是單個API請求必須通過微服務A、B、C和D,分佈式跟蹤將添加一個唯一的標識符請求進入系統,並保留標識符在子請求中,全部這些微服務容許收集全部相關的調用、延遲等。
Istio以複雜著稱。相比之下,使用咱們今天擁有的工具,構建像我在本文開頭描述的那樣的路由網格相對比較簡單。那麼,構建咱們本身的服務網格是否有意義呢?
若是咱們有適度的需求(若是咱們不須要可觀察性,斷路器,和其餘細節),咱們可能想創建本身的。可是若是咱們正在使用Kubernetes,咱們甚至可能不須要這樣作,由於Kubernetes已經提供了基本的服務發現和負載平衡。
如今,若是咱們有高級的需求,購買服務網格多是一個更好的選擇。(因爲Istio是開源的,因此它並不老是真正的購買,可是咱們仍然須要投入工程時間來理解它是如何工做、部署和運行的。)
如何選擇Istio、Linkerd和Consul Connect
到目前爲止,咱們只討論了Istio,但它並非惟一的服務網格。Linkerd是另外一個流行的選擇,還有Consul Connect。
實際上在這一點上我也很差說,我不認爲我有足夠的瞭解可以幫助任何人作決策。不過,已經有一些有趣的文章[2]比較它們,甚至基準測試。
一種值得一提而且頗有潛力的方法是使用像SuperGloo這樣的工具。SuperGloo提供了一個抽象層來簡化和統一服務網格公開的API。咱們可使用SuperGloo提供的更簡單的構造,並沒有縫地從一個服務網格切換到另外一個服務網格,而不是學習各類服務網格的特定API(在我看來,相對複雜)。有點像咱們有一個描述HTTP前端和後端的中間配置格式,可以爲NGINX、HAProxy、Traefik、Apache生成實際配置 我已經使用SuperGloo稍微涉足Istio,在將來的博客文章中,我想說明如何使用SuperGloo將Isio或Linkerd添加到現有的集羣中,以及後者是否能實現它的承諾,即容許我在不重寫配置的狀況下從一個路由網格切換到另外一個。
若是你喜歡這篇文章,而且想讓我嘗試一些具體的場景,我很樂意聽到你的消息!
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/protobuf.md#proposal-and-motivation
https://thenewstack.io/which-service-mesh-should-i-use/
原文連接:https://jpetazzo.github.io/2019/05/17/containers-microservices-service-meshes/
推薦閱讀:
什麼是Service Mesh?
基於SpringCloud的微服務架構演變史?
Spring Cloud中Hystrix、Ribbon及Feign的熔斷關係是什麼?
Spring Cloud微服務運維神器之Consul Template?
Python寫的微服務如何融入Spring Cloud體系?
Spring Cloud微服務接口這麼多怎麼調試?
Spring Boot集成Flyway實現數據庫版本控制?
Spring Cloud微服務如何實現熔斷降級?
Spring Cloud微服務如何設計異常處理機制?
Spring Cloud微服務中網關服務是如何實現的?(Zuul篇)
Spring Cloud是怎麼運行的?
Spring Boot究竟是怎麼運行的,你知道嗎?
—————END—————
識別圖片二維碼,關注「無敵碼農」獲取精彩內容
友情推廣|第六屆 Service Mesh Meetup 廣州站
讓各位久等了,第六屆Service Mesh Meetup廣州站開放報名了!涵蓋 Kubernetes、微服務和 Service Mesh 話題,8 月 11 日(星期日),廣州見!報名地址:https://tech.antfin.com/community/activities/781