微服務架構全景
1 微服務優勢與挑戰
1.1 微服務的優勢
1.1.1 單一職責
微服務架構中的每個節點高度服務化,都是具有業務邏輯的,符合高內聚、低耦合原則以及單一職責原則的單元,包括數據庫和數據模型;
不同的服務通過 “管道” 的方式靈活組合,從而構建出龐大的系統。
1.1.2 輕量級通信
通過 REST API 模式或者 RPC 框架,事件流和消息代理的組合相互通信,實現服務間互相協作的輕量級通信機制。
1.1.3 獨立性
在微服務架構中,每個服務都是獨立的業務單元,與其他服務高度解耦,只需要改變當前服務本身,就可以完成獨立的開發、測試、部署、運維。
1.1.4 進程隔離
在微服務架構中,應用程序由多個服務組成,每個服務都是高度自治的獨立業務實體,可以運行在獨立的進程中,不同的服務能非常容易地部署到不同的主機上,實現高度自治和高度隔離。
進程的隔離,還能保證服務達到動態擴縮容的能力,業務高峯期自動增加服務資源以提升併發能力,業務低谷期則可自動釋放服務資源以節省開銷。
1.1.5 混合技術棧和混合部署方式
團隊可以爲不同的服務組件使用不同的技術棧和不同的部署方式(公有云、私有云、混合雲)。
1.1.6 簡化治理
組件可以彼此獨立地進行縮放,從而減少了因必須縮放整個應用程序而產生的浪費和成本,獨立的發佈、服務治理。
1.1.7 安全可靠,可維護。
從架構上對運維提供友好的支撐,在安全、可維護的基礎上規範化發佈流程,支持數據存儲容災、業務模塊隔離、訪問權限控制、編碼安全檢測等。
1.2 面臨的挑戰
1.2.1 分佈式固有複雜性
微服務架構是基於分佈式的系統,而構建分佈式系統必然會帶來額外的開銷。
-
性能:分佈式系統是跨進程、跨網絡的調用,受網絡延遲和帶寬的影響。
-
可靠性:由於高度依賴於網絡狀況,任何一次的遠程調用都有可能失敗,隨着服務的增多還會出現更多的潛在故障點。因此,如何提高系統的可靠性、降低因網絡引起的故障率,是系統構建的一大挑戰。
-
分佈式通信:分佈式通信大大增加了功能實現的複雜度,並且伴隨着定位難、調試難等問題。
-
數據一致性:需要保證分佈式系統的數據強一致性,即在 C(一致性)A(可用性)P(分區容錯性) 三者之間做出權衡。這塊可以參考我的這篇《分佈式事務》。
1.2.2 服務的依賴管理和測試
在單體應用中,通常使用集成測試來驗證依賴是否正常。而在微服務架構中,服務數量衆多,每個服務都是獨立的業務單元,服務主要通過接口進行交互,如何保證它的正常,是測試面臨的主要挑戰。
所以單元測試和單個服務鏈路的可用性非常重要。
1.2.3 有效的配置版本管理
在單體系統中,配置可以寫在 yaml 文件,分佈式系統中需要統一進行配置管理,同一個服務在不同的場景下對配置的值要求還可能不一樣,所以需要引入配置的版本管理、環境管理。
1.2.4 自動化的部署流程
在微服務架構中,每個服務都獨立部署,交付週期短且頻率高,人工部署已經無法適應業務的快速變化。有效地構建自動化部署體系,配合服務網格、容器技術,是微服務面臨的另一個挑戰。
1.2.5 對於 DevOps 更高的要求
在微服務架構的實施過程中,開發人員和運維人員的角色發生了變化,開發者也將承擔起整個服務的生命週期的責任,包括部署、鏈路追蹤、監控;因此,按需調整組織架構、構建全功能的團隊,也是一個不小的挑戰。
1.2.6 運維成本
運維主要包括配置、部署、監控與告警和日誌收集四大方面。微服務架構中,每個服務都需要獨立地配置、部署、監控和收集日誌,成本呈指數級增長。
服務化粒度越細,運維成本越高。
怎樣去解決這些問題,是微服務架構必須面臨的挑戰。
2 微服務全景架構
3 微服務核心組件
微服務架構核心組件包括:
組件名
- 服務註冊與發現
- API 網關服務
- 分佈式配置中心
- 服務通信
- 服務治理
- 服務監控
- 分佈式服務追蹤
3.1 服務註冊與發現
3.1.1 原理圖
服務註冊與發現三要素:
-
Provider:服務的提供方
-
Consumer:調用遠程服務的服務消費方
-
Registry:服務註冊和發現的註冊中心
3.1.2 註冊中心的原理、流程
1、 Provider(服務提供者) 綁定指定端口並啓動服務
2、提供者連接註冊中心,併發本機 IP、端口、應用信息和服務信息發送至註冊中心存儲
3、Consumer(消費者),連接註冊中心 ,併發送應用信息、所求服務信息至註冊中心
4、註冊中心根據消費者所求服務信息匹配對應的提供者列表發送至 Consumer 應用緩存。
5、Consumer 在發起遠程調用時基於緩存的消費者列表擇其一發起調用。
6、Provider 狀態變更會實時通知註冊中心、在由註冊中心實時推送至 Consumer 設計的原因:
Consumer 與 Provider 解偶,雙方都可以橫向增減節點數。註冊中心對本身可做對等集羣,可動態增減節點,並且任意一臺宕掉後,將自動切換到另一臺
7、去中心化,雙方不直接依賴註冊中心,即使註冊中心全部宕機短時間內也不會影響服務的調用(Consumer 應用緩存中保留提供者 Provider 列表)
8、服務提供者無狀態,任意一臺宕掉後,不影響使用
註冊中心包含如下功能:註冊中心、服務註冊和反註冊、心跳監測與彙報、服務訂閱、服務變更查詢、集羣部署、服務健康狀態檢測、服務狀態變更通知 等
我們有很多種註冊中心的技術,Zookeeper、Etcd、Consul、Eureka 4 種比較常用,如下
分佈式系統中 CAP 模型 3 者不可兼得。由於網絡的原因,分佈式系統中 P 是必備的,意味着只能選擇 AP 或者 CP。CP 代表數據一致性是第一位的,AP 代表可用性是第一位的。
Zookeeper、Etcd、Consul 是 CP 型註冊中心,犧牲可用性來保證數據強一致性
Eureka 是 AP 型註冊中心,犧牲一致性來保證可用性
3.2 API 網關服務
上面是 Api 網關服務的基本架構:用戶的請求經過統一的 Api 網關來訪問微服務裏具體的服務顆粒,並且可能產生串聯的鏈路服務調用。
有很多耳熟能詳的 API 網關技術,比如 Zuul、Kong、Tyk 等,提供了服務路由在內的很多通用功能,後面會有專門的章節來說這個。
Tyk:Tyk 是一個開放源碼的 API 網關,它是快速、可擴展和現代的。Tyk 提供了一個 API 管理平臺,其中包括 API 網關、API 分析、開發人員門戶和 API 管理面板。Try 是一個基於 Go 實現的網關服務。
Kong:Kong 是一個可擴展的開放源碼 API Layer(也稱爲 API 網關或 API 中間件)。Kong 在任何 RESTful API 的前面運行,通過插件擴展,它提供了超越核心平臺的額外功能和服務。
Netflix zuul:Zuul 是一種提供動態路由、監視、彈性、安全性等功能的邊緣服務。Zuul 是 Netflix 出品的一個基於 JVM 路由和服務端的負載均衡器。
除了路由之外,Api 網關服務還包含:認證和授權,重試、熔斷、降級,負載均衡,日誌、監控、鏈路追蹤,灰度發佈,ABTesting 等功能。
3.3 配置中心
上面這個是攜程的開源配置中心 Apollo 系統的架構設計,我們從下往上進行分析:
1、Config Service 提供配置的讀取、推送等功能,服務對象是 Apollo 客戶端
2、Admin Service 提供配置的修改、發佈等功能,服務對象是 Apollo Portal(管理界面)
3、Config Service 和 Admin Service 都是多實例、無狀態部署,所以需要將自己註冊到 Eureka 中並保持心跳,支持註冊、更新、刪除能力
4、在 Eureka 之上我們架了一層 Meta Server 用於封裝 Eureka 的服務發現接口
5、Client 通過域名訪問 Meta Server 獲取 Config Service 服務列表(IP+Port),而後直接通過 IP+Port 訪問服務,同時在 Client 側會做 load balance、錯誤重試
6、Portal 通過域名訪問 Meta Server 獲取 Admin Service 服務列表(IP+Port),而後直接通過 IP+Port 訪問服務,同時在 Portal 側會做 load balance、錯誤重試
7、爲了簡化部署,我們實際上會把 Config Service、Eureka 和 Meta Server 三個邏輯角色部署在同一個 JVM 進程中
上面的架構體現瞭如下特點:
• 高可用:配置服務爲多實例部署,訪問層保證 load balance、錯誤重試
• 弱依賴:使用了 Eureka 來做配置中心的服務註冊,如果出現問題或者網絡出現問題的時候,服務應該可以依賴於它本身所緩存的配置來提供正常的服務
3.4 服務通信
分佈式系統一般是由多個微服務顆粒組成的,微服務與微服務之前存在互相調用,甚至多個鏈路訪問的情況。所以他們之間是需要通信的,通信方式繼承於 SOA,包含同步與異步兩種模式。
3.4.1 同步訪問方式
1、RPC 訪問模式
Remote Procedure Call Protocol,遠程過程調用協議,一般使用在分佈式業務或者微服務架構風格中。像調用本地函數一樣,去調用一個遠端服務。
本質上是請求鏈的底層,維護同一個端口,進行 socket 通信。常見的 RPC 技術包含 gRPC、Dubbo、Thrift 等。
2、REST 訪問模式
這個應該大家最常用,可以通過一套統一風格的接口模式,爲 Web,iOS 和 Android 等提供接口服務。
3.4.2 異步訪問方式
消息中間件:RabbitMQ、Kafka、RocketMQ 之類,對於實時性要求不那麼嚴格的服務請求和計算。
3.5 服務治理
常見的服務治理手段有如下幾種:
3.5.1 節點管理
服務調用失敗時可能是服務提供者自身出現,也可能是網絡發生故障,我們一般有兩種處理手段。
-
註冊中心主動摘除機制
這種機制要求服務提供者定時向註冊中心彙報心跳,如果超時,就認爲服務提供者出現問題,並將節點從服務列表中摘除。 -
服務消費者摘除機制
當服務提供者網絡出現異常,服務消費者調用就會失敗,如果持續錯誤就可以將它從服務提供者節點列表中移除。
3.5.2 負載均衡
服務消費者在從服務列表中選取可用節點時,如果能讓性能較好的服務機多承擔一些流量的話,就能充分利用機器的性能。這就需要對負載均衡算法做一些調整。
常用的負載均衡算法主要包括以下幾種:
-
Radom 隨機算法
從可用的服務節點中隨機選取一個節點。一般情況下,隨機算法是均勻的,也就是說後端服務節點無論配置好壞,最終得到的調用量都差不多。 -
Round Robin 輪詢算法(加權重)
就是按照固定的權重,對可用服務節點進行輪詢。如果所有服務節點的權重都是相同的,則每個節點的調用量也是差不多的。但可以給性能較好的節點的權重調大些,充分發揮其性能優勢,提高整體調用的平均性能。 -
Least Conn 最少活躍調用算法
這種算法是在服務消費者這一端的內存裏動態維護着同每一個服務節點之間的連接數,選擇連接數最小的節點發起調用,也就是選擇了調用量最小的服務節點,性能理論上也是最優的。 -
一致性 Hash 算法
指相同參數的請求總是發到同一服務節點。當某一個服務節點出現故障時,原本發往該節點的請求,基於虛擬節點機制,平攤到其他節點上,不會引起劇烈變動。
3.5.3 服務路由
所謂的路由規則,就是通過一定的規則如條件表達式或者正則表達式來限定服務節點的選擇範圍。
制定路由規則主要有兩個原因。
- 業務存在灰度發佈、多版本 ABTesting 的需求
功能逐步開放發佈或者灰度測試的場景。
- 多機房就近訪問的需求
一般可以通過 IP 段規則來控制訪問,在選擇服務節點時,優先選擇同一 IP 段的節點。這個也是算力靠近的優先原則。
3.5.4 服務容錯
在分佈式系統中,分區容錯性是很重要的一個話題,要知道,服務間的調用調用並不總是成功,服務提供者程序 bug、異常退出 或者 消費者與提供者之間的網絡故障。而服務調用失敗之後,我們需要一些方法來保證調用的正常。
常用的方式有以下幾種:
FailOver 失敗自動切換。就是服務消費者發現調用失敗或者超時後,自動從可用的服務節點列表中選擇下一個節點重新發起調用,也可以設置重試的次數。
FailBack 失敗通知。就是服務消費者調用失敗或者超時後,不再重試,而是根據失敗的詳細信息,來決定後續的執行策略。
FailCache 失敗緩存。就是服務消費者調用失敗或者超時後,不立即發起重試,而是隔一段時間後再次嘗試發起調用。
FailFast 快速失敗。就是服務消費者調用一次失敗後,不再重試。
服務治理的手段是從不同角度來確保服務調用的成功率。節點管理是從服務節點健康狀態角度來考慮,負載均衡和服務路由是從服務節點訪問優先級角度來考慮,而服務容錯是從調用的健康狀態角度來考慮。
3.6 服務監控
常見的開發監控報警技術有 ELK、InfluxData 的 TICK、Promethues 等。
在分佈式系統中,微服務一般都具有複雜的鏈路調用,對於鏈路之間的狀態、服務可用性、調用情況的監控,是需要一套完整的服務監控系統去保障的。
如我們上面的那個圖所示, 服務系統主要由哪幾部分構成:
1、數據採集部分,包含性能指標信息、日誌信息(一般是服務埋點日誌或者 sidecar 的 inbound、outbound 信息)、端到端的 Trace 信息。
2、採集上來的監控數據通過傳輸系統,或者使用消息中間件來異步傳輸,或者調用服務端接口推送監控數據。並把這些數據持久化到我們的數據服務層中。
3、制定一套規則,對於採集到的數據進行清理、計算、分級等,處理好的數據,通過提前設置好的報警策略,來判斷它是否觸發了這些報警。
4、梳理完的數據可以進行查詢展示(有一個日誌查詢界面)、分級報警、分析趨勢報表推送等。
3.7 服務追蹤
服務追蹤的原理主要包括下面兩個關鍵點。
1、爲了實現請求跟蹤,當請求發送到分佈式系統的入口端點時,只需要服務跟蹤框架爲該請求創建一個唯一的跟蹤標識,同時在分佈式系統內部流轉的時候,框架始終保持傳遞該唯一標識,直到返回給請求方爲止,這個唯一標識就是前文中提到的 Trace ID。
通過 Trace ID 的記錄,我們就能將所有請求過程的日誌關聯起來。
2、爲了統計各處理單元的時間延遲,當請求到達各個服務組件時,或是處理邏輯到達某個狀態時,也通過一個唯一標識來標記它的開始、具體過程以及結束,該標識就是前文中提到的 Span ID。對於每個 Span 來說,它必須有開始和結束兩個節點,
通過記錄開始 Span 和結束 Span 的時間戳,就能統計出該 Span 的時間延遲,除了時間戳記錄之外,它還可以包含一些其他元數據,比如事件名稱、請求信息等。
上圖顯示了 Trace ID 和 Spand ID 在鏈路中的傳輸過程,它把服務調用的一個時序結構給展現出來了。
常見的服務鏈路追蹤的技術有 Zipkin、Pinpoint、SkyWalking 等。後面講到 Service Mesh 的時候會詳細說下 Zipkin 的 x-b3 header 頭傳遞,以及流量染色的使用,非常給力。
4 總結
微服務架構提倡的單一應用程序劃分成一組鬆散耦合的細粒度小型服務,輔助輕量級的協議,互相協調、互相配合,實現高效的應用價值,符合我們應用服務開發的發展趨勢。
後續我們圍繞它的核心模塊:服務註冊與發現、API 網關服務、分佈式配置中心、服務通信、服務治理、分佈式服務追蹤與監控等,從原理到實踐,一步步展開來研究。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/5pge6DrBM0HYHSGFMnhkrQ