文章目錄
- 應用層
- 微服務架構
- 服務注冊查詢 Service Discovery
- 客戶端 Service Discovery
- DNS-SD DNS-based Service Discovery
- 服務端 Service Discovery
- 服務注冊與注銷
- 自注冊模式
- 第三方注冊模式
- 總結
- 參考
應用層
在簡單的 3 層結構中,Web 服務層既要處理請求,又要承載業務功能:
而更優的結構是把 Web 層與應用層(也叫平臺層)分開:
這樣的優勢在于:
- 能夠單獨擴展應用層;允許獨立加機器、換專用機器
- 復用基礎設施:簡化多端支持,緩存、數據庫等處理都可以復用
- 使得組織更容易擴展:一個團隊負責實現/優化平臺本身,其他多個團隊利用平臺功能進行開發
分離出應用層之后,面臨的下一個問題是應用層內部如何劃分職責,如何協同工作,也就是微服務架構所要解決的問題
微服務架構
Monolithic application 架構
把軟件應用的不同組件都放到一個程序中,就叫 Monolithic application。例如,通過編程語言的基本特性將應用劃分成類、函數和命名空間,用部署流水線來保證變更都經過測試后才部署到生產環境,并通過負載均衡機制運行多個實例,將其進行橫向擴展。
在這種架構模式下,應用程序也能很好地工作,但存在 2 個問題:
- 變更受限制:很小的一處變更也需要對整個應用進行重新構建和部署,而且難以控制變更的影響范圍
- 不利于擴展:無法僅擴展應用中需要更多資源的那些部分,只能擴展整個應用
這些限制在云環境下尤其突出。于是,微服務架構登上了舞臺。
微服務架構提倡把應用程序設計成一系列松耦合的細粒度服務,并通過輕量級的通信協議組織起來。
這些服務都能夠獨立部署、獨立擴展,每個服務都具有穩固的模塊邊界,甚至允許使用不同的編程語言來編寫不同服務,也可以由不同的團隊來管理。
微服務架構具有下面 9 大特征:
1、通過服務進行組件化(Componentization via Services)
組件可以理解為能夠獨立更換升級的軟件單元,一系列組件插在一起構成軟件系統。
在微服務架構中,組件就是服務,通過 Web 服務請求或 RPC 之類的機制通信。這種服務粒度的組件化方式有 2 點優勢: - 服務能夠獨立部署
- 服務具有顯式的對外接口
獨立部署,意味著對一個服務的內部改動只需要重新部署該服務,涉及服務接口改動時才需要協同修改多個服務。另一方面,還可以通過服務邊界和服務協議方面的演進來盡可能減少這樣的關聯。顯式的對外接口則是一種強約束,能夠保證組件的封裝性,避免組件間出現過度的緊耦合。但比起進程內調用,RPC 的性能成本更高,因此 RPC 接口大多是粗粒度的,也往往更難使用。另一方面,如果想要調整組件職責的話,重構成本也更高。
2、圍繞業務功能來組織團隊(Organized around Business Capabilities)
微服務允許將系統根據業務功能分解成一系列服務,因此可以圍繞業務功能來組織跨職能的團隊。并且,這種組織結構還有利于強化服務邊界。比起在 Monolithic application 中按業務線劃分團隊,以服務為邊界更清晰、約束力也更強。因為很容易出現跨越模塊邊界的業務功能,而服務邊界相對穩固一些。
3、做產品而不是做項目(Products not Projects)
微服務架構傾向于一個產品由所屬開發團隊長期維護/演進,而不是項目交付后轉由另一個維護團隊負責。
這種產品理念能夠在開發團隊與用戶之間建立持續的關聯,讓開發團隊關注到軟件如何幫助用戶增進業務功能。
4、智能端點和傻瓜式管道(Smart endpoints and dumb pipes)
通信機制上,一個典型的例子是企業服務總線(Enterprise Service Bus),消息都流經 ESB,由 ESB 負責消息路由、編排、轉換以及業務規則的應用,隨后到達端點(endpoints)進行處理。這種模式下,端點可以保持傻瓜式,因為很多邏輯都在 ESB 消息管道里處理了。因此,稱之為智能管道和傻瓜式端點(smart pipes and dumb endpoints)。
而微服務傾向于相反的做法,智能端點和傻瓜式管道(smart endpoints and dumb pipes):管道只負責在組件之間分發消息,由服務本身針對消息做相應處理。
5、去中心化技術治理(Decentralized Governance)
中心化技術治理最大的問題在于其局限性,統一的技術棧并不一定適用于所有場景。
而在微服務背景下,每個服務單獨構建,就有了選擇不同技術棧的機會,允許用更合適的工具去做不同的事情。這種技術棧上的自由有助于服務獨立演進,自然選擇出更好的模式。
6、去中心化數據管理(Decentralized Data Management)
從最抽象的層面看,去中心化地管理數據,意味著各個系統對客觀世界所形成的概念模型各不相同。給模型概念限定一個上下文,在該上下文中保證概念嚴格一致。把一個復雜領域劃分成多個界限上下文,再將其間關聯勾畫出來,就是概念模型層面的去中心化。具體到數據存儲上,微服務也進行類似的去中心化策略,讓每一個服務管理自己的數據庫。這些數據庫可以是相同數據庫的不同實例,也可以是完全不同的數據庫系統,稱之為混合持久化。對于去中心化數據存儲帶來的數據一致性問題,可以考慮通過一些補償操作來讓數據最終達到一致。
7、基礎設施自動化(Infrastructure Automation)
與 Monolithic application 相比,微服務的部署要更復雜一些。因為在復雜的網絡環境中,部署多個服務比部署一個獨立應用更困難。
8、容錯設計(Design for failure)
在微服務背景下,客戶端的容錯設計更為重要:
將服務作為組件使用的一個結果是,應用程序需要設計為能夠容忍服務故障。
由于供應商不可用,任何服務呼叫都可能失敗,客戶必須盡可能優雅地響應。
比起 Monolithic application,這種容錯設計帶來的額外復雜性算是一種劣勢。另一方面,為了快速檢測到故障點,甚至盡可能自動恢復服務,實時監控在微服務架構中也格外重要。
9、演進式設計(Evolutionary Design)
組件的劃分在微服務架構中很關鍵,關系到能否減少變化。一般原則是該組件能否獨立更換和升級。
把微服務架構提供的服務分解能力當做一種工具來使用,以此實現服務粒度的變化控制:
- 預期一些服務將來會作廢,不必長期演進
- 把那些會同時變化的東西放到同一個服務中,把很少發生變化的部分放到單獨服務中,與經常發生變化的部分區分開
服務注冊查詢 Service Discovery
微服務架構下,應用被拆分成了多個服務,各自運行在(不同機器的)不同進程中。
如果每個微服務都只運行在單臺機器上,一個微服務可以通過靜態配置表找到其它依賴服務,進而通過服務間通信完成協作。然而,實際場景下,1 個微服務通常會部署在多臺機器上,并按需動態伸縮(增減機器),簡單的靜態配置顯然無法滿足,因而需要一種服務注冊查詢機制:
這點即Service Discovery
客戶端 Service Discovery
客戶端查詢服務注冊表,得到目標服務的一系列地址,并根據負載均衡策略從中選擇一個發起請求(即客戶端負載均衡)。
其中,服務注冊表(service registry)用來存放所有可用的服務實例,并提供管理(注冊/注銷)和查詢 API:
服務注冊表是可用服務實例的數據庫。
服務注冊中心提供了一個管理API和一個查詢API。
使用管理API在服務注冊表中注冊和注銷服務實例。
系統組件使用查詢API來發現可用的服務實例。
具體的,在啟動服務實例時,向注冊表添加其網絡位置,停掉服務時移除記錄,并在服務實例運行期間,通過心跳機制周期性地刷新注冊信息。
這種模式相對簡單,而且客戶端能夠做出更聰明的(比如特定于應用程序的)負載均衡決策,但也存在一些缺點:
- 客戶端用到的每種語言都要實現一遍
- 需要自行維護一個高可用的注冊服務
- 服務發現相關邏輯都在客戶端實現,比如重試,造成客戶端比較重
DNS-SD DNS-based Service Discovery
特殊的,可以將 DNS 用作服務注冊表,稱之為DNS-SD(DNS-based Service Discovery)
通過 DNS SRV 記錄來完成服務到實例的一對多映射:
SRV 記錄(Service locator record):通用服務定位記錄,指定服務所在的服務器(域名和端口號),多用于 SIP(Session Initiation Protocol,會話發起協議)
借助 DNS 雖然簡單易操作,但受限于 DNS 的更新時效(緩存問題)
服務端 Service Discovery
當然,查詢的過程也可以在服務端完成:
客戶端通過負載均衡器請求目標服務,負載均衡器查注冊表得到一組可用實例,并根據負載均衡策略從中選擇一個發起請求。
這種模式下,客戶端不必再為各種語言、不同框架實現服務查詢邏輯,簡單地向負載均衡器發起請求即可,但如果部署平臺沒有提供這種能力的話,需要自行建立并維護這樣一個高可用的系統組件。
服務注冊與注銷
Service Discovery 中,服務實例必須注冊到服務注冊表,并及時注銷,分為自注冊與第三方注冊 2 種模式。
自注冊模式
自注冊模式下,服務實例負責把自己注冊到服務注冊表,以及從中注銷,必要的話,還要發送心跳請求保持活躍,避免其注冊過期。這種方式相對簡單,不依賴其它系統組件,但服務實例和服務注冊機制產生了耦合,以致于注冊邏輯需要在各種語言、不同框架的客戶端都實現一遍。
第三方注冊模式
服務實例不再負責注冊/注銷,交由服務登記員(service registrar)來處理,解除了服務實例與注冊機制間的耦合關系。登記員通過輪詢部署平臺或訂閱事件來跟蹤服務實例的運行狀態,發現新服務實例就注冊上去,發現服務實例停掉了就注銷掉。
例如Registrator就采用了這種模式,支持自動注冊/注銷用 Docker 容器部署的服務。
總結
微服務架構負責拆分服務、解耦依賴關系,而 Service Discovery 用來解決這些服務間的通信問題,讓一個微服務能夠找到另一個。
實現上,分為客戶端 Service Discovery 與服務端 Service Discovery 兩種,區別在于查詢/選取邏輯實現在客戶端還是服務端。而服務的注冊/注銷可以由服務自身完成(自注冊),也可以由部署平臺等第三方來完成(第三方注冊)
參考
http://www.ayqy.net/blog/service-discovery/