0105-微服務的事件驅動的數據管理

微服務和分佈式數據管理問題

單片應用程序一般具備單個關係數據庫。使用關係數據庫的一個關鍵好處是您的應用程序可使用ACID事務,這提供了一些重要的保證:html

  • 原子性 - 變化是自動進行的
  • 一致性 - 數據庫的狀態始終保持一致
  • 隔離 - 即便交易是同時執行的,看起來它們是連續執行的
  • 耐久性 - 交易完成後,它不會被撤消

所以,您的應用程序能夠簡單地開始一個事務,更改(插入,更新和刪除)多行,並提交事務。nginx

使用關係數據庫的另外一個好處是它提供了SQL,它是一種豐富的,聲明式的,標準化的查詢語言。您能夠輕鬆編寫一個結合多個表中數據的查詢。RDBMS查詢規劃器而後肯定執行查詢的最佳方式。您沒必要擔憂底層細節,例如如何訪問數據庫。並且,由於全部應用程序的數據都在一個數據庫中,因此查詢起來很容易。git

不幸的是,當咱們轉向微服務架構時,數據訪問變得更加複雜。這是由於每一個微服務擁有的數據都是該微服務的私有數據而且只能經過其API訪問。封裝數據可確保微服務鬆散耦合,而且能夠相互獨立進化。若是多個服務訪問相同的數據,則模式更新須要耗時且協調地更新全部服務。github

更糟糕的是,不一樣的微服務一般使用不一樣類型的數據庫。現代應用程序存儲和處理各類數據和關係數據庫並不老是最好的選擇。對於某些用例,特定的NoSQL數據庫可能具備更方便的數據模型,並提供更好的性能和可伸縮性。例如,存儲和查詢文本以使用文本搜索引擎(如Elasticsearch)的服務是有意義的。一樣,存儲社交圖數據的服務可能應該使用圖形數據庫,例如Neo4j。所以,基於微服務的應用程序一般使用SQL和NoSQL數據庫的混合體,即所謂的多邊形持久性方法。數據庫

用於數據存儲的分區多邊形持久架構具備許多優勢,包括鬆散耦合的服務以及更好的性能和可伸縮性。可是,它確實引入了一些分佈式數據管理挑戰。編程

第一個挑戰是如何實如今多個服務之間保持一致性的業務事務。要明白爲何這是一個問題,咱們來看看一個在線B2B商店的例子。客戶服務部門保存有關客戶的信息,包括他們的信用額度。訂單服務管理訂單,而且必須驗證新訂單不超過客戶的信用額度。在此應用程序的單一版本中,訂單服務能夠簡單地使用ACID交易來檢查可用信用並建立訂單。架構

相反,在微服務架構中,ORDER和CUSTOMER表對於它們各自的服務是私有的,以下圖所示。併發

訂單服務沒法直接訪問CUSTOMER表。它只能使用客戶服務提供的API。訂單服務可能使用分佈式事務,也稱爲兩階段提交(2PC)。可是,2PC在現代應用中一般不是可行的選擇。該CAP定理須要你的可用性和ACID風格的一致性之間作出選擇,和可用性一般是更好的選擇。並且,許多現代技術(如大多數NoSQL數據庫)不支持2PC。在服務和數據庫之間保持數據一致性相當重要,因此咱們須要另外一種解決方案。分佈式

第二個挑戰是如何實現從多個服務中檢索數據的查詢。例如,讓咱們想象應用程序須要顯示一個客戶和他最近的訂單。若是訂單服務提供用於檢索客戶訂單的API,那麼您可使用應用程序端鏈接檢索這些數據。應用程序從客戶服務中檢索客戶,並從訂單服務中檢索客戶的訂單。可是,假設訂單服務僅支持經過主鍵查找訂單(也許它使用僅支持基於主鍵的檢索的NoSQL數據庫)。在這種狀況下,沒有明顯的方法來檢索所需的數據。ide

事件驅動架構

對於許多應用程序,解決方案是使用事件驅動的體系結構在這種體系結構中,微服務在發生顯着事件時發佈事件,例如更新業務實體時。其餘微服務訂閱這些事件。當微服務接收到事件時,它能夠更新本身的業務實體,這可能會致使發佈更多事件。

您可使用事件來實現跨多個服務的業務事務。交易由一系列步驟組成。每一個步驟都包含一個微服務,用於更新業務實體併發布觸發下一步的事件。如下圖表序列顯示如何在建立訂單時使用事件驅動方法來檢查可用信用。微服務經過Message Broker交換事件。

  1. 訂單服務建立一個狀態爲NEW的訂單併發布訂單建立事件。

  2. 客戶服務使用建立的訂單事件,爲訂單保留信用,併發布信用保留事件。

  3. 訂單服務使用信用保留事件,並將訂單狀態更改成OPEN。

更復雜的狀況可能涉及其餘步驟,例如在檢查客戶信用的同時預訂庫存。

(a)每一個服務自動更新數據庫併發佈一個事件 - 稍後再介紹 - 和(b)Message Broker保證事件至少被傳遞一次,而後您能夠實現跨越多個服務的業務事務。重要的是要注意這些不是ACID事務。它們提供了諸如最終一致性等更弱的保證這種交易模式被稱爲BASE模型

您還可使用事件來維護預加入多個微服務擁有的數據的物化視圖。維護視圖的服務訂閱相關事件並更新視圖。例如,維護客戶訂單視圖的客戶訂單視圖更新程序服務訂閱由客戶服務和訂單服務發佈的事件。

 

當客戶訂單視圖更新器服務收到客戶或訂單事件時,它會更新客戶訂單視圖數據存儲。您可使用文檔數據庫(如MongoDB)來實現客戶訂單視圖,併爲每一個客戶存儲一個文檔。客戶訂單視圖查詢服務經過查詢客戶訂單視圖數據庫來處理客戶和近期訂單的請求。

事件驅動的體系結構有幾個優勢和缺點。它能夠實現跨越多個服務的交易並提供最終的一致性。另外一個好處是它還使應用程序可以維護物化視圖。一個缺點是編程模型比使用ACID事務更復雜。一般您必須實施補償性事務才能從應用程序級別的故障中恢復; 例如,若是信用檢查失敗,您必須取消訂單。此外,應用程序還必須處理不一致的數據。這是由於機上交易所作的更改是可見的。若是應用程序從還沒有更新的實例化視圖中讀取,也可能會看到不一致。另外一個缺點是用戶必須檢測並忽略重複事件。

實現原子性

在事件驅動的體系結構中,還存在自動更新數據庫和發佈事件的問題。例如,訂單服務必須在ORDER表中插入一行併發布Order Created事件。這兩項操做是以原子方式完成的。若是服務在更新數據庫以後但在發佈事件以前崩潰,則系統變得不一致。確保原子性的標準方法是使用涉及數據庫和Message Broker的分佈式事務。可是,因爲上述緣由,例如CAP定理,這正是咱們不想作的。

使用本地事務發佈事件

實現原子性的一種方式是讓應用程序使用僅涉及本地事務多步處理來發布事件訣竅是在存儲業務實體狀態的數據庫中有一個用做消息隊列的EVENT表。應用程序開始一個(本地)數據庫事務,更新業務實體的狀態,將事件插入EVENT表並提交事務。單獨的應用程序線程或進程查詢EVENT表,將事件發佈到Message Broker,而後使用本地事務將事件標記爲已發佈。下圖顯示了設計。

訂單服務將一行插入到ORDER表中,並將一個Order Created事件插入到EVENT表中。Event Publisher線程或進程查詢EVENT表以查找未發佈的事件,發佈事件,而後更新EVENT表以將事件標記爲已發佈。

這種方法有幾個好處和缺點。其中一個好處是它保證每次更新都會發佈一個事件,而不依賴於2PC。另外,應用程序發佈業務級別的事件,這消除了推斷它們的須要。這種方法的一個缺點是它有潛在的錯誤傾向,由於開發者必須記得發佈事件。這種方法的侷限性在於,因爲它們的事務和查詢能力有限,所以使用某些NoSQL數據庫時實施具備挑戰性。

這種方法經過讓應用程序使用本地事務來更新狀態和發佈事件來消除對2PC的需求。如今讓咱們看看經過讓應用程序簡單更新狀態來實現原子性的方法。

挖掘數據庫事務日誌

在不使用2PC的狀況下實現原子性的另外一種方式是事件由線程或進程發佈,該線程或進程挖掘數據庫的事務或提交日誌。應用程序更新數據庫,致使數據庫的事務日誌中記錄更改。事務日誌挖掘程序線程或進程讀取事務日誌並將事件發佈到Message Broker。下圖顯示了設計。

這種方法的一個例子是開源的LinkedIn Databus項目。Databus挖掘Oracle事務日誌併發布與更改相對應的事件。LinkedIn使用Databus來保持各類衍生數據存儲與記錄系統一致。

另外一個示例是AWS DynamoDB中流機制,它是託管的NoSQL數據庫。DynamoDB流包含在過去24小時內對DynamoDB表中的項目進行的按時間排序的更改(建立,更新和刪除操做)。應用程序能夠從流中讀取這些更改,並將其做爲事件發佈。

事務日誌挖掘具備各類優勢和缺點。其中一個好處是它能夠保證每次更新都會發佈一個事件,而不使用2PC。事務日誌挖掘還能夠經過從應用程序的業務邏輯中分離事件發佈來簡化應用程序。一個主要缺點是事務日誌的格式是每一個數據庫專有的,甚至可能在數據庫版本之間改變。此外,從事務日誌中記錄的低級更新對高級業務事件進行反向工程很難。

事務日誌挖掘經過讓應用程序執行一件事來消除對2PC的須要:更新數據庫。如今讓咱們看看消除更新並僅依賴於事件的不一樣方法。

使用事件採購

事件採購經過使用徹底不一樣的,以事件爲中心的方法來持久化商業實體,從而在沒有2PC的狀況下實現原子性。應用程序不是存儲實體的當前狀態,而是存儲一系列狀態改變事件。應用程序經過重播事件來重建實體的當前狀態。每當業務實體的狀態發生變化時,新事件將附加到事件列表中。因爲保存一個事件是一個單獨的操做,它本質上是原子的。

要了解事件採購如何工做,請考慮訂單實體做爲示例。在傳統方法中,每一個訂單映射到ORDER表中的一行以及ORDER_LINE_ITEM表中的行。可是在使用事件採購時,訂單服務以狀態變化事件的形式存儲訂單:建立,批准,發貨,取消。每一個事件都包含足夠的數據來重建訂單的狀態。

事件存儲在事件存儲中,事件存儲是一個事件數據庫。該商店有一個用於添加和檢索實體事件的API。Event Store的行爲與咱們前面介紹的體系結構中的Message Broker類似。它提供了一個API,使服務可以訂閱事件。活動商店將全部活動提供給全部感興趣的訂戶。Event Store是事件驅動的微服務架構的中堅力量。

事件採購有幾個好處。它解決了實現事件驅動體系結構的關鍵問題之一,而且能夠在狀態發生變化時可靠地發佈事件。所以,它解決了微服務架構中的數據一致性問題。並且,由於它堅持事件而不是域對象,因此它大多避免了對象 - 關係阻抗不匹配問題事件採購還提供了對業務實體所作更改的100%可靠審計日誌,而且能夠實如今任什麼時候間點肯定實體狀態的臨時查詢。事件採購的另外一個主要優點是您的業務邏輯由交換事件的鬆散耦合的業務實體組成。這使得從單一應用程序遷移到微服務體系結構變得更加容易。

事件採購也有一些缺點。這是一種不一樣的,不熟悉的編程風格,因此有一條學習曲線。事件存儲只能直接支持經過主鍵查找業務實體。您必須使用命令查詢責任隔離(CQRS)來實施查詢。所以,應用程序必須處理最終一致的數據。

概要

在微服務架構中,每一個微服務都有本身的私有數據存儲。不一樣的微服務可能使用不一樣的SQL和NoSQL數據庫。雖然這種數據庫體系結構具備顯着的優點,但卻形成了一些分佈式數據管理挑戰 第一個挑戰是如何實如今多個服務之間保持一致性的業務事務。第二個挑戰是如何實現從多個服務中檢索數據的查詢。

對於許多應用程序,解決方案是使用事件驅動的體系結構。實現事件驅動架構的一個挑戰是如何自動更新狀態以及如何發佈事件。有幾種方法能夠實現這一點,包括將數據庫用做消息隊列,事務日誌挖掘和事件源。

原文地址:https://www.nginx.com/blog/event-driven-data-management-microservices/

相關文章
相關標籤/搜索