如何实现微服务架构中的服务发现
為什么使用服務(wù)發(fā)現(xiàn)?
想象一下,如果你在寫代碼調(diào)用一個(gè)有REST API或Thrift API的服務(wù),你的代碼需要知道一個(gè)服務(wù)實(shí)例的網(wǎng)絡(luò)地址(IP地址和端口)。運(yùn)行在物理硬件上的傳統(tǒng)應(yīng)用中,服務(wù)實(shí)例的網(wǎng)絡(luò)地址是相對(duì)靜態(tài)的,你的代碼可以從一個(gè)很少更新的配置文件中讀取網(wǎng)絡(luò)地址。
在一個(gè)現(xiàn)代的,基于云的微服務(wù)應(yīng)用中,這個(gè)問題就變得復(fù)雜多了,如下圖所示:
服務(wù)實(shí)例的網(wǎng)絡(luò)地址是動(dòng)態(tài)分配的。而且,由于自動(dòng)擴(kuò)展,失敗和更新,服務(wù)實(shí)例的配置也經(jīng)常變化。這樣一來,你的客戶端代碼需要一套更精細(xì)的服務(wù)發(fā)現(xiàn)機(jī)制。
有兩種主要的服務(wù)發(fā)現(xiàn)模式:客戶端服務(wù)發(fā)現(xiàn)(client-side discovery)和服務(wù)器端服務(wù)發(fā)現(xiàn)(server-side discovery)。我們首先來看下客戶端服務(wù)發(fā)現(xiàn)。
?
客戶端服務(wù)發(fā)現(xiàn)模式
當(dāng)使用客戶端服務(wù)發(fā)現(xiàn)的時(shí)候,客戶端負(fù)責(zé)決定可用的服務(wù)實(shí)例的網(wǎng)絡(luò)地址,以及圍繞他們的負(fù)載均衡。客戶端向服務(wù)注冊(cè)表(service registry)發(fā)送一個(gè)請(qǐng)求,服務(wù)注冊(cè)表是一個(gè)可用服務(wù)實(shí)例的數(shù)據(jù)庫。客戶端使用一個(gè)負(fù)載均衡算法,去選擇一個(gè)可用的服務(wù)實(shí)例,來響應(yīng)這個(gè)請(qǐng)求,下圖展示了這種模式的架構(gòu):
一個(gè)服務(wù)實(shí)例被啟動(dòng)時(shí),它的網(wǎng)絡(luò)地址會(huì)被寫到注冊(cè)表上;當(dāng)服務(wù)實(shí)例終止時(shí),再從注冊(cè)表中刪除。這個(gè)服務(wù)實(shí)例的注冊(cè)表通過心跳機(jī)制動(dòng)態(tài)刷新。
Netflix OSS提供了一個(gè)客戶端服務(wù)發(fā)現(xiàn)的好例子。Netflix Eureka是一個(gè)服務(wù)注冊(cè)表,提供了REST API用來管理服務(wù)實(shí)例的注冊(cè)和查詢可用的實(shí)例。Netflix Ribbon是一個(gè)IPC客戶端,和Eureka一起處理可用服務(wù)實(shí)例的負(fù)載均衡。下面會(huì)深入討論Eureka。
客戶端的服務(wù)發(fā)現(xiàn)模式有優(yōu)勢(shì)也有缺點(diǎn)。這種模式相對(duì)直接,但是除了服務(wù)注冊(cè)表,沒有其它動(dòng)態(tài)的部分了。而且,由于客戶端知道可用的服務(wù)實(shí)例,可以做到智能的,應(yīng)用明確的負(fù)載均衡決策,比如一直用hash算法。這種模式的一個(gè)重大缺陷在于,客戶端和服務(wù)注冊(cè)表是邏輯耦合,必須為服務(wù)客戶端用到的每一種編程語言和框架實(shí)現(xiàn)客戶端服務(wù)發(fā)現(xiàn)邏輯。
?
服務(wù)器端服務(wù)發(fā)現(xiàn)模式
下圖展示了這種模式的架構(gòu)
客戶端通過負(fù)載均衡器向一個(gè)服務(wù)發(fā)送請(qǐng)求,這個(gè)負(fù)載均衡器會(huì)查詢服務(wù)注冊(cè)表,并將請(qǐng)求路由到可用的服務(wù)實(shí)例上。通過客戶端的服務(wù)發(fā)現(xiàn),服務(wù)實(shí)例在服務(wù)注冊(cè)表上被注冊(cè)和注銷。
AWS的ELB(Elastic Load Blancer)就是一個(gè)服務(wù)器端服務(wù)發(fā)現(xiàn)路由器。一個(gè)ELB通常被用來均衡來自互聯(lián)網(wǎng)的外部流量,也可以用ELB去均衡流向VPC(Virtual Private Cloud)的流量。一個(gè)客戶端通過ELB發(fā)送請(qǐng)求(HTTP或TCP)時(shí),使用的是DNS,ELB會(huì)均衡這些注冊(cè)的EC2實(shí)例或ECS(EC2 Container Service)容器的流量。沒有另外的服務(wù)注冊(cè)表,EC2實(shí)例和ECS容器也只會(huì)在ELB上注冊(cè)。
HTTP服務(wù)器和類似Nginx、Nginx Plus的負(fù)載均衡器也可以被用做服務(wù)器端服務(wù)發(fā)現(xiàn)負(fù)載均衡器。例如,Consul Template可以用來動(dòng)態(tài)配置Nginx的反向代理。
Consul Template定期從存儲(chǔ)在Consul服務(wù)注冊(cè)表的數(shù)據(jù)中,生成任意的配置文件。每當(dāng)文件變化時(shí),會(huì)運(yùn)行一個(gè)shell命令。比如,Consul Template可以生成一個(gè)配置反向代理的nginx.conf文件,然后運(yùn)行一個(gè)命令告訴Nginx去重新加載配置。還有一個(gè)更復(fù)雜的實(shí)現(xiàn),通過HTTP API或DNS去動(dòng)態(tài)地重新配置Nginx Plus。
有些部署環(huán)境,比如Kubernetes和Marathon會(huì)在集群中的每個(gè)host上運(yùn)行一個(gè)代理。這個(gè)代理承擔(dān)了服務(wù)器端服務(wù)發(fā)現(xiàn)負(fù)載均衡器的角色。為了向一個(gè)服務(wù)發(fā)送一個(gè)請(qǐng)求,一個(gè)客戶端使用host的IP地址和服務(wù)分配的端口,通過代理路由這個(gè)請(qǐng)求。這個(gè)代理會(huì)直接將請(qǐng)求發(fā)送到集群上可用的服務(wù)實(shí)例。
服務(wù)器端服務(wù)發(fā)現(xiàn)模式也是優(yōu)勢(shì)和缺陷并存。最大的好處在于服務(wù)發(fā)現(xiàn)的細(xì)節(jié)被從客戶端中抽象出來,客戶端只需要向負(fù)載均衡器發(fā)送請(qǐng)求,不需要為服務(wù)客戶端使用的每一種語言和框架,實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)邏輯;另外,這種模式也有一些問題,除非這個(gè)負(fù)載均衡器是由部署環(huán)境提供的,又是另一個(gè)需要啟動(dòng)和管理的高可用的系統(tǒng)組件。
?
服務(wù)注冊(cè)表(Service Registry)
服務(wù)注冊(cè)表是服務(wù)發(fā)現(xiàn)的關(guān)鍵部分,是一個(gè)包含了服務(wù)實(shí)例的網(wǎng)絡(luò)地址的數(shù)據(jù)庫,必須是高可用和最新的。客戶端可以緩存從服務(wù)注冊(cè)表處獲得的網(wǎng)絡(luò)地址。但是,這些信息最終會(huì)失效,客戶端會(huì)找不到服務(wù)實(shí)例。所以,服務(wù)注冊(cè)表由一個(gè)服務(wù)器集群組成,通過應(yīng)用協(xié)議來保持一致性。
正如上面提到的,Netflix Eureka是一個(gè)服務(wù)注冊(cè)表的好例子。它提供了一個(gè)REST API用來注冊(cè)和查詢服務(wù)實(shí)例。一個(gè)服務(wù)實(shí)例通過POST請(qǐng)求來注冊(cè)自己的網(wǎng)絡(luò)位置,每隔30秒要通過一個(gè)PUT請(qǐng)求重新注冊(cè)。注冊(cè)表中的一個(gè)條目會(huì)因?yàn)橐粋€(gè)HTTP DELETE請(qǐng)求或?qū)嵗?cè)超時(shí)而被刪除,客戶端通過一個(gè)HTTP GET請(qǐng)求來檢索注冊(cè)的服務(wù)實(shí)例。
Netflix通過在每個(gè)EC2的可用區(qū)中,運(yùn)行一個(gè)或多個(gè)Eureka服務(wù)器實(shí)現(xiàn)高可用。每個(gè)運(yùn)行在EC2實(shí)例上的Eureka服務(wù)器都有一個(gè)彈性的IP地址。DNS TEXT records用來存儲(chǔ)Eureka集群配置,實(shí)際上是從可用區(qū)到Eureka服務(wù)器網(wǎng)絡(luò)地址的列表的映射。當(dāng)一個(gè)Eureka服務(wù)器啟動(dòng)時(shí),會(huì)向DNS發(fā)送請(qǐng)求,檢索Eureka集群的配置,定位節(jié)點(diǎn),并為自己分配一個(gè)未占用的彈性IP地址。
Eureka客戶端(服務(wù)和服務(wù)客戶端)查詢DNS去尋找Eureka服務(wù)器的網(wǎng)絡(luò)地址。客戶端更想使用這個(gè)可用區(qū)內(nèi)的Eureka服務(wù)器,如果沒有可用的Eureka服務(wù)器,客戶端會(huì)用另一個(gè)可用區(qū)內(nèi)的Eureka服務(wù)器。
其它服務(wù)注冊(cè)的例子包括:
- Etcd:一個(gè)高可用,分布式,一致的key-value存儲(chǔ),用來共享配置和服務(wù)發(fā)現(xiàn)。Kubernetes和Cloudfoundry都使用了etcd;
- Consul:一個(gè)發(fā)現(xiàn)和配置服務(wù)的工具。客戶端可以利用它提供的API,注冊(cè)和發(fā)現(xiàn)服務(wù)。Consul可以執(zhí)行監(jiān)控檢測(cè)來實(shí)現(xiàn)服務(wù)的高可用;
- Apache Zookeeper:一個(gè)常用的,為分布式應(yīng)用設(shè)計(jì)的高可用協(xié)調(diào)服務(wù),最開始Zookeeper是Hadoop的子項(xiàng)目,現(xiàn)在已經(jīng)頂級(jí)項(xiàng)目了。
一些系統(tǒng),比如Kubernetes,Marathon和AWS沒有一個(gè)明確的服務(wù)注冊(cè)組件,這項(xiàng)功能是內(nèi)置在基礎(chǔ)設(shè)置中的。
下面我們來看看服務(wù)實(shí)例如何在注冊(cè)表中注冊(cè)。
?
服務(wù)注冊(cè)(Service Registration)
前面提到了,服務(wù)實(shí)例必須要從注冊(cè)表中注冊(cè)和注銷,有很多種方式來處理注冊(cè)和注銷的過程。一個(gè)選擇是服務(wù)實(shí)例自己注冊(cè),即self-registration模式。另一種選擇是其它的系統(tǒng)組件管理服務(wù)實(shí)例的注冊(cè),即第third-party registration模式。
自注冊(cè)模式(The Self-Registration Pattern)
在self-registration模式中,服務(wù)實(shí)例負(fù)責(zé)從服務(wù)注冊(cè)表中注冊(cè)和注銷。如果需要的話,一個(gè)服務(wù)實(shí)例發(fā)送心跳請(qǐng)求防止注冊(cè)過期。下圖展示了這種模式的架構(gòu):
Netflix OSS Eureka客戶端是這種方式的一個(gè)好例子。Eureka客戶端處理服務(wù)實(shí)例注冊(cè)和注銷的所有問題。Spring Cloud實(shí)現(xiàn)包括服務(wù)發(fā)現(xiàn)在內(nèi)的多種模式,簡化了Eureka的服務(wù)實(shí)例自動(dòng)注冊(cè)。僅僅通過@EnableEurekaClient注釋就可以注釋Java的配置類
self-registration模式同樣也是優(yōu)劣并存。優(yōu)勢(shì)之一在于簡單,不需要其它組件。缺點(diǎn)是服務(wù)實(shí)例和服務(wù)注冊(cè)表相對(duì)應(yīng),必須要為服務(wù)中用到的每種編程語言和框架實(shí)現(xiàn)注冊(cè)代碼。
第三方注冊(cè)模式(The Third-Party Registration Pattern)
在third-party registration模式中,服務(wù)實(shí)例不會(huì)自己在服務(wù)注冊(cè)表中注冊(cè),由另一個(gè)系統(tǒng)組件service registrar負(fù)責(zé)。service registrar通過輪詢部署環(huán)境或訂閱事件去跟蹤運(yùn)行中的實(shí)例的變化。當(dāng)它注意到一個(gè)新的可用的服務(wù)實(shí)例時(shí),就會(huì)到注冊(cè)表中去注冊(cè)。service registrar也會(huì)將停止的服務(wù)實(shí)例注銷,下圖展示了這種模式的架構(gòu)。
service registrar的一個(gè)例子是開源的Registrator項(xiàng)目。它會(huì)自動(dòng)注冊(cè)和注銷像Docker容器一樣部署的服務(wù)。Registrator支持etcd和Consul等服務(wù)注冊(cè)。
另一個(gè)service registrar的例子是NetflixOSS Prana。主要用于非JVM語言編寫的服務(wù),它是一個(gè)和服務(wù)實(shí)例配合的『雙輪』應(yīng)用。Prana會(huì)在Netflix Eureka上注冊(cè)和注銷實(shí)例。
service registrar是一個(gè)部署環(huán)境的內(nèi)置組件,由Autoscaling Group創(chuàng)建的EC2實(shí)例可以被ELB自動(dòng)注冊(cè)。Kubernetes服務(wù)也可以自動(dòng)注冊(cè)。
third-party registration模式主要的優(yōu)勢(shì)在于解耦了服務(wù)和服務(wù)注冊(cè)表。不需要為每個(gè)語言和框架都實(shí)現(xiàn)服務(wù)注冊(cè)邏輯。服務(wù)實(shí)例注冊(cè)由一個(gè)專用的服務(wù)集中實(shí)現(xiàn)。缺點(diǎn)是除了被內(nèi)置到部署環(huán)境中,它本身也是一個(gè)高可用的系統(tǒng)組件,需要被啟動(dòng)和管理。
?
總結(jié)
在一個(gè)微服務(wù)應(yīng)用中,服務(wù)實(shí)例在運(yùn)行時(shí)的配置也會(huì)動(dòng)態(tài)變化,包括他們的網(wǎng)絡(luò)地址。為了滿足客戶端向服務(wù)發(fā)送請(qǐng)求的需要,必須要實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)機(jī)制。
服務(wù)發(fā)現(xiàn)的關(guān)鍵部分是服務(wù)注冊(cè)表。服務(wù)注冊(cè)表是一個(gè)可用的服務(wù)實(shí)例的數(shù)據(jù)庫。服務(wù)注冊(cè)表提供了一個(gè)管理API和一個(gè)查詢API。服務(wù)實(shí)例的注冊(cè)和注銷通過管理API實(shí)現(xiàn),查詢API用來尋找可用的服務(wù)實(shí)例。
有兩種主要的服務(wù)發(fā)現(xiàn)模式:客戶端服務(wù)發(fā)現(xiàn)和服務(wù)器端服務(wù)發(fā)現(xiàn)。客戶端服務(wù)發(fā)現(xiàn)系統(tǒng)中,客戶端查詢服務(wù)注冊(cè)表,選擇一個(gè)可用的實(shí)例,響應(yīng)一個(gè)請(qǐng)求;在服務(wù)器端服務(wù)發(fā)現(xiàn)系統(tǒng)中,客戶端通過一個(gè)路由器發(fā)送請(qǐng)求,這個(gè)路由器會(huì)去查詢服務(wù)注冊(cè)表,并將請(qǐng)求發(fā)送給可用的實(shí)例。
有兩種形式可以實(shí)現(xiàn)服務(wù)實(shí)例的注冊(cè)和注銷,一種是self-registration模式,一種是third-party registration模式。
一些部署環(huán)境中,需要通過類似Netflix Eureka,etcd或Apache Zookeeper的組件,啟動(dòng)自己的服務(wù)發(fā)現(xiàn)基礎(chǔ)設(shè)施。其它的部署環(huán)境中,服務(wù)發(fā)現(xiàn)是內(nèi)置的。比如,Kubernetes和Marathon處理服務(wù)實(shí)例的注冊(cè)和注銷,還會(huì)在每個(gè)集群host上運(yùn)行一個(gè)代理,作為服務(wù)器端服務(wù)發(fā)現(xiàn)路由器的角色。
一個(gè)HTTP反向代理和Nginx也可以被用做服務(wù)器端服務(wù)發(fā)現(xiàn)負(fù)載均衡器。服務(wù)注冊(cè)表可以推送路由信息到Nginx,引起配置更新,比如可以用Consul Template。Nginx Plus支持動(dòng)態(tài)的重配置機(jī)制,可以從注冊(cè)表中拉取服務(wù)實(shí)例相關(guān)的信息,還提供了遠(yuǎn)程配置的API。
轉(zhuǎn)載于:https://www.cnblogs.com/kaleidoscope/p/9605958.html
總結(jié)
以上是生活随笔為你收集整理的如何实现微服务架构中的服务发现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js中浮点数
- 下一篇: unity 中让Text的文字动态刷新形