爲什麼使用服務發現

爲什麼使用服務發現?

想象一下,如果你在寫代碼調用一個有REST API或Thrift API的服務,你的代碼需要知道一個服務實例的網絡地址(IP地址和端口)。運行在物理硬件上的傳統應用中,服務實例的網絡地址是相對靜態的,你的代碼可以從一個很少更新的配置文件中讀取網絡地址。

在一個現代的,基於雲的微服務應用中,這個問題就變得複雜多了,如下圖所示: 
無服務發現時,無法確定連接的服務 
服務實例的網絡地址是動態分配的。而且,由於自動擴展,失敗和更新,服務實例的配置也經常變化。這樣一來,你的客戶端代碼需要一套更精細的服務發現機制。

有兩種主要的服務發現模式:客戶端服務發現(client-side discovery)和服務器端服務發現(server-side discovery)。我們首先來看下客戶端服務發現。

客戶端服務發現模式

當使用客戶端服務發現的時候,客戶端負責決定可用的服務實例的網絡地址,以及圍繞他們的負載均衡。客戶端向服務註冊表(service registry)發送一個請求,服務註冊表是一個可用服務實例的數據庫。客戶端使用一個負載均衡算法,去選擇一個可用的服務實例,來響應這個請求,下圖展示了這種模式的架構: 
客戶端發現模式 
一個服務實例被啓動時,它的網絡地址會被寫到註冊表上;當服務實例終止時,再從註冊表中刪除。這個服務實例的註冊表通過心跳機制動態刷新。

Netflix OSS提供了一個客戶端服務發現的好例子。Netflix Eureka是一個服務註冊表,提供了REST API用來管理服務實例的註冊和查詢可用的實例。Netflix Ribbon是一個IPC客戶端,和Eureka一起處理可用服務實例的負載均衡。下面會深入討論Eureka。

客戶端的服務發現模式有優勢也有缺點。這種模式相對直接,但是除了服務註冊表,沒有其它動態的部分了。而且,由於客戶端知道可用的服務實例,可以做到智能的,應用明確的負載均衡決策,比如一直用hash算法。這種模式的一個重大缺陷在於,客戶端和服務註冊表是一一對應的,必須爲服務客戶端用到的每一種編程語言和框架實現客戶端服務發現邏輯。

服務器端服務發現模式

下圖展示了這種模式的架構 
服務器端服務發現模式 
客戶端通過負載均衡器向一個服務發送請求,這個負載均衡器會查詢服務註冊表,並將請求路由到可用的服務實例上。通過客戶端的服務發現,服務實例在服務註冊表上被註冊和註銷。

AWS的ELB(Elastic Load Blancer)就是一個服務器端服務發現路由器。一個ELB通常被用來均衡來自互聯網的外部流量,也可以用ELB去均衡流向VPC(Virtual Private Cloud)的流量。一個客戶端通過ELB發送請求(HTTP或TCP)時,使用的是DNS,ELB會均衡這些註冊的EC2實例或ECS(EC2 Container Service)容器的流量。沒有另外的服務註冊表,EC2實例和ECS容器也只會在ELB上註冊。

HTTP服務器和類似Nginx、Nginx Plus的負載均衡器也可以被用做服務器端服務發現負載均衡器。例如,Consul Template可以用來動態配置Nginx的反向代理。

Consul Template定期從存儲在Consul服務註冊表的數據中,生成任意的配置文件。每當文件變化時,會運行一個shell命令。比如,Consul Template可以生成一個配置反向代理的nginx.conf文件,然後運行一個命令告訴Nginx去重新加載配置。還有一個更復雜的實現,通過HTTP API或DNS去動態地重新配置Nginx Plus。

有些部署環境,比如Kubernetes和Marathon會在集羣中的每個host上運行一個代理。這個代理承擔了服務器端服務發現負載均衡器的角色。爲了向一個服務發送一個請求,一個客戶端使用host的IP地址和服務分配的端口,通過代理路由這個請求。這個代理會直接將請求發送到集羣上可用的服務實例。

服務器端服務發現模式也是優勢和缺陷並存。最大的好處在於服務發現的細節被從客戶端中抽象出來,客戶端只需要向負載均衡器發送請求,不需要爲服務客戶端使用的每一種語言和框架,實現服務發現邏輯;另外,這種模式也有一些問題,除非這個負載均衡器是由部署環境提供的,又是另一個高需要啓動和管理的可用的系統組件。

服務註冊表(Service Registry)

服務註冊表是服務發現的關鍵部分,是一個包含了服務實例的網絡地址的數據庫,必須是高可用和最新的。客戶端可以緩存從服務註冊表處獲得的網絡地址。但是,這些信息最終會失效,客戶端會找不到服務實例。所以,服務註冊表由一個服務器集羣組成,通過應用協議來保持一致性。

正如上面提到的,Netflix Eureka是一個服務註冊表的好例子。它提供了一個REST API用來註冊和查詢服務實例。一個服務實例通過POST請求來註冊自己的網絡位置,每隔30秒要通過一個PUT請求重新註冊。註冊表中的一個條目會因爲一個HTTP DELETE請求或實例註冊超時而被刪除,客戶端通過一個HTTP GET請求來檢索註冊的服務實例。

Netflix通過在每個EC2的可用區中,運行一個或多個Eureka服務器實現高可用。每個運行在EC2實例上的Eureka服務器都有一個彈性的IP地址。DNS TEXT records用來存儲Eureka集羣配置,實際上是從可用區到Eureka服務器網絡地址的列表的映射。當一個Eureka服務器啓動時,會向DNS發送請求,檢索Eureka集羣的配置,定位節點,併爲自己分配一個未佔用的彈性IP地址。

Eureka客戶端(服務和服務客戶端)查詢DNS去尋找Eureka服務器的網絡地址。客戶端更想使用這個可用區內的Eureka服務器,如果沒有可用的Eureka服務器,客戶端會用另一個可用區內的Eureka服務器。

其它服務註冊的例子包括:

  • Etcd:一個高可用,分佈式,一致的key-value存儲,用來共享配置和服務發現。Kubernetes和Cloudfoundry都使用了etcd;
  • Consul:一個發現和配置服務的工具。客戶端可以利用它提供的API,註冊和發現服務。Consul可以執行監控檢測來實現服務的高可用;
  • Apache Zookeeper:一個常用的,爲分佈式應用設計的高可用協調服務,最開始Zookeeper是Hadoop的子項目,現在已經頂級項目了。

一些系統,比如Kubernetes,Marathon和AWS沒有一個明確的服務註冊組件,這項功能是內置在基礎設置中的。

下面我們來看看服務實例如何在註冊表中註冊。

服務註冊(Service Registration)

前面提到了,服務實例必須要從註冊表中註冊和註銷,有很多種方式來處理註冊和註銷的過程。一個選擇是服務實例自己註冊,即self-registration模式。另一種選擇是其它的系統組件管理服務實例的註冊,即第third-party registration模式。

自注冊模式(The Self-Registration Pattern)

在self-registration模式中,服務實例負責從服務註冊表中註冊和註銷。如果需要的話,一個服務實例發送心跳請求防止註冊過期。下圖展示了這種模式的架構: 
自注冊模式 
Netflix OSS Eureka客戶端是這種方式的一個好例子。Eureka客戶端處理服務實例註冊和註銷的所有問題。Spring Cloud實現包括服務發現在內的多種模式,簡化了Eureka的服務實例自動註冊。僅僅通過@EnableEurekaClient註釋就可以註釋Java的配置類

self-registration模式同樣也是優劣並存。優勢之一在於簡單,不需要其它組件。缺點是服務實例和服務註冊表相對應,必須要爲服務中用到的每種編程語言和框架實現註冊代碼。

第三方註冊模式(The Third-Party Registration Pattern)

在third-party registration模式中,服務實例不會自己在服務註冊表中註冊,由另一個系統組件service registrar負責。service registrar通過輪詢部署環境或訂閱事件去跟蹤運行中的實例的變化。當它注意到一個新的可用的服務實例時,就會到註冊表中去註冊。service registrar也會將停止的服務實例註銷,下圖展示了這種模式的架構。 
第三方註冊模式 
service registrar的一個例子是開源的Registrator項目。它會自動註冊和註銷像Docker容器一樣部署的服務。Registrator支持etcd和Consul等服務註冊。

另一個service registrar的例子是NetflixOSS Prana。主要用於非JVM語言編寫的服務,它是一個和服務實例配合的『雙輪』應用。Prana會在Netflix Eureka上註冊和註銷實例。

service registrar是一個部署環境的內置組件,由Autoscaling Group創建的EC2實例可以被ELB自動註冊。Kubernetes服務也可以自動註冊。

third-party registration模式主要的優勢在於解耦了服務和服務註冊表。不需要爲每個語言和框架都實現服務註冊邏輯。服務實例註冊由一個專用的服務集中實現。缺點是除了被內置到部署環境中,它本身也是一個高可用的系統組件,需要被啓動和管理。

總結

在一個微服務應用中,服務實例在運行時的配置也會動態變化,包括他們的網絡地址。爲了滿足客戶端向服務發送請求的需要,必須要實現服務發現機制。

服務發現的關鍵部分是服務註冊表。服務註冊表是一個可用的服務實例的數據庫。服務註冊表提供了一個管理API和一個查詢API。服務實例的註冊和註銷通過管理API實現,查詢API用來尋找可用的服務實例。

有兩種主要的服務發現模式:客戶端服務發現和服務器端服務發現。客戶端服務發現系統中,客戶端查詢服務註冊表,選擇一個可用的實例,響應一個請求;在服務器端服務發現系統中,客戶端通過一個路由器發送請求,這個路由器會去查詢服務註冊表,並將請求發送給可用的實例。

有兩種形式可以實現服務實例的註冊和註銷,一種是self-registration模式,一種是third-party registration模式。

一些部署環境中,需要通過類似Netflix Eureka,etcd或Apache Zookeeper的組件,啓動自己的服務發現基礎設施。其它的部署環境中,服務發現是內置的。比如,Kubernetes和Marathon處理服務實例的註冊和註銷,還會在每個集羣host上運行一個代理,作爲服務器端服務發現路由器的角色。

一個HTTP反向代理和Nginx也可以被用做服務器端服務發現負載均衡器。服務註冊表可以推送路由信息到Nginx,引起配置更新,比如可以用Consul Template。Nginx Plus支持動態的重配置機制,可以從註冊表中拉取服務實例相關的信息,還提供了遠程配置的API。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章