為什么使用服務(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è)問(wèn)題就變得復(fù)雜多了,如下圖所示:
服務(wù)實(shí)例的網(wǎng)絡(luò)地址是動(dòng)態(tài)分配的。而且,由于自動(dòng)擴(kuò)展,失敗和更新,服務(wù)實(shí)例的配置也經(jīng)常變化。這樣一來(lái),你的客戶端代碼需要一套更精細(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)。我們首先來(lái)看下客戶端服務(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ù)庫(kù)。客戶端使用一個(gè)負(fù)載均衡算法,去選擇一個(gè)可用的服務(wù)實(shí)例,來(lái)響應(yīng)這個(gè)請(qǐng)求,下圖展示了這種模式的架構(gòu):
一個(gè)服務(wù)實(shí)例被啟動(dòng)時(shí),它的網(wǎng)絡(luò)地址會(huì)被寫到注冊(cè)表上;當(dāng)服務(wù)實(shí)例終止時(shí),再?gòu)淖?cè)表中刪除。這個(gè)服務(wù)實(shí)例的注冊(cè)表通過(guò)心跳機(jī)制動(dòng)態(tài)刷新。
客戶端的服務(wù)發(fā)現(xiàn)模式有優(yōu)勢(shì)也有缺點(diǎn)。這種模式相對(duì)直接,但是除了服務(wù)注冊(cè)表,沒(méi)有其它動(dòng)態(tài)的部分了。而且,由于客戶端知道可用的服務(wù)實(shí)例,可以做到智能的,應(yīng)用明確的負(fù)載均衡決策,比如一直用hash算法。這種模式的一個(gè)重大缺陷在于,客戶端和服務(wù)注冊(cè)表是邏輯耦合,必須為服務(wù)客戶端用到的每一種編程語(yǔ)言和框架實(shí)現(xiàn)客戶端服務(wù)發(fā)現(xiàn)邏輯。
服務(wù)器端服務(wù)發(fā)現(xiàn)模式
下圖展示了這種模式的架構(gòu)
客戶端通過(guò)負(fù)載均衡器向一個(gè)服務(wù)發(fā)送請(qǐng)求,這個(gè)負(fù)載均衡器會(huì)查詢服務(wù)注冊(cè)表,并將請(qǐng)求路由到可用的服務(wù)實(shí)例上。通過(guò)客戶端的服務(wù)發(fā)現(xiàn),服務(wù)實(shí)例在服務(wù)注冊(cè)表上被注冊(cè)和注銷。
AWS的ELB(Elastic Load Blancer)就是一個(gè)服務(wù)器端服務(wù)發(fā)現(xiàn)路由器。一個(gè)ELB通常被用來(lái)均衡來(lái)自互聯(lián)網(wǎng)的外部流量,也可以用ELB去均衡流向VPC(Virtual Private Cloud)的流量。一個(gè)客戶端通過(guò)ELB發(fā)送請(qǐng)求(HTTP或TCP)時(shí),使用的是DNS,ELB會(huì)均衡這些注冊(cè)的EC2實(shí)例或ECS(EC2 Container Service)容器的流量。沒(méi)有另外的服務(wù)注冊(cè)表,EC2實(shí)例和ECS容器也只會(huì)在ELB上注冊(cè)。
HTTP服務(wù)器和類似Nginx、Nginx Plus的負(fù)載均衡器也可以被用做服務(wù)器端服務(wù)發(fā)現(xiàn)負(fù)載均衡器。例如,Consul Template可以用來(lái)動(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),通過(guò)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ù)分配的端口,通過(guò)代理路由這個(gè)請(qǐng)求。這個(gè)代理會(huì)直接將請(qǐng)求發(fā)送到集群上可用的服務(wù)實(shí)例。
服務(wù)器端服務(wù)發(fā)現(xiàn)模式也是優(yōu)勢(shì)和缺陷并存。最大的好處在于服務(wù)發(fā)現(xiàn)的細(xì)節(jié)被從客戶端中抽象出來(lái),客戶端只需要向負(fù)載均衡器發(fā)送請(qǐng)求,不需要為服務(wù)客戶端使用的每一種語(yǔ)言和框架,實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)邏輯;另外,這種模式也有一些問(wè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ù)庫(kù),必須是高可用和最新的??蛻舳丝梢跃彺鎻姆?wù)注冊(cè)表處獲得的網(wǎng)絡(luò)地址。但是,這些信息最終會(huì)失效,客戶端會(huì)找不到服務(wù)實(shí)例。所以,服務(wù)注冊(cè)表由一個(gè)服務(wù)器集群組成,通過(guò)應(yīng)用協(xié)議來(lái)保持一致性。
其它服務(wù)注冊(cè)的例子包括:
一些系統(tǒng),比如Kubernetes,Marathon和AWS沒(méi)有一個(gè)明確的服務(wù)注冊(cè)組件,這項(xiàng)功能是內(nèi)置在基礎(chǔ)設(shè)置中的。
下面我們來(lái)看看服務(wù)實(shí)例如何在注冊(cè)表中注冊(cè)。
服務(wù)注冊(cè)(Service Registration)
前面提到了,服務(wù)實(shí)例必須要從注冊(cè)表中注冊(cè)和注銷,有很多種方式來(lái)處理注冊(cè)和注銷的過(guò)程。一個(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è)過(guò)期。下圖展示了這種模式的架構(gòu):
self-registration模式同樣也是優(yōu)劣并存。優(yōu)勢(shì)之一在于簡(jiǎn)單,不需要其它組件。缺點(diǎn)是服務(wù)實(shí)例和服務(wù)注冊(cè)表相對(duì)應(yīng),必須要為服務(wù)中用到的每種編程語(yǔ)言和框架實(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通過(guò)輪詢部署環(huán)境或訂閱事件去跟蹤運(yùn)行中的實(shí)例的變化。當(dāng)它注意到一個(gè)新的可用的服務(wù)實(shí)例時(shí),就會(huì)到注冊(cè)表中去注冊(cè)。service registrar也會(huì)將停止的服務(wù)實(shí)例注銷,下圖展示了這種模式的架構(gòu)。
service registrar的一個(gè)例子是開(kāi)源的Registrator項(xiàng)目。它會(huì)自動(dòng)注冊(cè)和注銷像Docker容器一樣部署的服務(wù)。Registrator支持etcd和Consul等服務(wù)注冊(cè)。
另一個(gè)service registrar的例子是NetflixOSS Prana。主要用于非JVM語(yǔ)言編寫的服務(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è)語(yǔ)言和框架都實(shí)現(xiàn)服務(wù)注冊(cè)邏輯。服務(wù)實(shí)例注冊(cè)由一個(gè)專用的服務(wù)集中實(shí)現(xiàn)。缺點(diǎn)是除了被內(nèi)置到部署環(huán)境中,它本身也是一個(gè)高可用的系統(tǒng)組件,需要被啟動(dòng)和管理。
聯(lián)系客服