如何實現微服務架構中的服務發現?
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

轉載出處:​如何實現微服務架構中的服務發現? 
原文地址:Service Discovery in a Microservices Architecture

編者按:在『應用架構一團糟?如何將單體應用改造為微服務』一文中,介紹瞭如何逐步地將單體應用改造為一系列的微服務。本文是系列文章的第四篇,將為大家講述如何在微服務架構實現服務發現。作者首先介紹了服務發現的兩種實現模式,接下來介紹了服務發現中最重要的服務註冊如何實現。

作者簡介:Chris Richardson是Cloudfoundry.com的創始人,現在為提供開發和部署應用的諮詢服務。

以下為譯文:

為什麼使用服務發現?

想象一下,如果你在寫程式碼呼叫一個有REST API或Thrift API的服務,你的程式碼需要知道一個服務例項的網路地址(IP地址和埠)。執行在物理硬體上的傳統應用中,服務例項的網路地址是相對靜態的,你的程式碼可以從一個很少更新的配置檔案中讀取網路地址。

在一個現代的,基於雲的微服務應用中,這個問題就變得複雜多了,如下圖所示: 
無服務發現時,無法確定連線的服務 
服務例項的網路地址是動態分配的。而且,由於自動擴充套件,失敗和更新,服務例項的配置也經常變化。這樣一來,你的客戶端程式碼需要一套更精細的服務發現機制。

有兩種主要的服務發現模式:客戶端服務發現(client-side discovery)和伺服器端服務發現(server-side discovery)。我們首先來看下客戶端服務發現。

客戶端服務發現模式

當使用客戶端服務發現的時候,客戶端負責決定可用的服務例項的網路地址,以及圍繞他們的負載均衡。客戶端向服務登錄檔(service registry)傳送一個請求,服務登錄檔是一個可用服務例項的資料庫。客戶端使用一個負載均衡演算法,去選擇一個可用的服務例項,來響應這個請求,下圖展示了這種模式的架構: 
客戶端發現模式 
一個服務例項被啟動時,它的網路地址會被寫到登錄檔上;當服務例項終止時,再從登錄檔中刪除。這個服務例項的登錄檔通過心跳機制動態重新整理。

Netflix OSS提供了一個客戶端服務發現的好例子。Netflix Eureka是一個服務登錄檔,提供了REST API用來管理服務例項的註冊和查詢可用的例項。Netflix Ribbon是一個IPC客戶端,和Eureka一起處理可用服務例項的負載均衡。下面會深入討論Eureka。

客戶端的服務發現模式有優勢也有缺點。這種模式相對直接,但是除了服務登錄檔,沒有其它動態的部分了。而且,由於客戶端知道可用的服務例項,可以做到智慧的,應用明確的負載均衡決策,比如一直用hash演算法。這種模式的一個重大缺陷在於,客戶端和服務登錄檔是一一對應的,必須為服務客戶端用到的每一種程式語言和框架實現客戶端服務發現邏輯。

伺服器端服務發現模式

下圖展示了這種模式的架構 
伺服器端服務發現模式 
客戶端通過負載均衡器向一個服務傳送請求,這個負載均衡器會查詢服務登錄檔,並將請求路由到可用的服務例項上。通過客戶端的服務發現,服務例項在服務登錄檔上被註冊和登出。

AWS的ELB(Elastic Load Blancer)就是一個伺服器端服務發現路由器。一個ELB通常被用來均衡來自網際網路的外部流量,也可以用ELB去均衡流向VPC(Virtual Private Cloud)的流量。一個客戶端通過ELB傳送請求(HTTP或TCP)時,使用的是DNS,ELB會均衡這些註冊的EC2例項或ECS(EC2 Container Service)容器的流量。沒有另外的服務登錄檔,EC2例項和ECS容器也只會在ELB上註冊。

HTTP伺服器和類似Nginx、Nginx Plus的負載均衡器也可以被用做伺服器端服務發現負載均衡器。例如,Consul Template可以用來動態配置Nginx的反向代理。

Consul Template定期從儲存在Consul服務登錄檔的資料中,生成任意的配置檔案。每當檔案變化時,會執行一個shell命令。比如,Consul Template可以生成一個配置反向代理的nginx.conf檔案,然後執行一個命令告訴Nginx去重新載入配置。還有一個更復雜的實現,通過HTTP API或DNS去動態地重新配置Nginx Plus。

有些部署環境,比如Kubernetes和Marathon會在叢集中的每個host上執行一個代理。這個代理承擔了伺服器端服務發現負載均衡器的角色。為了向一個服務傳送一個請求,一個客戶端使用host的IP地址和服務分配的埠,通過代理路由這個請求。這個代理會直接將請求傳送到叢集上可用的服務例項。

伺服器端服務發現模式也是優勢和缺陷並存。最大的好處在於服務發現的細節被從客戶端中抽象出來,客戶端只需要向負載均衡器傳送請求,不需要為服務客戶端使用的每一種語言和框架,實現服務發現邏輯;另外,這種模式也有一些問題,除非這個負載均衡器是由部署環境提供的,又是另一個高需要啟動和管理的可用的系統元件。

服務登錄檔(Service Registry)

服務登錄檔是服務發現的關鍵部分,是一個包含了服務例項的網路地址的資料庫,必須是高可用和最新的。客戶端可以快取從服務登錄檔處獲得的網路地址。但是,這些資訊最終會失效,客戶端會找不到服務例項。所以,服務登錄檔由一個伺服器叢集組成,通過應用協議來保持一致性。

正如上面提到的,Netflix Eureka是一個服務登錄檔的好例子。它提供了一個REST API用來註冊和查詢服務例項。一個服務例項通過POST請求來註冊自己的網路位置,每隔30秒要通過一個PUT請求重新註冊。登錄檔中的一個條目會因為一個HTTP DELETE請求或例項註冊超時而被刪除,客戶端通過一個HTTP GET請求來檢索註冊的服務例項。

Netflix通過在每個EC2的可用區中,執行一個或多個Eureka伺服器實現高可用。每個執行在EC2例項上的Eureka伺服器都有一個彈性的IP地址。DNS TEXT records用來儲存Eureka叢集配置,實際上是從可用區到Eureka伺服器網路地址的列表的對映。當一個Eureka伺服器啟動時,會向DNS傳送請求,檢索Eureka叢集的配置,定位節點,併為自己分配一個未佔用的彈性IP地址。

Eureka客戶端(服務和服務客戶端)查詢DNS去尋找Eureka伺服器的網路地址。客戶端更想使用這個可用區內的Eureka伺服器,如果沒有可用的Eureka伺服器,客戶端會用另一個可用區內的Eureka伺服器。

其它服務註冊的例子包括:

  • Etcd:一個高可用,分散式,一致的key-value儲存,用來共享配置和服務發現。Kubernetes和Cloudfoundry都使用了etcd;
  • Consul:一個發現和配置服務的工具。客戶端可以利用它提供的API,註冊和發現服務。Consul可以執行監控檢測來實現服務的高可用;
  • Apache Zookeeper:一個常用的,為分散式應用設計的高可用協調服務,最開始Zookeeper是Hadoop的子專案,現在已經頂級專案了。

一些系統,比如Kubernetes,Marathon和AWS沒有一個明確的服務註冊元件,這項功能是內建在基礎設定中的。

下面我們來看看服務例項如何在登錄檔中註冊。

服務註冊(Service Registration)

前面提到了,服務例項必須要從登錄檔中註冊和登出,有很多種方式來處理註冊和登出的過程。一個選擇是服務例項自己註冊,即self-registration模式。另一種選擇是其它的系統元件管理服務例項的註冊,即第third-party registration模式。

自注冊模式(The Self-Registration Pattern)

在self-registration模式中,服務例項負責從服務登錄檔中註冊和登出。如果需要的話,一個服務例項傳送心跳請求防止註冊過期。下圖展示了這種模式的架構: 
自注冊模式 
Netflix OSS Eureka客戶端是這種方式的一個好例子。Eureka客戶端處理服務例項註冊和登出的所有問題。spring Cloud實現包括服務發現在內的多種模式,簡化了Eureka的服務例項自動註冊。僅僅通過@EnableEurekaClient註釋就可以註釋Java的配置類

self-registration模式同樣也是優劣並存。優勢之一在於簡單,不需要其它元件。缺點是服務例項和服務登錄檔相對應,必須要為服務中用到的每種程式語言和框架實現註冊程式碼。

第三方註冊模式(The Third-Party Registration Pattern)

在third-party registration模式中,服務例項不會自己在服務登錄檔中註冊,由另一個系統元件service registrar負責。service registrar通過輪詢部署環境或訂閱事件去跟蹤執行中的例項的變化。當它注意到一個新的可用的服務例項時,就會到登錄檔中去註冊。service registrar也會將停止的服務例項登出,下圖展示了這種模式的架構。 
第三方註冊模式 
service registrar的一個例子是開源的Registrator專案。它會自動註冊和登出像Docker容器一樣部署的服務。Registrator支援etcd和Consul等服務註冊。

另一個service registrar的例子是NetflixOSS Prana。主要用於非JVM語言編寫的服務,它是一個和服務例項配合的『雙輪』應用。Prana會在Netflix Eureka上註冊和登出例項。

service registrar是一個部署環境的內建元件,由Autoscaling Group建立的EC2例項可以被ELB自動註冊。Kubernetes服務也可以自動註冊。

third-party registration模式主要的優勢在於解耦了服務和服務登錄檔。不需要為每個語言和框架都實現服務註冊邏輯。服務例項註冊由一個專用的服務集中實現。缺點是除了被內建到部署環境中,它本身也是一個高可用的系統元件,需要被啟動和管理。

總結

在一個微服務應用中,服務例項在執行時的配置也會動態變化,包括他們的網路地址。為了滿足客戶端向服務傳送請求的需要,必須要實現服務發現機制。

服務發現的關鍵部分是服務登錄檔。服務登錄檔是一個可用的服務例項的資料庫。服務登錄檔提供了一個管理API和一個查詢API。服務例項的註冊和登出通過管理API實現,查詢API用來尋找可用的服務例項。

有兩種主要的服務發現模式:客戶端服務發現和伺服器端服務發現。客戶端服務發現系統中,客戶端查詢服務登錄檔,選擇一個可用的例項,響應一個請求;在伺服器端服務發現系統中,客戶端通過一個路由器傳送請求,這個路由器會去查詢服務登錄檔,並將請求傳送給可用的例項。

有兩種形式可以實現服務例項的註冊和登出,一種是self-registration模式,一種是third-party registration模式。

一些部署環境中,需要通過類似Netflix Eureka,etcd或Apache Zookeeper的元件,啟動自己的服務發現基礎設施。其它的部署環境中,服務發現是內建的。比如,Kubernetes和Marathon處理服務例項的註冊和登出,還會在每個叢集host上執行一個代理,作為伺服器端服務發現路由器的角色。

一個HTTP反向代理和Nginx也可以被用做伺服器端服務發現負載均衡器。服務登錄檔可以推送路由資訊到Nginx,引起配置更新,比如可以用Consul Template。Nginx Plus支援動態的重配置機制,可以從登錄檔中拉取服務例項相關的資訊,還提供了遠端配置的API。

相關文章

程式語言 最新文章