跳到主要內容
黯羽輕揚每天積累一點點

Service Discovery_系統設計筆記 7

免費2020-02-16#Back-End#服务发现#服务注册发现#微服务间通信#DNS-SD#DNS SRV

微服務架構負責拆分服務、解耦依賴關係,而 Service Discovery 用來解決這些服務間的通訊問題,讓一個微服務能夠找到另一個

一。應用層

在簡單的 3 層結構中,Web 服務層既要處理請求,又要承載業務功能:

而更優的結構是把 Web 層與應用層(也叫平臺層)分開:

優勢在於:

  • 能夠單獨擴充套件應用層:允許獨立加機器、換專用機器等

  • 複用基礎設施:簡化多端支援,快取、資料庫等處理都可以複用

  • 使得組織更容易擴充套件:一個團隊負責實現/優化平臺本身,其它多個團隊利用平臺功能進行開發

分離出應用層之後,面臨的下一個問題是應用層內部如何劃分職責,如何協同工作,也就是微服務架構所要解決的問題

二。微服務架構

微服務架構提倡把應用程式設計成一系列鬆耦合的細粒度服務,並通過輕量級的通訊協議組織起來:

In a microservices architecture, an application is structured as a collection of loosely coupled services, which are fine-grained and the protocols are lightweight.

這些服務都能夠獨立部署、獨立擴充套件,每個服務都具有穩固的模組邊界,甚至允許使用不同的程式語言來編寫不同服務,也可以由不同的團隊來管理:

P.S. 關於微服務架構的更多資訊,見 微服務架構(Microservices)

微服務架構下,應用被拆分成了多個服務,各自執行在(不同機器的)不同程序中:

如果每個微服務都只執行在單臺機器上,一個微服務可以通過靜態配置表找到其它依賴服務,進而通過服務間通訊完成協作

然而,實際場景下,1 個微服務通常會部署在多臺機器上,並按需動態伸縮(增減機器),簡單的靜態配置顯然無法滿足,因而需要一種服務註冊查詢機制

即 Service Discovery

三。Service Discovery

客戶端 Service Discovery

客戶端查詢服務註冊表,得到目標服務的一系列地址,並根據負載均衡策略從中選擇一個發起請求(即 客戶端負載均衡

其中,服務註冊表(service registry) 用來存放所有可用的服務例項,並提供管理(註冊/註銷)和查詢 API:

The service registry is a database of available service instances. The service registry provides a management API and a query API. Service instances are registered with and deregistered from the service registry using the management API. The query API is used by system components to discover available service instances.

具體的,在啟動服務例項時,向註冊表新增其網路位置,停掉服務時移除記錄,並在服務例項執行期間,通過心跳機制週期性地重新整理註冊資訊

P.S. 例如 Netflix Eureka 提供了 REST API 用來註冊/註銷、查詢服務例項:

Netflix Eureka provides a REST API for registering and querying service instances. A service instance registers its network location using a POST request. Every 30 seconds it must refresh its registration using a PUT request. A registration is removed by either using an HTTP DELETE request or by the instance registration timing out. As you might expect, a client can retrieve the registered service instances by using an HTTP GET request.

以及配套的 Netflix Ribbon,用作客戶端負載均衡

這種模式相對簡單,而且客戶端能夠做出更聰明的(比如特定於應用程式的)負載均衡決策,但也存在一些缺點:

  • 客戶端用到的每種語言都要實現一遍

  • 需要自行維護一個高可用的註冊服務

  • 服務發現相關邏輯都在客戶端實現,比如重試,造成客戶端比較重

DNS-SD

特殊的,可以將 DNS 用作服務註冊表,稱之為 DNS-SD(DNS-based Service Discovery)

通過 DNS SRV 記錄來完成服務到例項的一對多對映:

SRV 記錄(Service locator record):通用服務定位記錄,指定服務所在的伺服器(域名和埠號),多用於 SIP(Session Initiation Protocol,會話發起協議)

(摘自 資源記錄 | DNS_系統設計筆記 3

例如:

$ nslookup -query=SRV _http._tcp.backends.example.com 10.0.0.2
Server:		10.0.0.2
Address:	10.0.0.2#53

_http._tcp.backends.example.com	service = 0 2 8090 backend-0.example.com.
_http._tcp.backends.example.com	service = 0 1 8091 backend-1.example.com.
_http._tcp.backends.example.com	service = 10 1 8092 backend-2.example.com.

藉助 DNS 雖然簡單易操作,但受限於 DNS 的更新時效(快取問題)

服務端 Service Discovery

當然,查詢的過程也可以在服務端完成:

客戶端通過負載均衡器請求目標服務,負載均衡器查註冊表得到一組可用例項,並根據負載均衡策略從中選擇一個發起請求

P.S. 例如 AWS Elastic Load Balancer (ELB)

這種模式下,客戶端不必再為各種語言、不同框架實現服務查詢邏輯,簡單地向負載均衡器發起請求即可,但如果部署平臺沒有提供這種能力的話,需要自行建立並維護這樣一個高可用的系統元件

四。服務註冊與註銷

Service Discovery 中,服務例項必須註冊到服務註冊表,並及時註銷,分為自註冊與第三方註冊 2 種模式

自註冊模式

自註冊模式下,服務例項負責把自己註冊到服務註冊表,以及從中註銷,必要的話,還要傳送心跳請求保持活躍,避免其註冊過期

這種方式相對簡單,不依賴其它系統元件,但服務例項和服務註冊機制產生了耦合,以致於註冊邏輯需要在各種語言、不同框架的客戶端都實現一遍

P.S. Netflix OSS Eureka client 採用的就是這種模式,由 Eureka 客戶端來處理服務例項的註冊和註銷

第三方註冊模式

服務例項不再負責註冊/註銷,交由服務登記員(service registrar)來處理,解除了服務例項與註冊機制間的耦合關係。登記員通過輪詢部署平臺或訂閱事件來跟蹤服務例項的執行狀態,發現新服務例項就註冊上去,發現服務例項停掉了就註銷掉

P.S. Registrator 採用了這種模式,支援自動註冊/註銷用 Docker 容器部署的服務

特殊的,部署平臺掌控著服務例項的啟動與停止,由它來完成註冊、註銷再合適不過了。事實上,KubernetesMarathon 等部署平臺也都提供了服務註冊、查詢的能力。具體的,把集群中執行在每個節點上的代理服務用作服務端 Service Discovery 裡的負載均衡器,客戶端向代理傳送請求,由代理服務轉發給集群中其它節點上的可用例項

五。總結

微服務架構負責拆分服務、解耦依賴關係,而 Service Discovery 用來解決這些服務間的通訊問題,讓一個微服務能夠找到另一個

實現上,分為客戶端 Service Discovery 與服務端 Service Discovery 兩種,區別在於查詢/選取邏輯實現在客戶端還是服務端。而服務的註冊/註銷可以由服務自身完成(自註冊),也可以由部署平臺等第三方來完成(第三方註冊)

參考資料

評論

暫無評論,快來發表你的看法吧

提交評論