為什么使用服務(wù)發(fā)現(xiàn)?
想象一下,如果你在寫代碼調(diào)用一個有REST API或Thrift API的服務(wù),你的代碼需要知道一個服務(wù)實例的網(wǎng)絡(luò)地址(IP地址和端口)。運行在物理硬件上的傳統(tǒng)應(yīng)用中,服務(wù)實例的網(wǎng)絡(luò)地址是相對靜態(tài)的,你的代碼可以從一個很少更新的配置文件中讀取網(wǎng)絡(luò)地址。
在一個現(xiàn)代的,基于云的微服務(wù)應(yīng)用中,這個問題就變得復(fù)雜多了,如下圖所示:
服務(wù)實例的網(wǎng)絡(luò)地址是動態(tài)分配的。而且,由于自動擴展,失敗和更新,服務(wù)實例的配置也經(jīng)常變化。這樣一來,你的客戶端代碼需要一套更精細的服務(wù)發(fā)現(xiàn)機制。
有兩種主要的服務(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)模式
當使用客戶端服務(wù)發(fā)現(xiàn)的時候,客戶端負責決定可用的服務(wù)實例的網(wǎng)絡(luò)地址,以及圍繞他們的負載均衡??蛻舳讼蚍?wù)注冊表(service registry)發(fā)送一個請求,服務(wù)注冊表是一個可用服務(wù)實例的數(shù)據(jù)庫。客戶端使用一個負載均衡算法,去選擇一個可用的服務(wù)實例,來響應(yīng)這個請求,下圖展示了這種模式的架構(gòu):
一個服務(wù)實例被啟動時,它的網(wǎng)絡(luò)地址會被寫到注冊表上;當服務(wù)實例終止時,再從注冊表中刪除。這個服務(wù)實例的注冊表通過心跳機制動態(tài)刷新。
客戶端的服務(wù)發(fā)現(xiàn)模式有優(yōu)勢也有缺點。這種模式相對直接,但是除了服務(wù)注冊表,沒有其它動態(tài)的部分了。而且,由于客戶端知道可用的服務(wù)實例,可以做到智能的,應(yīng)用明確的負載均衡決策,比如一直用hash算法。這種模式的一個重大缺陷在于,客戶端和服務(wù)注冊表是邏輯耦合,必須為服務(wù)客戶端用到的每一種編程語言和框架實現(xiàn)客戶端服務(wù)發(fā)現(xiàn)邏輯。
服務(wù)器端服務(wù)發(fā)現(xiàn)模式
下圖展示了這種模式的架構(gòu)
客戶端通過負載均衡器向一個服務(wù)發(fā)送請求,這個負載均衡器會查詢服務(wù)注冊表,并將請求路由到可用的服務(wù)實例上。通過客戶端的服務(wù)發(fā)現(xiàn),服務(wù)實例在服務(wù)注冊表上被注冊和注銷。
AWS的ELB(Elastic Load Blancer)就是一個服務(wù)器端服務(wù)發(fā)現(xiàn)路由器。一個ELB通常被用來均衡來自互聯(lián)網(wǎng)的外部流量,也可以用ELB去均衡流向VPC(Virtual Private Cloud)的流量。一個客戶端通過ELB發(fā)送請求(HTTP或TCP)時,使用的是DNS,ELB會均衡這些注冊的EC2實例或ECS(EC2 Container Service)容器的流量。沒有另外的服務(wù)注冊表,EC2實例和ECS容器也只會在ELB上注冊。
HTTP服務(wù)器和類似Nginx、Nginx Plus的負載均衡器也可以被用做服務(wù)器端服務(wù)發(fā)現(xiàn)負載均衡器。例如,Consul Template可以用來動態(tài)配置Nginx的反向代理。
Consul Template定期從存儲在Consul服務(wù)注冊表的數(shù)據(jù)中,生成任意的配置文件。每當文件變化時,會運行一個shell命令。比如,Consul Template可以生成一個配置反向代理的nginx.conf文件,然后運行一個命令告訴Nginx去重新加載配置。還有一個更復(fù)雜的實現(xiàn),通過HTTP API或DNS去動態(tài)地重新配置Nginx Plus。
有些部署環(huán)境,比如Kubernetes和Marathon會在集群中的每個host上運行一個代理。這個代理承擔了服務(wù)器端服務(wù)發(fā)現(xiàn)負載均衡器的角色。為了向一個服務(wù)發(fā)送一個請求,一個客戶端使用host的IP地址和服務(wù)分配的端口,通過代理路由這個請求。這個代理會直接將請求發(fā)送到集群上可用的服務(wù)實例。
服務(wù)器端服務(wù)發(fā)現(xiàn)模式也是優(yōu)勢和缺陷并存。最大的好處在于服務(wù)發(fā)現(xiàn)的細節(jié)被從客戶端中抽象出來,客戶端只需要向負載均衡器發(fā)送請求,不需要為服務(wù)客戶端使用的每一種語言和框架,實現(xiàn)服務(wù)發(fā)現(xiàn)邏輯;另外,這種模式也有一些問題,除非這個負載均衡器是由部署環(huán)境提供的,又是另一個需要啟動和管理的高可用的系統(tǒng)組件。
服務(wù)注冊表(Service Registry)
服務(wù)注冊表是服務(wù)發(fā)現(xiàn)的關(guān)鍵部分,是一個包含了服務(wù)實例的網(wǎng)絡(luò)地址的數(shù)據(jù)庫,必須是高可用和最新的??蛻舳丝梢跃彺鎻姆?wù)注冊表處獲得的網(wǎng)絡(luò)地址。但是,這些信息最終會失效,客戶端會找不到服務(wù)實例。所以,服務(wù)注冊表由一個服務(wù)器集群組成,通過應(yīng)用協(xié)議來保持一致性。
其它服務(wù)注冊的例子包括:
- Etcd:一個高可用,分布式,一致的key-value存儲,用來共享配置和服務(wù)發(fā)現(xiàn)。Kubernetes和Cloudfoundry都使用了etcd;
- Consul:一個發(fā)現(xiàn)和配置服務(wù)的工具??蛻舳丝梢岳盟峁┑腁PI,注冊和發(fā)現(xiàn)服務(wù)。Consul可以執(zhí)行監(jiān)控檢測來實現(xiàn)服務(wù)的高可用;
- Apache Zookeeper:一個常用的,為分布式應(yīng)用設(shè)計的高可用協(xié)調(diào)服務(wù),最開始Zookeeper是Hadoop的子項目,現(xiàn)在已經(jīng)頂級項目了。
一些系統(tǒng),比如Kubernetes,Marathon和AWS沒有一個明確的服務(wù)注冊組件,這項功能是內(nèi)置在基礎(chǔ)設(shè)置中的。
下面我們來看看服務(wù)實例如何在注冊表中注冊。
服務(wù)注冊(Service Registration)
前面提到了,服務(wù)實例必須要從注冊表中注冊和注銷,有很多種方式來處理注冊和注銷的過程。一個選擇是服務(wù)實例自己注冊,即self-registration模式。另一種選擇是其它的系統(tǒng)組件管理服務(wù)實例的注冊,即第third-party registration模式。
自注冊模式(The Self-Registration Pattern)
在self-registration模式中,服務(wù)實例負責從服務(wù)注冊表中注冊和注銷。如果需要的話,一個服務(wù)實例發(fā)送心跳請求防止注冊過期。下圖展示了這種模式的架構(gòu):
self-registration模式同樣也是優(yōu)劣并存。優(yōu)勢之一在于簡單,不需要其它組件。缺點是服務(wù)實例和服務(wù)注冊表相對應(yīng),必須要為服務(wù)中用到的每種編程語言和框架實現(xiàn)注冊代碼。
第三方注冊模式(The Third-Party Registration Pattern)
在third-party registration模式中,服務(wù)實例不會自己在服務(wù)注冊表中注冊,由另一個系統(tǒng)組件service registrar負責。service registrar通過輪詢部署環(huán)境或訂閱事件去跟蹤運行中的實例的變化。當它注意到一個新的可用的服務(wù)實例時,就會到注冊表中去注冊。service registrar也會將停止的服務(wù)實例注銷,下圖展示了這種模式的架構(gòu)。
service registrar的一個例子是開源的Registrator項目。它會自動注冊和注銷像Docker容器一樣部署的服務(wù)。Registrator支持etcd和Consul等服務(wù)注冊。
另一個service registrar的例子是NetflixOSS Prana。主要用于非JVM語言編寫的服務(wù),它是一個和服務(wù)實例配合的『雙輪』應(yīng)用。Prana會在Netflix Eureka上注冊和注銷實例。
service registrar是一個部署環(huán)境的內(nèi)置組件,由Autoscaling Group創(chuàng)建的EC2實例可以被ELB自動注冊。Kubernetes服務(wù)也可以自動注冊。
third-party registration模式主要的優(yōu)勢在于解耦了服務(wù)和服務(wù)注冊表。不需要為每個語言和框架都實現(xiàn)服務(wù)注冊邏輯。服務(wù)實例注冊由一個專用的服務(wù)集中實現(xiàn)。缺點是除了被內(nèi)置到部署環(huán)境中,它本身也是一個高可用的系統(tǒng)組件,需要被啟動和管理。