假設咱們寫的代碼會調用 REST API 或者 Thrift API 的服務。爲了完成一次請求,代碼須要知道服務實例的網絡位置(IP 地址和端口)。運行在物理硬件上的傳統應用中,服務實例的網絡位置是相對固定的;代碼能從一個偶爾更新的配置文件中讀取網絡位置。nginx
對於基於雲端的、現代化的微服務應用而言,這倒是一大難題,正以下圖所示。算法
服務實例的網絡位置都是動態分配的。因爲擴展、失敗和升級,服務實例會常常動態改變,所以,客戶端代碼須要使用更加複雜的服務發現機制。docker
服務發現有兩大模式:客戶端發現模式和服務端發現模式。咱們先來了解客客戶端發現模式。數據庫
使用客戶端發現模式時,客戶端決定相應服務實例的網絡位置,而且對請求實現負載均衡。客戶端查詢服務註冊表,後者是一個可用服務實例的數據庫;而後使用負載均衡算法從中選擇一個實例,併發出請求。編程
客戶端從服務註冊服務中查詢,其中是全部可用服務實例的庫。客戶端使用負載均衡算法從多個服務實例中選擇出一個,而後發出請求。緩存
下圖顯示了這種模式的架構:服務器
服務實例的網絡位置在啓動時被記錄到服務註冊表,等實例終止時被刪除。服務實例的註冊信息一般使用心跳機制來按期刷新。網絡
Netflix OSS 是客戶端發現模式的絕佳範例。Netflix Eureka 是一個服務註冊表,爲服務實例註冊管理和查詢可用實例提供了 REST API 接口。Netflix Ribbon 是 IPC 客戶端,與 Eureka 一塊兒實現對請求的負載均衡。咱們會在後面深刻討論 Eureka。架構
客戶端發現模式優缺點兼有。這一模式相對直接,除了服務註冊外,其它部分無需變更。此外,因爲客戶端知曉可用的服務實例,能針對特定應用實現智能負載均衡,好比使用哈希一致性。這種模式的一大缺點就是客戶端與服務註冊綁定,要針對服務端用到的每一個編程語言和框架,實現客戶端的服務發現邏輯。併發
分析過客戶端發現後,咱們來了解服務端發現。
另一種服務發現的模式是服務端發現模式,下圖展示了這種模式的架構:
客戶端經過負載均衡器向某個服務提出請求,負載均衡器查詢服務註冊表,並將請求轉發到可用的服務實例。如同客戶端發現,服務實例在服務註冊表中註冊或註銷。
AWS Elastic Load Balancer(ELB)是服務端發現路由的例子,ELB 一般均衡來自互聯網的外部流量,也可用來負載均衡 VPC(Virtual private cloud)的內部流量。客戶端使用 DNS 經過 ELB 發出請求(HTTP 或 TCP),ELB 在已註冊的 EC2 實例或 ECS 容器之間負載均衡。這裏並無單獨的服務註冊表,相反,EC2 實例和 ECS 容器註冊在 ELB。
HTTP 服務器與相似 NGINX PLUS 和 NGINX 這樣的負載均衡起也能用做服務端的發現均衡器。Graham Jenson 的Scalable Architecture DR CoN: Docker, Registrator, Consul, Consul Template and Nginx 一文就描述如何使用 Consul Template 來動態配置 NGINX 反向代理。Consul Template 按期從 Consul Template 註冊表中的配置數據中生成配置文件;文件發生更改即運行任意命令。在這篇文章中,Consul Template 生成 nginx.conf 文件,用於配置反向代理,而後運行命令,告訴 NGINX 從新加載配置文件。在更復雜的實現中,須要使用 HTTP API 或 DNS 來動態配置 NGINX Plus。
Kubernetes 和 Marathon 這樣的部署環境會在每一個集羣上運行一個代理,將代理用做服務端發現的負載均衡器。客戶端使用主機 IP 地址和分配的端口經過代理將請求路由出去,向服務發送請求。代理將請求透明地轉發到集羣中可用的服務實例。
服務端發現模式兼具優缺點。它最大的優勢是客戶端無需關注發現的細節,只須要簡單地向負載均衡器發送請求,這減小了編程語言框架須要完成的發現邏輯。而且如上文所述,某些部署環境免費提供這一功能。這種模式也有缺點。除非負載均衡器由部署環境提供,不然會成爲一個須要配置和管理的高可用系統組件。
服務註冊表是服務發現的核心部分,是包含服務實例的網絡地址的數據庫。服務註冊表須要高可用並且隨時更新。客戶端可以緩存從服務註冊表中獲取的網絡地址,然而,這些信息最終會過期,客戶端也就沒法發現服務實例。所以,服務註冊表會包含若干服務端,使用複製協議保持一致性。
如前所述,Netflix Eureka 是服務註冊表的上好案例,爲註冊和請求服務實例提供了 REST API。服務實例使用 POST 請求來註冊網絡地址,每三十秒使用 PUT 請求來刷新註冊信息。註冊信息也能經過 HTTP DELETE 請求或者實例超時來被移除。以此類推,客戶端可以使用 HTTP GET 請求來檢索已註冊的服務實例。
Netflix 經過在每一個 AWS EC2 域運行一個或者多個 Eureka 服務實現高可用性。每一個 Eureka 服務器都運行在擁有彈性 IP 地址的 EC2 實例上。DNS TEXT 記錄被用來保存 Eureka 集羣配置,後者包括可用域和 Eureka 服務器的網絡地址列表。Eureka 服務在啓動時會查詢 DNS 去獲取 Eureka 集羣配置,肯定同伴位置,以及給本身分配一個未被使用的彈性 IP 地址。
Eureka 客戶端,包括服務和服務客戶端,查詢 DNS 去發現 Eureka 服務的網絡地址。客戶端首選同一域內的 Eureka 服務。然而,若是沒有可用服務,客戶端會使用其它可用域中的 Eureka 服務。
其它的服務註冊表包括:
此外,如前所強調,像 Kubernetes、Marathon 和 AWS 並無明確的服務註冊,相反,服務註冊已經內置在基礎設施中。
瞭解了服務註冊的概念後,如今瞭解服務實例如何在註冊表中註冊。
如前所述,服務實例必須在註冊表中註冊和註銷。註冊和註銷有兩種不一樣的方法。方法一是服務實例本身註冊,也叫自注冊模式(self-registration pattern);另外一種是採用管理服務實例註冊的其它系統組件,即第三方註冊模式。
當使用自注冊模式時,服務實例負責在服務註冊表中註冊和註銷。另外,若是須要的話,一個服務實例也要發送心跳來保證註冊信息不會過期。下圖描述了這種架構:
Netflix OSS Eureka 客戶端是很是好的案例,它負責處理服務實例的註冊和註銷。Spring Cloud 可以執行包括服務發如今內的各類模式,使得利用 Eureka 自動註冊服務實例更簡單,只須要給 Java 配置類註釋 @EnableEurekaClient。
自注冊模式優缺點兼備。它相對簡單,無需其它系統組件。然而,它的主要缺點是把服務實例和服務註冊表耦合,必須在每一個編程語言和框架內實現註冊代碼。
另外一個方案將服務與服務註冊表解耦合,被稱做第三方註冊模式。
使用第三方註冊模式,服務實例則不須要向服務註冊表註冊;相反,被稱爲服務註冊器的另外一個系統模塊會處理。服務註冊器會經過查詢部署環境或訂閱事件的方式來跟蹤運行實例的更改。一旦偵測到有新的可用服務實例,會向註冊表註冊此服務。服務管理器也負責註銷終止的服務實例。下面是這種模式的架構圖。
Registrator 是一個開源的服務註冊項目,它可以自動註冊和註銷被部署爲 Docker 容器的服務實例。Registrator 支持包括 etcd 和 Consul 在內的多種服務註冊表。
NetflixOSS Prana 是另外一個服務註冊器,主要面向非 JVM 語言開發的服務,是一款與服務實例一塊兒運行的並行應用。Prana 使用 Netflix Eureka 來註冊和註銷服務實例。
服務註冊器是部署環境的內置組件。由 Autoscaling Group 建立的 EC2 實例可以自動向 ELB 註冊。Kubernetes 服務自動註冊並可以被發現。
第三方註冊模式也是優缺點兼具。在第三方註冊模式中,服務與服務註冊表解耦合,無需爲每一個編程語言和框架實現服務註冊邏輯;相反,服務實例經過一個專有服務以中心化的方式進行管理。它的不足之處在於,除非該服務內置於部署環境,不然須要配置和管理一個高可用的系統組件。
在微服務應用中,服務實例的運行環境會動態變化,實例網絡地址也是如此。所以,客戶端爲了訪問服務必須使用服務發現機制。
服務註冊表是服務發現的關鍵部分。服務註冊表是可用服務實例的數據庫,提供管理 API 和查詢 API。服務實例使用管理 API 來實現註冊和註銷,系統組件使用查詢 API 來發現可用的服務實例。
服務發現有兩種主要模式:客戶端發現和服務端發現。在使用客戶端服務發現的系統中,客戶端查詢服務註冊表,選擇可用的服務實例,而後發出請求。在使用服務端發現的系統中,客戶端經過路由轉發請求,路由器查詢服務註冊表並轉發請求到可用的實例。
服務實例的註冊和註銷也有兩種方式。一種是服務實例本身註冊到服務註冊表中,即自注冊模式;另外一種則是由其它系統組件處理註冊和註銷,也就是第三方註冊模式。
在一些部署環境中,須要使用 Netflix Eureka、etcd、Apache Zookeeper 等服務發現來設置本身的服務發現基礎設施。而另外一些部署環境則內置了服務發現。例如,Kubernetes 和 Marathon 處理服務實例的註冊和註銷,它們也在每一個集羣主機上運行代理,這個代理具備服務端發現路由的功能。
HTTP 反向代理和 NGINX 這樣的負載均衡器可以用作服務器端的服務發現均衡器。服務註冊表可以將路由信息推送到 NGINX,激活配置更新,譬如使用 Cosul Template。NGINX Plus 支持額外的動態配置機制,可以經過 DNS 從註冊表中獲取服務實例的信息,併爲遠程配置提供 API。
英文原文:https://www.nginx.com/blog/service-discovery-in-a-microservices-architecture/