這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
這是關於使用微服務架構建立應用系列的第四篇文章。第一篇介紹了微服務架構的模式,討論了使用微服務架構的優缺點。第二和第三篇描述了微服務架構內部的通訊機制。這篇文章中,我們將會探討服務發現相關問題。
為什麼要使用服務發現?
設想一下,我們正在寫代碼使用了提供REST API或者Thrift API的服務,為了完成一次服務要求,代碼需要知道服務執行個體的網路位置(IP地址和連接埠)。傳統應用都運行在物理硬體上,服務執行個體的網路位置都是相對固定的。例如,代碼可以從一個經常變更的設定檔中讀取網路位置。
而對於一個現代的,雲端式微服務的應用來說,這卻是一個很麻煩的問題。其架構:
服務執行個體的網路位置都是動態分配的,而且因為擴充、失效和升級等需求,服務執行個體會經常動態改變,因此,用戶端代碼需要使用一種更加複雜的服務發現機制。
目前有兩大類服務發現模式:用戶端發現和服務端發現。
我們先來來討論一下用戶端發現。
用戶端發現模式
當使用用戶端發現模式時,用戶端負責決定相應服務執行個體的網路位置,並且對請求實現負載平衡。用戶端從一個服務註冊服務中查詢,其中是所有可用服務執行個體的庫。用戶端使用負載平衡演算法從多個服務執行個體中選擇出一個,然後發出請求。
顯示的是這種模式的架構圖:
服務執行個體的網路位置是在啟動時註冊到服務註冊表中,並且在服務終止時從註冊表中刪除。服務執行個體註冊資訊一般是使用心跳機制來定期重新整理的。
Netflix OSS提供了一種非常棒的用戶端發現模式。Netflix Eureka是一個服務註冊表,為服務執行個體註冊管理和查詢可用執行個體提供了REST API介面。Netflix Ribbon是一種IPC用戶端,與Eureka合約工作實現對請求的負載平衡。我們會在後面詳細討論Eureka。
用戶端發現模式也是優缺點分明。這種模式相對比較直接,而且除了服務註冊表,沒有其它改變的因素。除此之外,因為用戶端知道可用服務註冊表資訊,因此用戶端可以通過使用雜湊一致性(hashing consistently)變得更加聰明,更加有效負載平衡。
而這種模式一個
最大的缺點是需要針對不同的程式設計語言註冊不同的服務,在用戶端需要為每種語言開發不同的服務發現邏輯。
我們分析過用戶端發現後,再看看服務端發現。
服務端發現模式
另外一種服務發現的模式是服務端發現模式(server-side discovery pattern),展現了這種模式的架構圖:
用戶端通過負載平衡器向某個服務提出請求,負載平衡器向服務註冊表發出請求,將每個請求轉寄往可用的服務執行個體。跟用戶端發現一樣,服務執行個體在服務註冊表中註冊或者登出。
AWS Elastic Load Balancer(ELB)是一種服務端發現路由的例子,ELB一般用於均衡從網路來的訪問流量,也可以使用ELB來均衡VPC內部的流量。用戶端使用DNS,通過ELB發出請求(HTTP或者TCP)。ELB負載平衡器負責在註冊的EC2執行個體或者ECS容器之間均衡負載,並不存在一個分離的服務註冊表,而EC2執行個體和ECS執行個體也向ELB註冊。
HTTP服務和類似NGINX和NGINX Plus的負載平衡器都可以作為服務端發現均衡器。例如,這篇博文就描述如何使用Consul Template來動態配置NGINX反向 Proxy。Consul Template是周期性從存放在Consul Template註冊表中配置資料重建設定檔的工具。當檔案發生變化時,會運行一個命令。在如上部落格中,Consul Template產生了一個nginx.conf檔案,用於配置反向 Proxy,然後運行一個命令,告訴NGINX重新調入設定檔。更複雜的例子可以用HTTP API或者DNS動態重新設定NGINX Plus。
某些部署環境,例如Kubernetes和Marathon在叢集每個節點上運行一個代理,此代理作為服務端發現負載平衡器。為了向服務發出請求,用戶端使用主機IP地址和分配的連接埠通過代理將請求路由出去。代理將次請求透明的轉寄到叢集中可用的服務執行個體。
服務端發現模式也有優缺點。最大的優點是用戶端無需關注發現的細節,用戶端只需要簡單的向負載平衡器發送請求,實際上減少了程式設計語言架構需要完成的發現邏輯。而且,如上說所,某些部署環境免費提供以上功能。
這種模式也有缺陷,除非部署環境提供負載平衡器,否則負載平衡器是另外一個需要組態管理的高可用系統功能。
服務註冊表
服務註冊表是服務發現很重要的部分,它是包含服務執行個體網路地址的資料庫。服務註冊表需要高可用而且隨時更新。用戶端可以緩衝從服務註冊表獲得的網路地址。然而,這些資訊最終會變得過時,用戶端也無法探索服務執行個體。因此,服務註冊表由若干使用複製協議保持同步的伺服器構成。
如前所述,Netflix Eureka是一個服務註冊表很好地例子,提供了REST API註冊和請求服務執行個體。 服務執行個體使用POST請求註冊網路地址,每30秒必須使用PUT方法更新註冊表,使用HTTP DELETE請求或者執行個體逾時來登出。可以想見,用戶端可以使用HTTP GET請求接受註冊服務執行個體資訊。
Netflix通過在每個AWS EC2域運行一個或者多個Eureka服務實現高可用性,每個Eureka伺服器都運行在擁有彈性IP地址的EC2執行個體上。DNS TEXT記錄用於儲存Eureka叢集配置,其中存放從可用域到一系列Eureka伺服器網路地址的列表。當Eureka服務啟動時,向DNS請求接受Eureka叢集配置,確認同伴位置,給自己分配一個未被使用的彈性IP地址。
Eureka用戶端—服務和服務用戶端—向DNS請求發現Eureka服務的網路地址,用戶端首選使用同一域內的服務。然而,如果沒有可用服務,用戶端會使用另外一個可用域的Eureka服務。
另外一些服務註冊表例子包括:
- etcd – 是一個高可用,分布式的,一致性的,索引值表,用於共用配置和服務發現。兩個著名案例包括Kubernetes和Cloud Foundry。
- consul – 是一個用於發現和配置的服務。提供了一個API允許用戶端註冊和探索服務。Consul可以用於健全狀態檢查來判斷服務可用性。
- Apache ZooKeeper – 是一個廣泛使用,為分布式應用提供高效能整合的服務。Apache ZooKeeper最初是Hadoop的子項目,現在已經變成頂級項目。
另外,前面強調過,某些系統,例如Kubernetes、Marathon和AWS並沒有獨立的服務註冊表,對他們來說,服務註冊表只是一個內建的功能。
現在我們來看看服務註冊表的概念,看看服務執行個體是如何在註冊表中註冊的。
服務註冊選項
如前所述,服務執行個體必須向註冊表中註冊和登出,如何註冊和登出也有一些不同的方式。一種方式是服務執行個體自己註冊,也叫自註冊模式(self-registration pattern);另外一種方式是為其它系統提供服務執行個體管理的,也叫第三方註冊模式(third party registration pattern)。我們來看看自註冊模式。
自註冊方式
當使用自註冊模式時,服務執行個體負責在服務註冊表中註冊和登出。另外,如果需要的話,一個服務執行個體也要發送心跳來保證註冊資訊不會過時。描述了這種架構:
一個很好地例子是 Netflix OSS Eureka client。Eureka用戶端負責處理服務執行個體的註冊和登出。Spring Cloud project,實現了多種模式,包括服務發現,使得向Eureka服務執行個體自動註冊時更容易。可以用@EnableEurekaClient注釋Java配置類。
自註冊模式也有優缺點。一個優點是,相對簡單,不需要其他系統功能。而一個主要缺點則是,把服務執行個體跟服務註冊表聯絡起來。必須在每種程式設計語言和架構內部實現註冊代碼。
另外一個方法,不需要串連服務和註冊表,則是第三方註冊模式。
第三方註冊模式
當使用第三方註冊模式時,服務執行個體並不負責向服務註冊表註冊,而是由另外一個系統模組,叫做服務管理員,負責註冊。服務管理員通過查詢部署環境或訂閱事件來跟蹤運行服務的改變。當管理器發現一個新可用服務,會向註冊表註冊此服務。服務管理員也負責登出終止的服務執行個體。是這種模式的架構圖。
一個服務管理員的例子是開源項目Registrator,負責自動註冊和登出被部署為Docker容器的服務執行個體。Reistrator支援多種服務管理員,包括etcd和Consul。
另外一個服務管理員例子是NetflixOSS Prana,主要面向非JVM語言開發的服務,也稱為附帶應用(sidecar application),Prana使用Netflix Eureka註冊和登出服務執行個體。
服務管理員是部署環境內建的模組。有自動擴充組建立的EC2執行個體可以自向ELB自動註冊,Kubernetes服務自動註冊並且對探索服務可用。
第三方註冊模式也是優缺點都有。主要的優點是服務跟服務註冊表是分離的,不需要為每種程式設計語言和架構完成服務註冊邏輯,替代的,服務執行個體是通過一個集中化管理的服務進行管理的。
一個缺點是,除非這種服務被內建於部署環境中,否則也需要組態管理一個高可用的系統。
總結
在一個微服務應用中,服務執行個體運行環境是動態變化的。執行個體網路地址也是動態變化的,因此,用戶端為了訪問服務必須使用服務發現機制。
服務發現關鍵區段是服務註冊表,也就是可用服務執行個體的資料庫。服務註冊表提供一種註冊管理API和請求API。服務執行個體使用註冊管理API來實現註冊和登出。
請求API用於發現可用服務執行個體,相對應的,有兩種主要服務發現模式:用戶端發現和服務端發現。
在使用用戶端發現的系統中,用戶端向服務註冊表發起請求,選擇可用執行個體,然後發出服務要求
而在使用服務端發現的系統中,用戶端通過路由轉寄請求,路由器向服務註冊表發出請求,轉寄此請求到某個可用執行個體。
服務執行個體註冊和登出主要有兩類方式。一種是服務執行個體自動註冊到服務註冊表中,也就是自註冊模式;另外一種則是某個系統模組負責處理註冊和登出,也就是第三方註冊模式。
在某些部署環境中,需要配置自己的服務發現架構,例如:Netflix Eureka、etcd或者Apache ZooKeeper。而在另外一些部署環境中,則內建了這種功能,例如Kubernetes和Marathon 負責處理服務執行個體的註冊和登出。他們也在每個叢集節點上運行代理,來實現服務端發現路由器的功能。
HTTP反向 Proxy和負載據衡器(例如NGINX)可以用於服務發現負載平衡器。服務註冊表可以將路由資訊推送到NGINX,啟用一個即時配置更新;例如,可以使用 Consul Template。NGINX Plus 支援額外的動態重新設定機制,可以使用DNS,將服務執行個體資訊從註冊表中拉下來,並且提供遠程配置的API。
在未來的部落格中,我們還將深入探討微服務其它特點。可以註冊NGINX郵件清單來獲得最新產品更新提示。
此篇其它部落格譯文參見如下地址:
- 微服務架構的優勢與不足
- 使用API Gateway
- 深入微服務架構的處理序間通訊
原文連結:Service Discovery in a Microservices Architecture (翻譯:楊峰 校對:宋喻)