1. 程式人生 > >Chris Richardson 微服務系列 第四篇 微服務中的服務發現

Chris Richardson 微服務系列 第四篇 微服務中的服務發現

這是使用微服務構建應用的第四篇文章。第一篇文章介紹了微服務架構模式並討論了使用微服務的優勢和劣勢,該系列的第二和第三篇文章 描述了微服務架構中通訊的不同方面,本篇文章我們將密切討論下服務發現的問題。

為什麼使用服務發現

設想下,我們寫了一些通過REST API或者Thrift API呼叫某個服務的程式碼,為了發起這個請求,你的程式碼需要知道服務例項的網路地址(IP 地址和埠號)。在傳統執行在物理機器上的應用中,某個服務例項的網路地址一般是靜態的,比如,程式碼可以從只會偶爾更新的配置檔案中讀取網路地址。 然而在現在流行的基於雲平臺的微服務應用中, 有更多如下圖所示的困難問題需要去解決:

Paste_Image.png

服務例項需要動態分配網路地址,而且,一組服務例項可能會因為自動擴充套件、失敗或者升級發生動態變化,因此 你的客戶端程式碼應該使用更加精細的服務發現機制。 有兩種主要的服務發現機制:

客戶端發現服務端發現。讓我們先看客戶端發現機制。

客戶端發現模式

當我們使用 客戶端發現的時候,客戶端負責決定可用服務例項的網路地址並且在叢集中對請求負載均衡, 客戶端訪問服務登記表,也就是一個可用服務的資料庫,然後客戶端使用一種負載均衡演算法選擇一個可用的服務例項然後發起請求。 下圖展示了該結構模式:

Paste_Image.png

服務例項的網路地址在服務啟動的時候被登記到服務登錄檔中 ,當例項終止服務時從服務登錄檔中移除。服務例項的註冊一般是通過心跳機制階段性的進行重新整理。

Netflix OSS 為客戶端發現機制提供了很多優秀的例子。Netflix Eureka 實現了服務登錄檔,它通過提供REST API來管理服務例項註冊以及可用例項的查詢。

Netflix Ribbon 是一個與Eureka一起使用並在多個可用例項間對請求負載均衡的IPC客戶端。我們將在下面文章深入討論Eureka。

客戶端發現機制有諸多優勢和劣勢:該模式除了服務登錄檔之外沒有其他的活動部分了,相對來說還是簡單直接的,而且,由於客戶端知道相關的可用服務例項,那麼就可以使用更加智慧的,特定於應用的負載均衡機制,比如一致性雜湊。一個明顯的缺點是它把客戶端與服務登錄檔緊耦合了,你必須為每一種消費服務的客戶端對應的程式語言和框架實現服務發現邏輯。

現在看完了客戶端發現,再讓我們看下服務端發現吧。

服務端發現模式

服務發現的另一種模式就是服務端發現模式。下圖展示了該模式的結構:

Paste_Image.png

客戶端通過一個負載均衡器向服務傳送請求,負載均衡器查詢服務登錄檔並把請求路由到一臺可用的服務例項上。和客戶端發現一樣,服務例項通過服務登錄檔進行服務的註冊和登出。

AWS Elastic Load Balancer (ELB) 是服務端發現路由的一個示例。一個ELB通常對來自外部網際網路的請求進行負載均衡,當然,你也可以使用ELB對虛擬私有云(VPC)的內部請求進行負載均衡。客戶端通過DNS域名向ELB發起HTTP或者TCP請求,ELB將請求負載均衡到一系列註冊的Elastic Compute Cloud (EC2) 例項 或者EC2 Container Service (ECS) 的容器中,兩者並沒有分割的服務登錄檔,EC2 例項和ECS容器都是通過ELB進行註冊的。

類似NGINX PLUG和NGINX這些HTTP伺服器和負載均衡器可以作為服務端發現負載均衡來使用。比如 這篇部落格 就描述了使用Consul Template 動態重配置NGINX反向代理,Consul Template是一種根據儲存在Consul 服務登錄檔的配置資料階段性重新生成任意配置檔案的工具 ,每當檔案發生變化時,它將執行任意的Shell 命令。在部落格描述的例子中,Consul Template 生成用於配置反向代理的nginx.conf檔案,然後執行一個命令列告知NGINX過載配置。更復雜的實現可能使用 HTTP API or DNS動態重配置NGINX Plus。

一些部署環境使用諸如KubernetesMarathon在叢集中的每個主機上執行一個代理,這些代理扮演了服務端發現負載均衡的角色,代理可以根據主機IP地址和服務分配的埠號來路由客戶端請求,代理因此可以透明的把客戶端請求轉發到叢集中某臺可用的服務例項上去。

服務端發現模式有一些優勢也有一些劣勢:一個巨大的優勢是,服務發現的細節對客戶端來說是抽象的,客戶端僅需向負載均衡器傳送請求即可。這種方式減少了為消費服務的不同程式語言與框架實現服務發現邏輯的麻煩。當然,正如前面所述,一些部署環境已經提供了該功能。這種模式也有一些劣勢: 除非部署環境已經提供了負載均衡器,否則這又是一個需要額外設定和管理的可高可用的系統元件。

服務登錄檔

服務登錄檔 是服務發現的關鍵部分,它是一個包含服務例項網路地址的的資料庫。一個服務登錄檔需要高可用和實時更新,客戶端可以快取從服務登錄檔獲取的網路地址。然而,這樣的話快取的資訊最終會過期,客戶端不能再根據該資訊發現服務例項。因此,服務登錄檔對叢集中的服務例項使用複製協議來維護一致性。

之前也提到 Netflix Eureka 是服務登錄檔的好例子,它為服務例項的註冊與查詢提供了REST API:一個服務例項可以使用POST來註冊自己的網路地址,它必須每30秒通過PUT去重新整理,服務例項可以直接或者在服務例項註冊超時的時候使用DELETE刪除登錄檔中的資訊,正如你所料,客戶端可以使用HTTP GET獲取註冊例項的資訊。

Netflix通過在每一個Amazon EC2 availability zone執行一到多個Eureka服務 實現高可用 。每一個Eureka伺服器執行在一個關聯 Elastic IP地址的 EC2 例項上。DNS TEXT記錄了Eureka叢集的配置檔案,配置檔案對映availability zones到一組Eureka伺服器可用的網路地址。 Eureka 伺服器啟動的時候將會查詢DNS獲取Eureka叢集的配置、查詢同等節點併為自己分配一個未被使用的Elastic IP地址。

Eureka clients – services和service clients,通過查詢DNS發現Eureka伺服器的網路地址。客戶端更傾向使用在同一availability zone中的Eureka伺服器,當然,如果該zone中沒有可用的網路地址,它將使用另一zone中的。

其他的服務登錄檔例子包括:

  • etcd ,一個高可用、分散式、一致性、key-value 方式的儲存,被用在分享配置和服務發現中。兩個著名的專案使用了它:Kubernetes 和 Cloud Foundry.
  • consul ,一個發現和配置服務的工具,為客戶端註冊和發現服務提供了API,Consul還可以通過執行健康檢查決定服務的可用性。
  • Apache Zookeeper ,是一個廣泛使用、高效能的針對分散式應用的協調服務。 Apache Zookeeper本來是Hadoop的子工程,現在已經是頂級工程了。

正如前面所述,一些諸如Kubernetes、Marathon和AWS之類的應用並沒有顯示的服務登錄檔,相反,服務登錄檔是架構內建的一部分。

我們已經看過了服務登錄檔的概念,現在我們看下服務例項是如何使用登錄檔註冊的:

服務註冊選項

正如前面提到的那樣,服務例項必須使用服務登錄檔來進行服務的註冊和登出,我們有幾種方式來處理服務的註冊和登出,其中之一是服務例項自己註冊自己也就是self-registration 模式,另一種是系統的其他元件管理服務例項的註冊,也就是 third-party registration 模式.。我們先看下self-registration模式:

Self-Registration模式

當使用self-registration 模式,時,服務例項自己負責通過服務登錄檔對自己進行註冊和登出,另外如果有必要的話,服務例項可以通過傳送心跳請求防止註冊過期,下圖展示了該模式的結構:

Paste_Image.png

Netflix OSS Eureka client就是這種模式的一個例子,Eureka客戶端處理服務例項註冊和登出的各個方面。Spring Cloud project實現了包括服務發現在內的不同模式,使得自動註冊服務例項到Eureka變的簡單。你可以簡單的在你的java配置類上新增@EnableEurekaClient註解即可。

self-registration模式有一些優勢也有一些劣勢:優勢之一是它相對簡單,而且不強制使用其他的系統元件。然而,一個很大的劣勢是 它使得服務例項和服務登錄檔強耦合 ,你必須在每一個使用服務的客戶端程式語言和架構程式碼中實現註冊邏輯。

解綁服務和服務登錄檔的另一替換方案是,使用third-party registration 模式。

Third-Party Registration模式

當使用third-party registration 模式的時候,服務例項本身並不負責通過服務登錄檔註冊自己,相反的,通過另一個被稱作 service registrar系統元件來處理註冊。 service registrar通過輪詢或者訂閱事件來檢測一些執行例項的變化,當它檢測到一個新的可用服務例項時就把該例項註冊到服務登錄檔中去,service registrar還負責登出已經被終止的服務例項,下圖展示了該模式的架構:

Paste_Image.png

service registrar其中一個例子是開源的Registrator 專案,它自動的對部署到Docker 容器中的服務例項進行註冊和登出。 Registrator支援不同的服務登錄檔,包括etcd和Consul。

service registrar的另一個例子是 NetflixOSS Prana,原本是為非JVM語言的服務所設計,它像服務例項的跨鬥一樣和服務例項一起執行,Prana使用Netflix Eureka對服務進行註冊和登出。

service registrar是部署環境的內建元件,EC2例項可以自動擴充套件組 並可使用ELB進行服務註冊。Kubernetes 服務是自動註冊的並能使其可以被發現。

third-party registration模式有一些優勢也有一些劣勢:主要優勢是使得服務從服務登錄檔中被解耦,你不必為開發者使用的每種開發語言和框架實現服務註冊的邏輯,相反,服務例項的註冊被一個專有服務以集中式的方式處理。

該模式的劣勢是,除非它被內建在部署環境中,不然這又是一個需要被設定和管理的高可用系統元件。

總結

在一個微服務應用中,一組執行的服務例項是動態變化的,例項有動態分配的網路地址,因此,為了使得客戶端能夠向服務發起請求,必須要要有服務發現機制。

服務發現的關鍵是服務登錄檔,服務登錄檔是可用服務例項的資料庫,它提供了管理和查詢使用的API。服務例項使用這些管理API進行服務的註冊和登出,系統元件使用查詢API來發現可用的服務例項。

有兩種服務發現的模式:客戶端發現和服務端發現。在使用客戶端發現模式的系統中,客戶端直接查詢服務登錄檔,選擇一個可用的例項併發起請求,在一個使用服務端發現模式的系統中,客戶端通過路由發起請求,路由會查詢服務登錄檔並把請求轉發到可用的服務例項上。

對服務例項來講有兩種方式可以對服務登錄檔進行註冊和登出,一種是服務例項本身通過服務登錄檔來註冊自己,也就是self-registration模式,另一種則是第三方系統元件代表例項來處理服務的註冊和登出,也就是third-party registration模式

在一些部署環境中,你需要使用諸如Netflix Eurekaetcd, 或者Apache Zookeeper這樣的服務登錄檔來設定你自己的服務發現架構。在另一些部署環境中,服務發現則是內建元件,比如KubernetesMarathon用來處理服務註冊和登出,他們同樣也在叢集的每一個主機上執行一個代理來扮演服務端發現路由的角色。

一些諸如NGINX的HTTP反向代理和負載均衡器 可以用作服務端發現負載均衡器使用,服務登錄檔可以向NGINX推送路由資訊並呼叫優雅的配置更新,比如,你可以使用Consul Template。 NGINX Plus 支援額外的動態重配置機制 :它可以使用DNS從服務登錄檔 拉取服務例項的資訊,並且為遠端重配置提供API。

在該系列之後的文章中我們將繼續挖掘微服務的各個方面。

作者:nonumber1989 連結:http://www.jianshu.com/p/1bf9a46efe7a 來源:簡書 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。