首頁>技術>

作者 | Bibek Shah

策劃 | 田曉旭

微服務的目標是將應用程式儘量分解 / 解耦為圍繞業務功能組織的一系列鬆散耦合服務。這些分散式的微型單元共同滿足應用程式的目標。

將單個應用程式拆分為多個微服務後,跨越多個服務的事務(讀取和寫入)就變得不可避免了。進而, 跨各個微服務邊界的通訊——工作流管理——資料儲存機制 就成為了挑戰。這一系統應符合被稱為分散式計算謬誤的準則。當跨多個服務(每個都有自己的業務邏輯和資料庫)處理事務時,資料庫系統承諾的 ACIDity 是無法保障的。CAP 定理 意味著你需要在一致性(C)和可用性(A)之間做出權衡,因為分割槽容錯(P)在分散式系統中是無法指望的。在這篇部落格文章中,我們將探討針對這些挑戰和設計模式的解決方案。

1 協調服務間通訊

針對不同環境和目標的客戶和服務可以透過不同的機制來通訊。通訊可以是同步的或非同步的,具體取決於協議。

同步通訊——請求響應方法

在同步通訊中,需要一個預定義的源服務地址,指明請求要傳送到何處,並且 兩邊的服務 (呼叫方和被呼叫方)都應處於啟動和執行狀態。儘管協議可能是同步的,但 I/O 操作可以是非同步的,其中客戶端不必等待響應。這是 I/O 和協議 之間的區別。Web API 常見的通用請求 - 響應方法包括 REST、GraphQL 和 gRPC。

非同步通訊

在非同步通訊的情況下,呼叫方不必有被呼叫方的具體地址。這樣就可以相對容易地一次處理多個消費者(因為服務可能會增加消費者數量)。此外,如果接收服務關閉,訊息就會進入佇列,然後在接收服務開啟時繼續處理。從 鬆散耦合、多服務通訊以及應對部分伺服器故障 的角度來看,這尤其重要。正是這些決定性的因素讓 微服務傾向於非同步通訊 。諸如 MQTT、STOMP、AMQP 之類的非同步協議由 Apache Kafka Stream、RabbitMQ 之類的平臺處理。

瞭解何時何地使用同步模型與非同步模型,是設計高效微服務通訊機制時的基礎要素。

2 訊息與事件

在非同步通訊中,常見的機制是訊息傳遞和事件流。

訊息是傳送到特定目的地的資料專案,它封裝了 意圖 / 動作 (需要發生的事情),並透過訊息傳遞之類的渠道分發。佇列負責儲存訊息,直到它們得到處理和刪除。在訊息驅動的系統中,可定址的收件人等待訊息到達並做出響應,否則將處於休眠狀態。

事件封裝了狀態的變化(發生了什麼),而事件偵聽器會附加到事件源上,以便在事件發出時呼叫它們。

域事件:與應用程式生成的業務域相關的事件(下圖中的 OrderRequested、CreditReserved、InventoryReserved)。這些事件是事件源關注的。更改事件:從資料庫生成的事件,指示狀態轉換。這些事件是更改資料捕獲所關心的。

事件 streamer 是耐用的、持久的、容錯的,不受消費者干預。在這種情況下,處理器是 dumb 型別(從某種意義上說,它僅充當訊息路由器),並且客戶端 / 服務擁有以域為中心的,負責 轉儲處理器與活躍客戶端 的邏輯。這樣就避免了複雜的整合平臺,例如傳統 SOA 設計中使用的 ESB。

圖:微服務設計中的事件

3 微服務原理——智慧消費者與啞管道

微服務社群提出了智慧端點和啞管道的理念。Martin Fowler 是他稱為微服務通訊的智慧端點和啞管道的擁護者。統治 SOA 領域的 ESB 存在與複雜性、成本和故障排除相關的諸多問題。

4 非同步通訊協議

MQTT——訊息佇列遙測傳輸(MQTT)是一項基於釋出 / 訂閱的輕量級訊息傳遞協議 ISO 標準,已在物聯網中廣泛使用。AMQP——高階訊息佇列協議(AMQP)是一項開放標準應用程式層協議,用於面向訊息的中介軟體。STOMP——簡單文字定向訊息傳遞協議(STOMP)是 HTTP 上基於文字的協議,用於在服務之間交換資料。

5 通用訊息 / 流平臺

ActiveMQKafkaRabbitMQRedis Streams

評估標準的一些常見基準包括可用性、永續性 / 耐用性、耐用性、推 / 拉模型、可伸縮性和消費者能力。

6 微服務設計模式

微服務建立在獨立和自治服務、可伸縮性、低耦合 + 高內聚和容錯性等原則上。這些原則會帶來許多挑戰,包括複雜的管理和配置需求。微服務設計模式的目的是在給定的上下文中描述問題的可重用解決方案。我們將探討這些模式如何應對挑戰,以提供經過驗證的解決方案來打造更高效的微服務架構。

7 Saga 模式——跨多個服務維護原子性

單個事務可能會跨越多個服務。例如,在電子商務應用程式中,新訂單(與訂單服務連結)不應超過客戶信用額度(與客戶服務連結),並且貨品(與庫存服務連結)應處於可用狀態。這個事務根本不能使用本地 ACID 事務。

一個 saga 是一系列本地事務,這些事務可更新各個服務併發佈一個訊息 / 事件以觸發下一個本地事務。有任何本地事務失敗的情況下,saga 會執行一系列 補償事務 ,以回退先前的本地事務所做的更改,從而保持 原子性

基於編舞(Choreography)的 saga——參與者在沒有中心化控制點的情況下交換 事件 。基於編排的 saga——一箇中心化控制器告訴 saga 參與者要執行哪些本地事務。圖:編舞 / 編排的 saga

在這兩種模式之間具體選擇哪一種,取決於工作流程的複雜性、參與者數量、耦合水平以及其他因素。

兩階段提交

與 saga 類似,一個事務會分為兩個階段:準備和提交階段。在準備階段,要求所有參與者準備資料;在提交階段則進行實際更改。但是,由於同步存在副作用和效能問題,因此這種模式在微服務架構中被認為是行不通的。

事件源——面向狀態的永續性策略的替代方案

保持資料的傳統方法是更新已有資料來保持實體狀態的最新版本。假設,如果我們必須更改使用者實體的名稱,我們將使用新的使用者名稱來改變當前狀態。如果我們需要在任何時間點或一段時間上重建狀態該怎麼辦?在這種情況下,我們需要考慮這種永續性策略的替代方案。

與這種面向狀態的永續性相反,事件源將每個狀態突變儲存為一個單獨事件,而應用程式狀態則儲存為 不可變 事件的一個序列 / 日誌,而不是修改資料。透過有選擇地重播事件,我們可以隨時瞭解應用程式的狀態。應用程式在稱為事件儲存的僅附加事件日誌中保持資料。一個著名的例子是事務資料庫系統的事務日誌。

事件源基於三個服務層:

命令:由一個命令處理器處理的狀態更改請求。事件:狀態更改的不可變表示。聚合:域模型當前狀態的聚合表示。

事件源模式有很多優勢,包括提供準確的稽核日誌、重建任意時間點的狀態、方便的時間查詢、時間旅行、高效能和可伸縮性等。Netflix 透過事件源解決了離線下載功能需求。

CQRS——命令查詢職責隔離

如果我們將 CRUD 操作設計為可以用兩種獨立的讀寫模型來處理,會有什麼後果呢?它顯然增加了系統的複雜性,但收益是什麼?何時需要它?這種隔離增加了另一層可伸縮性、效能和靈活性,從而在處理複雜的域模型時實現精細的讀寫最佳化。

CQRS 將在應用程式中進行更改的模型 / 物件與讀取應用程式資料的模型 / 物件清楚地區分開。命令只是方法,其唯一目的是執行動作(建立、更新、刪除),並且可以被接受或拒絕,而不會暴露系統狀態。查詢是無需修改即可讀取系統狀態的方法。更進一步,我們可以引入一種保持同步的機制來拆分資料儲存的寫入部分和讀取部分(可以由多個數據庫管理)。

圖:具有相同和不同資料儲存的 CQRS

事件源和 CQRS

這些通常被稱為補充模式。

“沒有事件源的情況下也可以使用 CQRS,但有了事件源,你就必須使用 CQRS”——GregYoung,CQRS and Event Sourcing——Code on the Beach 2014。

如前所述,事件儲存由不可變事件的一個序列組成。通常,業務需求想要 執行復雜的查詢,而這些查詢無法由一個聚合響應 。每次都重播事件序列需要花費大量計算資源(並且在龐大的資料集中很難做到)。在這種情況下,隔離就會是有益的。

在下圖中,更新事件儲存的命令將釋出事件。查詢服務消費了更改日誌事件,併為將來的查詢建立一個預測。

圖:一個服務中的事件源和 CQRS

事務發件箱模式

在某些情況下,我們需要在資料庫中進行更新,經常還要在外部系統上呼叫另一個動作。例如,在電子商務應用程式中,我們需要儲存訂單並向客戶傳送電子郵件。如果其中一個事務失敗,就可能導致系統不一致。

在這種情況下, 發件箱(outbox)訊息中繼(message relay) 可以共同作用,可靠地保持狀態並呼叫其他動作。“ 發件箱 ”表位於服務的資料庫中。與主要更改(例如在訂單表中建立訂單)一起,代表事件(orderPlaced)的記錄也被引入同一資料庫事務中的發件箱表中。在非關係資料庫中,這通常是透過將事件儲存在文件內部來實現的。

圖:事務發件箱模式

更改資料捕獲(CDC)

應用程式狀態保留在資料庫中。更改資料捕獲(Change Data Capture)跟蹤一個源資料庫中的更改,並將這些更改轉發到預定目的地,以和相同的增量更改同步。CDC 可以是基於日誌的(事務資料庫將所有更改儲存在事務日誌中)或基於查詢的(定期用查詢檢查源資料庫,因為事務日誌可能在 Teradata 這樣的資料庫中不可用)。

下圖顯示了基於日誌的 CDC,用於捕獲發件箱表中的新條目(使用 Debezium connector for Postgres)並將它們流式傳輸到 Apache Kafka。事件捕獲發生時的開銷非常低,幾乎是實時的,並且這些事件是訂閱的目的地服務。

圖:事務發件箱與 CDC 使用 ApacheKafka

8 微服務設計注意事項

我們將簡要介紹設計微服務時需要的其他一些思想 / 原理。

冪等事務

冪等事務指的是發出多個相同請求的事務,這些事務具有與發出單個請求相同的效果。在 REST API 中,GET 方法是冪等的(可以反覆呼叫,結果與單次處理的結果是確定一致的),而 POST 方法不是冪等的(每個請求都會新增新專案)。

在分散式系統的上下文中,你不能實現訊息的精確一次傳遞。訊息代理(例如 Apache Kafka 或 RabbitMQ)實現了 至少一次傳遞 ,從而為同一事務帶來了多次呼叫的可能性。因此,在分散式系統中,消費者需要是冪等的。如果消費者不是冪等的,則多次呼叫可能導致錯誤和不一致。、

Airbnb 將一個名為“ Orpheus ”的 通用冪等庫 實現到了多個支付服務中,其中一個 冪等鍵 被傳遞到框架中,表示一個單獨的冪等請求。Paypal 使用 MsgSubId(訊息提交 ID)在 API 中實現了冪等性,而 Google Service Payment 使用 request ID 實現了冪等性。

最終一致性

在分散式系統中,一致性定義了對一個節點 / 服務的更新是否以及如何傳播到所有服務。最終一致性也稱為 樂觀複製 ,它只是一個宣告,表明將一臺計算機上所做的更改傳播到所有其他副本上的操作存在不受約束的延遲。

網路分割槽是分散式系統需要面對的一個現實,那就是網路可能會出故障。由於分割槽容限(P)是不可避免的,因此 CAP 定理要求你在一致性和可用性之間做出權衡。如果選擇可用性,就不能有很強的一致性,但你仍然可以在系統中提供最終一致性。

許多業務系統對資料不一致的容忍度比預期的要高。BASE(基本可用、軟狀態和最終一致性)系統優於 ACID 系統。

“對於分散式系統而言,保持強一致性非常困難,這意味著所有人都必須管理最終一致性。”——Martin Fowler

圖:分散式系統中的最終一致性

分散式跟蹤

在微服務中,與(可能跨越多個服務的)請求相關聯的元資料在很多場景中都能發揮作用:監視、日誌聚合、故障排除、延遲和效能最佳化、服務依賴分析,以及分散式上下文傳播。

分散式跟蹤是從頭到尾捕獲請求的 元資料 的過程,以將日誌記錄開銷保持在最低水平。一個 唯一事務 ID 被分配給外部請求,並透過分散式拓撲中各個事務的呼叫鏈傳遞,還包含在所有訊息中(包括時間戳和元資料)。

可以使用資料庫票證伺服器(由 Flickr 使用)、UUID 或 Twitter SnowFlake 生成唯一識別符號。常見的分散式跟蹤工具包括 OpenTracing、Jaeger、Zipkin 和 AppDash。

服務網格

微服務中的服務網格是處理程序間通訊的可配置網路基礎設施層。它和通常稱為 Sidecar 代理或 Sidecar 閘道器之的東西很像。它提供了以下功能:

負載均衡服務發現健康檢查安全性

Envoy 是專為雲原生應用程式設計的流行開源代理。Istio 是一個開放平臺,用於連線、管理和保護 Kubernetes 社群中流行的微服務。

原文連結:

https://medium.com/dev-genius/microservice-architecture-communication-design-patterns-70b37beec294

13
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • SpringBoot太強了、ShardingSphere上榜