Chris Richardson 微服務系列翻譯全7篇鏈接:
- 微服務介紹
- 構建微服務之使用API網關
- 構建微服務之微服務架構的進程通訊
- 微服務架構中的服務發現(本文)
- 微服務之事件驅動的數據管理
- 微服務部署
- 重構單體應用為微服務
原文鏈接:Service Discovery in a Microservices Architecture
為什么要使用服務發現
假設我們需要通過 REST API 或 Thrift API 去調用某個服務,為了完成一次請求,我們需要知道服務實例的地址(IP和端口號)。傳統運行在物理機上的應用,服務實例的網絡地址一般是靜態的,可以從配置文件中去讀取地址。
對于基于云平臺的微服務中,有更多如下的問題需要解決:
服務實例的網絡地址是動態分配的。由于擴展、升級,服務地址會經常變動,因此,客戶端需要使用更負責的服務發現機制。
主要有兩種服務發現機制:客戶端發現模式和服務端發現模式。
客戶端發現模式
客戶端決定服務實例的網絡地址,并對請求實現負載均衡。客戶端查詢服務注冊表(可用服務實例的數據庫),然后使用負載均衡算法從中選擇一個實例并請求。下圖展示該模式的架構:
服務實例的網絡地址在啟動時記錄到服務注冊表上,等實例停止時從服務注冊表中刪除。服務實例的注冊信息通常使用心跳機制來定期刷新。
Netflix OSS 是客戶端發現模式的絕佳范例。Netflix Eureka 實現了服務注冊表,為服務注冊管理和可用實例查詢提供了 REST API 接口,Netflix Ribbon 是 IPC 客戶端,與 Eureka 一起實現對請求的負載均衡。
客戶端發現機制有諸多優勢和不足。優點:1、相對直接,除服務注冊外,其他部分無需改動。2、客戶端知曉可用的服務實例,能針對特定應用智能的實現負載均衡,例如一致性哈希算法。不足:客戶端與服務注冊表綁定,要針對服務端用到的每個編程語言和框架,實現客戶端的服務發現邏輯。
服務端發現模式
下圖展示了服務端發現模式的架構:
客戶端通過負載均衡向某個服務發出請求,負載均衡查詢服務注冊表,并將請求路由至可用的服務實例。如同客戶端發現模式,服務實例在服務注冊表中注冊或刪除。
AWS Elastic Load Balancer (ELB)是服務端發現路由的范例。ELB 通常對外部的網絡請求進行負載均衡,也可對虛擬私有云的內部請求進行負載均衡。客戶端使用 DNS 通過 ELB 發出請求(HTTP或TCP),ELB 將請求負載均衡到一系列注冊的 EC2 實例或 ECS 容器,這兩者沒有單獨的服務注冊表,而是注冊在 ELB 中。
一些部署環境使用 Kubernetes 和 Marathon 在每個集群運行一個代理,作為服務端發現的負載均衡。代理可以根據 IP地址和端口 來路由客戶端請求,透明的將客戶端的請求轉發到集群中某個可用的服務實例上。
服務端發現機制的優點:客戶端無需關注服務發現的細節,只需簡單的向負載均衡發送請求,如上文所說,某些部署環境免費提供了這一功能;不足:除非部署環境提供了負載均衡,否則也成為了需要額外配置和管理的高可用組件。
服務注冊表
服務注冊表是服務發現的核心部分,是包含服務實例的網絡地址的數據庫。服務注冊表需要高可用和實時更新。客戶端能緩存從服務注冊表中獲取的網絡地址,然而這些信息最終會過時,客戶端也不能再根據該信息發現服務實例。因此,服務注冊表對集群中的實例使用復制協議來保證一致性。
Netflix Eureka 是服務注冊表的范例,為服務實例的注冊和查詢提供了 REST API:服務實例可以通過 POST 請求來注冊網絡地址,每 30秒通過 PUT 去更新注冊信息,也可主動通過 DELETE 請求或實例注冊超時來刪除注冊信息,客戶端使用 GET 請求來檢索已注冊的服務實例。
Netflix 通過在每個 AWS EC2 域運行一個或多個 Eureka 服務實例來實現高可用。DNS TEXT 記錄了 Eureka 集群的配置文件,配置文件映射了可用域和 Eureka 服務器網絡地址的映射關系。Eureka 服務啟動時查詢 DNS 獲取 Eureka 集群配置,確定同伴位置,為自己分配未被使用的彈性 IP 地址。
Eureka 客戶端傾向使用同一域內的 Eureka 服務器,如果該域中沒有可用的服務,則會使用其他域中的 Eureka 服務。
其他的服務注冊表例如:
- etcd :高可用、分布式、一致性的 key-value 存儲,用于共享配置和服務發現。Kubernetes 和 Cloud Foundry 使用了它
- consul:發現和配置服務的工具,為客戶端注冊和服務發現提供了API,還可以通過健康檢查來確定服務的可用性
- Apache Zookeeper:廣泛使用的、高性能的分布式應用的協調服務。 Apache Zookeeper 最初是 Hadoop 的子工程,現已成長為頂級項目
像 Kubernetes、Marathon 和 AWS ,服務注冊表是架構內置的一部分。
服務注冊的方式
服務實例必須在注冊表中注冊和注銷,有以下不同的兩種方法:1、服務實例自己注冊,也叫做自注冊模式;2、系統中其他組件管理服務實例的注冊,也就是第三方注冊模式。
自注冊方式
使用自注冊模式時,服務實例負責在注冊表中注冊和注銷,另外也需要發送心跳來防止注冊信息過期,如下圖所示:
Netflix OSS Eureka 客戶端就是這種模式的一個范例,他負責處理服務實例注冊和注銷的各個方面。Spring Cloud 實現了包括服務發現在內的各種模式,使得利用 Eureka 自注冊服務實例更簡單,只需要給 Java 配置類上添加 @EnableEurekaClient 即可。
自注冊的優勢:相對簡單,不使用其他系統組件。不足:服務實例與服務注冊表耦合,必須在每個客戶端實現注冊邏輯。
第三方注冊方式
使用第三方注冊模式,服務實例不需要向服務注冊表注冊,而是通過服務注冊器的系統組件來處理。服務注冊器通過輪詢或訂閱事件的方式來跟蹤運行實例的更改,一旦監測到有新的可用服務實例,會向注冊表注冊此服務。服務注冊器也負責注銷已終止的服務實例。架構圖如下圖所示:
Registrator 是一個開源的服務注冊器,他能夠自動注冊和注銷 Docker 容器中的服務實例,支持包括 etcd 和 Consul 在內的多種服務注冊表。
NetflixOSS Prana 是另一個服務注冊器,主要面向非 JVM 語言的服務,與服務實例一起運行。Prana 使用 Netflix Eureka 來注冊和注銷服務實例。
第三方服務注冊器的優點:服務與服務注冊器解耦,無需為不同的編程語言實現服務注冊的邏輯,而是通過一個專有服務以集中化的方式進行管理。不足:除非內置在部署環境中,不然又是一個需要被維護和管理的高可用組件。
總結
微服務應用中,服務實例的網絡地址會動態的變化,因此,為了使客戶端能夠向服務端發起請求,必須有服務發現機制。
服務注冊表是服務發現的關鍵。服務注冊表是可用服務實例的數據庫,提供了管理和查詢的 API,服務實例使用管理 API 實現注冊和注銷,系統組件使用查詢 API 發現可用的服務實例。
服務發現有兩種模式:客戶端發現和服務端發現。使用客戶端發現的系統中,客戶端直接查詢注冊表,選擇一個可用實例發起請求;在服務端發現的系統中,客戶端通過路由轉發請求,路由會查詢服務注冊表并將請求轉發到可用服務實例上。
服務實例的注冊和注銷也有兩種方式。一是服務實例自己注冊到服務注冊表中,即自注冊模式;另一種是其他系統組件處理注冊和注銷,也就是第三方注冊模式。
在一些部署環境中,可以使用 Netflix Eureka、etcd、Apache Zookeeper 等實現服務發現。而另一些部署環境則內置了服務發現,例如,Kubernetes 和 Marathon 用來處理服務注冊和注銷,他們在集群的每個主機上運行一個代理完成服務端發現路由。
NHINX 能夠用作服務端發現負載均衡使用,服務注冊表可以向 NGINX 推送路由信息,例如使用 Cosul Template。