微服務(wù)中的服務(wù)發(fā)現(xiàn)

原文鏈接:Service Discovery in a Microservices Architecture

  1. 微服務(wù)介紹
  2. 構(gòu)建微服務(wù)之使用API網(wǎng)關(guān)
  3. 構(gòu)建微服務(wù)之:微服務(wù)架構(gòu)中的進(jìn)程間通信
  4. 微服務(wù)中的服務(wù)發(fā)現(xiàn)(本文)
  5. 微服務(wù)之事件驅(qū)動的數(shù)據(jù)管理
  6. 選擇一種微服務(wù)部署策略
  7. 重構(gòu)單體應(yīng)用到微服務(wù)

這是使用微服務(wù)構(gòu)建應(yīng)用的第四篇文章。第一篇文章介紹了微服務(wù)架構(gòu)模式并討論了使用微服務(wù)的優(yōu)勢和劣勢,該系列的第二和第三篇文章 描述了微服務(wù)架構(gòu)中通信的不同方面,本篇文章我們將密切討論下服務(wù)發(fā)現(xiàn)的問題。

為什么使用服務(wù)發(fā)現(xiàn)

設(shè)想下,我們寫了一些通過REST API或者Thrift API調(diào)用某個服務(wù)的代碼,為了發(fā)起這個請求,你的代碼需要知道服務(wù)實例的網(wǎng)絡(luò)地址(IP 地址和端口號)。在傳統(tǒng)運(yùn)行在物理機(jī)器上的應(yīng)用中,某個服務(wù)實例的網(wǎng)絡(luò)地址一般是靜態(tài)的,比如,代碼可以從只會偶爾更新的配置文件中讀取網(wǎng)絡(luò)地址。
然而在現(xiàn)在流行的基于云平臺的微服務(wù)應(yīng)用中, 有更多如下圖所示的困難問題需要去解決:

Paste_Image.png

服務(wù)實例需要動態(tài)分配網(wǎng)絡(luò)地址,而且,一組服務(wù)實例可能會因為自動擴(kuò)展、失敗或者升級發(fā)生動態(tài)變化,因此 你的客戶端代碼應(yīng)該使用更加精細(xì)的服務(wù)發(fā)現(xiàn)機(jī)制。
有兩種主要的服務(wù)發(fā)現(xiàn)機(jī)制:客戶端發(fā)現(xiàn)服務(wù)端發(fā)現(xiàn)。讓我們先看客戶端發(fā)現(xiàn)機(jī)制。

客戶端發(fā)現(xiàn)模式

當(dāng)我們使用 客戶端發(fā)現(xiàn)的時候,客戶端負(fù)責(zé)決定可用服務(wù)實例的網(wǎng)絡(luò)地址并且在集群中對請求負(fù)載均衡, 客戶端訪問服務(wù)登記表,也就是一個可用服務(wù)的數(shù)據(jù)庫,然后客戶端使用一種負(fù)載均衡算法選擇一個可用的服務(wù)實例然后發(fā)起請求。
下圖展示了該結(jié)構(gòu)模式:

Paste_Image.png

服務(wù)實例的網(wǎng)絡(luò)地址在服務(wù)啟動的時候被登記到服務(wù)注冊表中 ,當(dāng)實例終止服務(wù)時從服務(wù)注冊表中移除。服務(wù)實例的注冊一般是通過心跳機(jī)制階段性的進(jìn)行刷新。

Netflix OSS 為客戶端發(fā)現(xiàn)機(jī)制提供了很多優(yōu)秀的例子。Netflix Eureka 實現(xiàn)了服務(wù)注冊表,它通過提供REST API來管理服務(wù)實例注冊以及可用實例的查詢。Netflix Ribbon 是一個與Eureka一起使用并在多個可用實例間對請求負(fù)載均衡的IPC客戶端。我們將在下面文章深入討論Eureka。

客戶端發(fā)現(xiàn)機(jī)制有諸多優(yōu)勢和劣勢:該模式除了服務(wù)注冊表之外沒有其他的活動部分了,相對來說還是簡單直接的,而且,由于客戶端知道相關(guān)的可用服務(wù)實例,那么就可以使用更加智能的,特定于應(yīng)用的負(fù)載均衡機(jī)制,比如一致性哈希。一個明顯的缺點是它把客戶端與服務(wù)注冊表緊耦合了,你必須為每一種消費(fèi)服務(wù)的客戶端對應(yīng)的編程語言和框架實現(xiàn)服務(wù)發(fā)現(xiàn)邏輯。

現(xiàn)在看完了客戶端發(fā)現(xiàn),再讓我們看下服務(wù)端發(fā)現(xiàn)吧。

服務(wù)端發(fā)現(xiàn)模式

服務(wù)發(fā)現(xiàn)的另一種模式就是服務(wù)端發(fā)現(xiàn)模式。下圖展示了該模式的結(jié)構(gòu):

Paste_Image.png

客戶端通過一個負(fù)載均衡器向服務(wù)發(fā)送請求,負(fù)載均衡器查詢服務(wù)注冊表并把請求路由到一臺可用的服務(wù)實例上。和客戶端發(fā)現(xiàn)一樣,服務(wù)實例通過服務(wù)注冊表進(jìn)行服務(wù)的注冊和注銷。

AWS Elastic Load Balancer (ELB) 是服務(wù)端發(fā)現(xiàn)路由的一個示例。一個ELB通常對來自外部互聯(lián)網(wǎng)的請求進(jìn)行負(fù)載均衡,當(dāng)然,你也可以使用ELB對虛擬私有云(VPC)的內(nèi)部請求進(jìn)行負(fù)載均衡??蛻舳送ㄟ^DNS域名向ELB發(fā)起HTTP或者TCP請求,ELB將請求負(fù)載均衡到一系列注冊的Elastic Compute Cloud (EC2) 實例 或者EC2 Container Service (ECS) 的容器中,兩者并沒有分割的服務(wù)注冊表,EC2 實例和ECS容器都是通過ELB進(jìn)行注冊的。

類似NGINX PLUG和NGINX這些HTTP服務(wù)器和負(fù)載均衡器可以作為服務(wù)端發(fā)現(xiàn)負(fù)載均衡來使用。比如 這篇博客 就描述了使用Consul Template 動態(tài)重配置NGINX反向代理,Consul Template是一種根據(jù)存儲在Consul 服務(wù)注冊表的配置數(shù)據(jù)階段性重新生成任意配置文件的工具 ,每當(dāng)文件發(fā)生變化時,它將運(yùn)行任意的Shell 命令。在博客描述的例子中,Consul Template 生成用于配置反向代理的nginx.conf文件,然后運(yùn)行一個命令行告知NGINX重載配置。更復(fù)雜的實現(xiàn)可能使用 HTTP API or DNS動態(tài)重配置NGINX Plus。

一些部署環(huán)境使用諸如KubernetesMarathon在集群中的每個主機(jī)上運(yùn)行一個代理,這些代理扮演了服務(wù)端發(fā)現(xiàn)負(fù)載均衡的角色,代理可以根據(jù)主機(jī)IP地址和服務(wù)分配的端口號來路由客戶端請求,代理因此可以透明的把客戶端請求轉(zhuǎn)發(fā)到集群中某臺可用的服務(wù)實例上去。

服務(wù)端發(fā)現(xiàn)模式有一些優(yōu)勢也有一些劣勢:一個巨大的優(yōu)勢是,服務(wù)發(fā)現(xiàn)的細(xì)節(jié)對客戶端來說是抽象的,客戶端僅需向負(fù)載均衡器發(fā)送請求即可。這種方式減少了為消費(fèi)服務(wù)的不同編程語言與框架實現(xiàn)服務(wù)發(fā)現(xiàn)邏輯的麻煩。當(dāng)然,正如前面所述,一些部署環(huán)境已經(jīng)提供了該功能。這種模式也有一些劣勢: 除非部署環(huán)境已經(jīng)提供了負(fù)載均衡器,否則這又是一個需要額外設(shè)置和管理的可高可用的系統(tǒng)組件。

服務(wù)注冊表

服務(wù)注冊表 是服務(wù)發(fā)現(xiàn)的關(guān)鍵部分,它是一個包含服務(wù)實例網(wǎng)絡(luò)地址的的數(shù)據(jù)庫。一個服務(wù)注冊表需要高可用和實時更新,客戶端可以緩存從服務(wù)注冊表獲取的網(wǎng)絡(luò)地址。然而,這樣的話緩存的信息最終會過期,客戶端不能再根據(jù)該信息發(fā)現(xiàn)服務(wù)實例。因此,服務(wù)注冊表對集群中的服務(wù)實例使用復(fù)制協(xié)議來維護(hù)一致性。

之前也提到 Netflix Eureka 是服務(wù)注冊表的好例子,它為服務(wù)實例的注冊與查詢提供了REST API:一個服務(wù)實例可以使用POST來注冊自己的網(wǎng)絡(luò)地址,它必須每30秒通過PUT去刷新,服務(wù)實例可以直接或者在服務(wù)實例注冊超時的時候使用DELETE刪除注冊表中的信息,正如你所料,客戶端可以使用HTTP GET獲取注冊實例的信息。

Netflix通過在每一個Amazon EC2 availability zone運(yùn)行一到多個Eureka服務(wù) 實現(xiàn)高可用 。每一個Eureka服務(wù)器運(yùn)行在一個關(guān)聯(lián) Elastic IP地址的 EC2 實例上。DNS TEXT記錄了Eureka集群的配置文件,配置文件映射availability zones到一組Eureka服務(wù)器可用的網(wǎng)絡(luò)地址。 Eureka 服務(wù)器啟動的時候?qū)樵僁NS獲取Eureka集群的配置、查詢同等節(jié)點并為自己分配一個未被使用的Elastic IP地址。

Eureka clients – services和service clients,通過查詢DNS發(fā)現(xiàn)Eureka服務(wù)器的網(wǎng)絡(luò)地址??蛻舳烁鼉A向使用在同一availability zone中的Eureka服務(wù)器,當(dāng)然,如果該zone中沒有可用的網(wǎng)絡(luò)地址,它將使用另一zone中的。

其他的服務(wù)注冊表例子包括:

  • etcd ,一個高可用、分布式、一致性、key-value 方式的存儲,被用在分享配置和服務(wù)發(fā)現(xiàn)中。兩個著名的項目使用了它:Kubernetes 和 Cloud Foundry.
  • consul ,一個發(fā)現(xiàn)和配置服務(wù)的工具,為客戶端注冊和發(fā)現(xiàn)服務(wù)提供了API,Consul還可以通過執(zhí)行健康檢查決定服務(wù)的可用性。
  • Apache Zookeeper ,是一個廣泛使用、高性能的針對分布式應(yīng)用的協(xié)調(diào)服務(wù)。 Apache Zookeeper本來是Hadoop的子工程,現(xiàn)在已經(jīng)是頂級工程了。

正如前面所述,一些諸如Kubernetes、Marathon和AWS之類的應(yīng)用并沒有顯示的服務(wù)注冊表,相反,服務(wù)注冊表是架構(gòu)內(nèi)置的一部分。

我們已經(jīng)看過了服務(wù)注冊表的概念,現(xiàn)在我們看下服務(wù)實例是如何使用注冊表注冊的:

服務(wù)注冊選項

正如前面提到的那樣,服務(wù)實例必須使用服務(wù)注冊表來進(jìn)行服務(wù)的注冊和注銷,我們有幾種方式來處理服務(wù)的注冊和注銷,其中之一是服務(wù)實例自己注冊自己也就是self-registration 模式,另一種是系統(tǒng)的其他組件管理服務(wù)實例的注冊,也就是 third-party registration 模式.。我們先看下self-registration模式:

Self-Registration模式

當(dāng)使用self-registration 模式,時,服務(wù)實例自己負(fù)責(zé)通過服務(wù)注冊表對自己進(jìn)行注冊和注銷,另外如果有必要的話,服務(wù)實例可以通過發(fā)送心跳請求防止注冊過期,下圖展示了該模式的結(jié)構(gòu):

Paste_Image.png

Netflix OSS Eureka client就是這種模式的一個例子,Eureka客戶端處理服務(wù)實例注冊和注銷的各個方面。Spring Cloud project實現(xiàn)了包括服務(wù)發(fā)現(xiàn)在內(nèi)的不同模式,使得自動注冊服務(wù)實例到Eureka變的簡單。你可以簡單的在你的java配置類上添加@EnableEurekaClient注解即可。

self-registration模式有一些優(yōu)勢也有一些劣勢:優(yōu)勢之一是它相對簡單,而且不強(qiáng)制使用其他的系統(tǒng)組件。然而,一個很大的劣勢是 它使得服務(wù)實例和服務(wù)注冊表強(qiáng)耦合 ,你必須在每一個使用服務(wù)的客戶端編程語言和架構(gòu)代碼中實現(xiàn)注冊邏輯。

解綁服務(wù)和服務(wù)注冊表的另一替換方案是,使用third-party registration 模式。

Third-Party Registration模式

當(dāng)使用third-party registration 模式的時候,服務(wù)實例本身并不負(fù)責(zé)通過服務(wù)注冊表注冊自己,相反的,通過另一個被稱作 service registrar系統(tǒng)組件來處理注冊。 service registrar通過輪詢或者訂閱事件來檢測一些運(yùn)行實例的變化,當(dāng)它檢測到一個新的可用服務(wù)實例時就把該實例注冊到服務(wù)注冊表中去,service registrar還負(fù)責(zé)注銷已經(jīng)被終止的服務(wù)實例,下圖展示了該模式的架構(gòu):

Paste_Image.png

service registrar其中一個例子是開源的Registrator 項目,它自動的對部署到Docker 容器中的服務(wù)實例進(jìn)行注冊和注銷。 Registrator支持不同的服務(wù)注冊表,包括etcd和Consul。

service registrar的另一個例子是 NetflixOSS Prana,原本是為非JVM語言的服務(wù)所設(shè)計,它像服務(wù)實例的跨斗一樣和服務(wù)實例一起運(yùn)行,Prana使用Netflix Eureka對服務(wù)進(jìn)行注冊和注銷。

service registrar是部署環(huán)境的內(nèi)置組件,EC2實例可以自動擴(kuò)展組 并可使用ELB進(jìn)行服務(wù)注冊。Kubernetes 服務(wù)是自動注冊的并能使其可以被發(fā)現(xiàn)。

third-party registration模式有一些優(yōu)勢也有一些劣勢:主要優(yōu)勢是使得服務(wù)從服務(wù)注冊表中被解耦,你不必為開發(fā)者使用的每種開發(fā)語言和框架實現(xiàn)服務(wù)注冊的邏輯,相反,服務(wù)實例的注冊被一個專有服務(wù)以集中式的方式處理。

該模式的劣勢是,除非它被內(nèi)置在部署環(huán)境中,不然這又是一個需要被設(shè)置和管理的高可用系統(tǒng)組件。

總結(jié)

在一個微服務(wù)應(yīng)用中,一組運(yùn)行的服務(wù)實例是動態(tài)變化的,實例有動態(tài)分配的網(wǎng)絡(luò)地址,因此,為了使得客戶端能夠向服務(wù)發(fā)起請求,必須要要有服務(wù)發(fā)現(xiàn)機(jī)制。

服務(wù)發(fā)現(xiàn)的關(guān)鍵是服務(wù)注冊表,服務(wù)注冊表是可用服務(wù)實例的數(shù)據(jù)庫,它提供了管理和查詢使用的API。服務(wù)實例使用這些管理API進(jìn)行服務(wù)的注冊和注銷,系統(tǒng)組件使用查詢API來發(fā)現(xiàn)可用的服務(wù)實例。

有兩種服務(wù)發(fā)現(xiàn)的模式:客戶端發(fā)現(xiàn)和服務(wù)端發(fā)現(xiàn)。在使用客戶端發(fā)現(xiàn)模式的系統(tǒng)中,客戶端直接查詢服務(wù)注冊表,選擇一個可用的實例并發(fā)起請求,在一個使用服務(wù)端發(fā)現(xiàn)模式的系統(tǒng)中,客戶端通過路由發(fā)起請求,路由會查詢服務(wù)注冊表并把請求轉(zhuǎn)發(fā)到可用的服務(wù)實例上。

對服務(wù)實例來講有兩種方式可以對服務(wù)注冊表進(jìn)行注冊和注銷,一種是服務(wù)實例本身通過服務(wù)注冊表來注冊自己,也就是self-registration模式,另一種則是第三方系統(tǒng)組件代表實例來處理服務(wù)的注冊和注銷,也就是third-party registration模式。

在一些部署環(huán)境中,你需要使用諸如Netflix Eureka、etcd, 或者Apache Zookeeper這樣的服務(wù)注冊表來設(shè)置你自己的服務(wù)發(fā)現(xiàn)架構(gòu)。在另一些部署環(huán)境中,服務(wù)發(fā)現(xiàn)則是內(nèi)置組件,比如KubernetesMarathon用來處理服務(wù)注冊和注銷,他們同樣也在集群的每一個主機(jī)上運(yùn)行一個代理來扮演服務(wù)端發(fā)現(xiàn)路由的角色。

一些諸如NGINX的HTTP反向代理和負(fù)載均衡器 可以用作服務(wù)端發(fā)現(xiàn)負(fù)載均衡器使用,服務(wù)注冊表可以向NGINX推送路由信息并調(diào)用優(yōu)雅的配置更新,比如,你可以使用Consul Template。 NGINX Plus 支持額外的動態(tài)重配置機(jī)制 :它可以使用DNS從服務(wù)注冊表 拉取服務(wù)實例的信息,并且為遠(yuǎn)程重配置提供API。

在該系列之后的文章中我們將繼續(xù)挖掘微服務(wù)的各個方面。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容