再见 Nacos,我要玩 Service Mesh 了!
作者 | 姜橋
出品?| CSDN云計算(ID:CSDNcloud)
前面的文章<<干貨|如何步入Service Mesh微服務架構時代>>實戰演練了Service Mesh微服務架構的具體玩法,該案例中通過Istio+Kubernetes的組合,一組以Spring Boot框架開發的服務,在自身沒有實現任何服務注冊發現邏輯的情況下,被部署到Kubernetes后便能通過服務名直接完成服務接口調用,并且還能對調用進行限流、熔斷及負載均衡等一系列服務治理操作。
這一切是怎么發生的呢?在今天介紹Service Mesh微服務架構有關服務注冊發現原理的文章中將為大家揭曉答案。
傳統微服務注冊中心實現機制
在闡述Service Mesh服務注冊發現機制前,先簡單回顧下在以Spring Cloud為代表的傳統微服務中是如何實現服務注冊與發現的。
傳統微服務體系中,注冊中心無疑是整個微服務體系最重要的組成部分,沒有服務注冊中心提供的統一服務注冊發現功能,微服務本身就無從談起。不過相較于Service Mesh架構中服務注冊發現,很大程度上是依賴于基礎設施(例如數據面[envoy]、控制面[istio]以及Kubernetes集群),而無需微服務親力親為。在Spring Cloud傳統架構中,服務注冊、發現及健康性檢查等服務治理邏輯則都需要微服務自己上下打點。
雖然不用重復造輪子,都有現成的服務治理組件及框架,但從應用運行形態上說,與服務注冊發現相關的邏輯都是微服務直接與注冊中心產生的交互。從系統架構上看,這種方式顯然是將服務治理邏輯與業務應用耦合了,其運行邏輯如下圖所示:
從上圖可以看到,微服務啟動時會通過集成的服務發現SDK,向注冊中心(應用配置的注冊中心地址)發送注冊信息,注冊中心在收到服務注冊請求后將存儲服務的基本信息;之后,如有服務消費者要調用該服務,那么調用方通過服務發現組件(例如Ribbon)就可以向注冊中心查詢目標微服務的地址列表,并通過獲取的服務地址列表,以某種負載策略向目標微服務發起調用了。
而當服務節點發現變更時,新的節點會被重新注冊,而下線的節點基于服務探活機制也會及時從服務注冊中心被踢除,基于這樣的服務注冊/發現機制,微服務之間的通信順暢就能得到保證。從這個角度看,注冊中心與服務之間的健康性檢查就顯得很重要,如果注冊中心不能及時將下線或故障的節點從可用服務器地址列表剔除,那么就很可能會造成微服務某些調用的失敗。
那么一般怎樣進行服務健康性檢查呢?從方式上看,主流的健康性檢查方式,主要有以下3種:
1、微服務主動探活
服務主動探活就是微服務定期向注冊中心發送租約信息以表面自己的存活。在實際場景中主動探活是我們使用注冊中心時用得最多的一種方式,如果服務規模不大,或者使用了類似于Eureka這樣的最終一致性注冊中心,那么主動探活就是一種最佳選擇,它可以較大程度地避免服務部署在Kubernetes集群后,因為Pod IP重用而導致的舊有服務節點依然存活的問題,畢竟續約信息都是帶著服務基礎信息上報到注冊中心的。
但這種方式也有明顯的弊端,它會造成注冊中心寫操作壓力變大。如果大量的服務同時發布,節點產生較大的變動,那么就可能產生大量的通知事件,從而對整個微服務體系的穩定產生較大影響。
此外,主動續約,也并不完全說明服務是健康的,因為某些特殊情況下可能會存在雖然服務無法對外提供服務,但還能正常向注冊中心發出租約信息的問題。
2、注冊中心發起健康性檢查
前面分析了微服務主動探活方式的優缺點,而如果由注冊中心發起健康性檢查會怎么樣呢?
這種方式是指微服務在注冊時,同時向注冊中心暴露自己的健康檢查端點(如/actuator/health),注冊中心通過定期訪問來探測服務節點是否存活。
不過這種方式也不是完全沒有問題,例如前面提到的Pod IP重用問題,如果其他微服務重用了之前節點的IP,那么就會發生失效節點被激活的假象。當然也有相應的解決方案,例如后面會講到Istio微服務注冊發現時Envoy會對服務名稱進行二次Check的方式。
3、調用方負載均衡器進行健康性檢查
第3種方案比較極端,注冊中心不進行任何服務探活,全部由微服務調用方所在的負載均衡器進行探活。這種方案常見的一種場景就是gRPC的失效節點自動摘除功能。但這種方案依然具有IP被重用問題,所以此種方式在實際的場景中并不是很受歡迎。
前面講了微服務注冊發現常見的三種服務探活方式,其實三種方案各有利弊。以Spring Cloud微服務體系中,使用最廣泛的幾種注冊中心為例,如Eureka、Consul、Nacos,它們的對比如下表所示:
從表格中可以看到,除了Eureka主要采用服務主動探活方式外,Consul及Nacos都采用了多種服務探活方式,從而盡量規避不同方式的弊端,這也是為什么目前大部分實踐逐步拋棄Eureka而采用Consul或Nacos的原因。
除了健康性檢查外,上面表格還分別列出了這幾種注冊中心的一致性協議。這里順帶普及下CAP理論。CAP是分布式系統中重要的一種概念,它分別由一致性(Consistency)、可用性(Availability)、分區容錯性(Partition tolerance)三部分組成。在CAP理論中,一個分布式系統不可能三種都滿足,一般只能同時滿足其中的兩種,例如Eureka和Nacos只能滿足可用性和分區容錯性,而無法滿足一致性;Consul則只能滿足一致性和分區容錯性,而無法完全滿足可用性。
在注冊中心的場景中,一致性一般要求并不高,只要能達到最終一致性即可。畢竟在微服務架構中,涉及節點的注冊和反注冊,注冊中心和客戶端之間的通信需要一定時間,一致性本身也很難達到。所以在注冊中心的選型中,一般會優先選擇AP的系統,這也是目前還在以Spring Cloud構建微服務的實踐中,除了自研外,開源技術中會優先選擇Nacos作為服務注冊中心的原因。
Kubernetes服務注冊與自動發現
前面以一定篇幅回顧了Spring Cloud傳統微服務體系中,注冊中心有關的基本邏輯及常見開源技術。在具體講述Service Mesh架構中服務注冊發現的邏輯前,有必要先了解下Kubernetes容器編排中,與Service服務資源有關的概念。
因為最流行的Service Mesh方案(如Istio),大都選擇了與Kubernetes集群相結合的方案,而其服務注冊邏輯也主要是利用了Kubernetes的內部服務發現機制。例如Istio就是通過監聽Kubernetes Pod的變化來實現服務發現的。當然這并不是說在Service Mesh中不能選擇傳統的注冊中心方案,只不過實施起來可能需要改造或自研注冊中心才能滿足需求(兼容新舊微服務體系時,可能會這么考慮)。如果是全新設計的Service Mesh微服務架構,最佳的方案還是選擇像Istio這樣直接利用Kubernetes自身功能實現服務發現。
在Kubernetes中能夠為Service Mesh微服務提供內部服務注冊發現的基礎就是Service類型的資源。Service是Kubernetes抽象出來的服務概念,一組Pod的集合就是Kubernetes的Service。在Kubernetes中Pod是最小的容器編排單元,一個Pod編排資源中可以定義多個容器,Pod內的容器可以通過本地訪問在Pod中通信,一組容器共享一個Pod IP,這就是Kubernetes之所以被稱為容器編排平臺最核心的體現。
但Pod是有生命周期的,也就是說Pod的IP地址并不固定,它會隨著Pod生命周期的變化而變化,所以如果以Pod為服務調用對象,那么IP地址的經常變化會導致調用方服務發現邏輯不穩定,從而使系統變得復雜。為了解決這個問題,Kubernetes中就抽象出了Service資源類型,雖然Pod的IP地址會變化,但是抽象的Service名稱卻是固定的,所以Kubernetes集群中通過Service名稱就能訪問這些后端IP,調用方則不用再直接感知這些后端Pod IP的變化了。具體Pod與Service之間的映射關系,則完全由Kubernetes集群本身來實現。它們之間的關系如下圖所示:
如上圖所示,現在要負載均衡地訪問一組相同的服務副本——訂單,通過Service資源類型的定義,就可以將其對外表示成一個進程或服務資源對象,Kubernetes會為其分配集群內的固定IP地址,之后通過請求Service(集群內用名稱、集群外可通過Ingress或NodePort方式暴露),Service自己就會負載均衡地將請求轉發給相應的Pod節點。
Service資源與Pod編排對象之間的關聯,雖說從實現上是由Kubernetes集群自己管理的,但在服務發布時則是需要我們自己通過資源定義進行關聯。以一段Kuberntes發布代碼為例:
apiVersion:?v1 kind:?Service metadata:name:?micro-orderlabels:app:?micro-orderservice:?micro-order spec:type:?ClusterIPports:-?name:?http#此處設置80端口的原因在于改造的Mock?FeignClient代碼默認是基于80端口進行服務調用port:?80targetPort:?9091selector:app:?micro-order--- apiVersion:?apps/v1 kind:?Deployment metadata:name:?micro-order-v1labels:app:?micro-orderversion:?v1 spec:replicas:?2selector:matchLabels:app:?micro-orderversion:?v1template:metadata:labels:app:?micro-orderversion:?v1spec:containers:-?name:?micro-orderimage:?10.211.55.2:8080/micro-service/micro-order:1.0-SNAPSHOTimagePullPolicy:?Alwaystty:?trueports:-?name:?httpprotocol:?TCPcontainerPort:?19091#環境參數設置(設置微服務返回gRPC服務端的地址+端口)env:-?name:?GRPC_SERVER_HOSTvalue:?micro-pay-?name:?GRPC_SERVER_PORTvalue:?"18888"如上述Kubernetes發布文件中高亮的代碼,在定義Pod編排對象時通過metadata標簽定義了這一組Service的label,然后通過selector標簽指定響應的標簽,這樣Service就可以訪問帶有這組標簽定義的Pod集合了。
以上就是Kubernetes實現服務注冊發現基本原理,其中涉及的邏輯將被利用在Service Mesh微服務平臺Istio的設計實現中。
Istio服務注冊發現
接下來我們以Istio(基于istio1.9架構)為代表的Service Mesh架構為例,看看它是如何實現服務注冊發現的。經過前面的鋪墊,相信你多少已經了解了一點Istio實現服務注冊發現的基本原理:“通過監聽Kubernetes節點變化及Service資源類型實現”。
接下來我們將進一步細化它,從運行邏輯的視角來分析下在Istio中控制面與數據面是如何配合實現微服務注冊發現的。具體如下圖所示:
上圖所描述的就是Istio基于Kubernetes實現微服務注冊發現的核心邏輯。Kubernetes集群環境安裝Istio后,Kubernetes在創建Pod時,就會通過Kube-APIserver調用控制面組件的Sidecar-Injector服務、自動修改應用程序的描述信息并將其注入SideCar,之后在創建業務容器的Pod中同時創建SideCar代理容器。SideCar則會通過xDS協議與Istio控制面各組件連接,這里我們著重介紹Pilot控制面組件實現服務發現的內容。
首先明確的是在新版的Istio中,服務發現的邏輯已經上移至控制面組件Pilot,Pilot會監聽Kube-APIServer中關于Service、Endpoint、Pod等資源的變化,并實時下發給各微服務SideCar中的Pilot Agent代理組件。這個過程是通過xDS標準協議下發的,而下發的基本邏輯是Envoy啟動時Pilot會把所有服務實例信息推送給Envoy,后續則是有更新就推送更新數據至所有Envoy,這樣各個微服務的Envoy就能實時感知微服務實例節點的變化了。
這種方式保證各個微服務的Envoy代理能隨時感知到Kubernetes集群中服務節點的變化,也天然實現了微服務的健康性檢測邏輯,當然為了防止Pod IP重用的問題,Envoy在接收Pilot推送的變動實例信息時也會對服務名稱進行二次Check,如果發現IP所對應的Service名稱與之前不一致,則及時更新本地數據信息,防止調用出錯。
通過上述服務發現系統的支持,服務消費方在調用目標微服務時,流量會被本Pod中的Envoy代理自動劫持,此時Envoy就會根據自身存儲的服務實例映射信息,及控制面配置下發的服務治理規則,對調用執行負載均衡、熔斷、限流等服務治理規則。
這就是以Istio為代表的Service Mesh微服務架構實現服務注冊發現的基本邏輯,可以看到Envoy數據面與Pilot控制面組件的配合自動實現了服務發現邏輯,而這一切對微服務本身來說都是無感知的!
后記
本篇文章簡單總結和概述了從傳統微服務架構到Service Mesh有關服務注冊發現邏輯的變化,也進一步從側面也感受到了以Istio為代表的Service Mesh微服務架構,在架構設計理念上的進步。希望本篇文章的內容能夠對你有所啟發,并進一步打開你進入Service Mesh微服務架構時代的窗戶,在后面的文章中我們還會進一步分享與Service Mesh原理和實踐相關的知識,敬請期待!
參考文檔:
#Istio 1.9流量管理官方文檔(英文版)
https://istio.io/latest/docs/concepts/traffic-management/#introducing-istio-traffic-management
#Istio 1.9流量管理官方文檔(中文版)
https://istio.io/latest/zh/docs/concepts/traffic-management/
#Sidecar資源隔離配置參考文檔
https://istio.io/latest/docs/reference/config/networking/sidecar
作者簡介:
姜橋 畢業于長春工業大學,曾就職于摩拜單車,設計研發日訂單千萬級支付系統;現任職于馬蜂窩旅行網,負責業務系統的微服務架構轉型及中臺系統。
今晚(2021.4.16)19:30,軟考工程師備考上分攻略,提升你的復習戰斗技巧! 立即掃碼進群,預約直播,拿超級福利大禮包! 更多精彩推薦 ?5G、射頻、奧特曼,這仨有聯系嗎??繼云計算巨頭失火后,微軟決定送數據中心去“泡澡”!?有沒有不用加班的程序員?如何衡量程序員的工作量?點分享點收藏點點贊點在看總結
以上是生活随笔為你收集整理的再见 Nacos,我要玩 Service Mesh 了!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CPU:别再拿我当搬砖工!
- 下一篇: 北森完成2.6亿美金融资,一体化×低代码