面向資料的架構

charlieroro發表於2021-11-21

面向資料的架構

譯自:Data-Oriented Architecture

面向資料的架構

2007年,Rajive Joshi在RTI 白皮書中首次提出了面向資料的架構,後在2017年,Christian Vorhemus 和 Erich Schikuta 在維也納大學的這篇iiWAS論文中再次進行了闡述。DOA是對傳統二元架構(即一體式架構和微服務、面向服務的架構)進行翻轉的結果。在面向資料的架構中,一體式資料儲存是系統的唯一狀態源,作用於鬆耦合、無狀態微服務。

面向資料的構架並不是萬能的,它也有其成本和好處。但在現實中,很多大公司和生態系統都受困於一類瓶頸,而面向資料的構架正好可以解決這類瓶頸。

一體式架構

儘管很多架構的定義都會與一體式架構進行對比,但本質上,它們是服務側軟體開發的自然狀態

面向資料的架構

在一個一體式服務中,大量服務側程式碼會與一個或多個資料庫進行互動,並處理功能運算的方方面面。想象一個交易系統,它會接收使用者的請求,進行購買或出售證券,對其定價以及填寫訂單等。

在一體式服務中,程式碼仍然是元件化的,並劃分到不同的模組中,但程式的不同元件之間並沒有明確的API邊界。程式中唯一剛性定義的API通常是(a)UI和服務之間的互動協議(即是否使用了REST/HTTP協議);(b)服務和資料儲存使用的請求語言;(c)服務和外部依賴。

面向服務的架構和微服務

面向服務的架構(SOA)將一體式程式打散為功能獨立、元件化的服務。在我們的交易APP中,可能會使用一個獨立的服務作為對外API,接收請求並響應客戶,並使用另一個系統來接收定價和市場的其他資訊,再使用一個系統來跟蹤訂單和風險等。這些服務之間的介面是正式定義的API層,服務間通常會使用RPCs來一對一進行互動,其他系統也會使用如訊息傳遞和訂閱等方式。

面向資料的架構

面向服務的架構允許獨立(且並行)開發和實現不同的服務。服務間是鬆耦合的,這意味著一個新的服務可以重用其他服務。

由於SOA中的每個服務都有其各自的API,因此可以獨立與各個服務進行互動。開發者可以通過除錯和模擬不同的元件,將不同的服務重組成新的流程,進而表現出不同的行為。

微服務是面向服務架構的一種型別。取決於問問題的人,他們認為的微服務可能和SOA不同,可能僅僅指代一些小型且輕量的服務,也可能與SOA的意思完全一樣。

擴充套件問題

在SOA中,元件間通過特定的API進行互動。為了互動,每個元件需要可達,即使用IP地址、服務地址或其他內部標識來不斷髮送請求/訊息。這意味著架構中的每個元件必須要了解它的外部依賴,並與之整合到一起。

根據架構的拓撲,當需要新增新的元件時,需要了解前面所有的元件。意味著移除一個已經整合到架構中(以及與其他多個服務建立連線)的服務可能具有一定的挑戰:需要預留臨時定義的API,並制定一個遷移計劃來轉移各個元件(移除舊服務,並接入新服務)。由於服務到服務的API是特定的,這也意味著元件間的RPC可能會異常複雜,進而增加了未來可能變化的API的範圍。變更一個其他服務依賴的API將是一項艱鉅的任務。

隨著微服務的生態的增長,在進行擴充套件時,會對如下問題愈發敏感:

  1. 隨著元件數目的增加,整合複雜度為N2
  2. 難以根據經驗來理解網路結構,即建立或維護一個測試環境或沙箱將需要確保沒有外部依賴的元件。

一些SOA使用者反饋的問題如下:

  • 服務間的迴圈依賴:由於服務是滾動式釋出的,且無法在一開始就掌控整個系統,因此很容易引入迴圈並打破DAG
  • SOA擴充套件的另外一個問題是,它要求提前瞭解所有未來的客戶工作流。如果事先不知道,並在多個垂直維度上對資料進行隔離,那麼後續可能會面臨如何保證跨多個持久化儲存的事務處理效能,以及如何定義哪些儲存需要備份資料。

面向資料的架構

面向資料的架構(DOA)同SOA一樣,圍繞小的、鬆耦合的元件進行組織,但DOA使用兩種主要的方式來劃分微服務。

面向資料的架構
  1. 元件總是無狀態的

    相比為每個相關的元件建立元件化以及聯合的資料儲存,在管理全域性schema時,DOA託管描述資料或狀態層。

  2. 最小化元件間的互動,儘量通過資料層來互動。

    在我們的交易系統中,一個元件接收到不同證券的報價後,會以一種標準格式將報價釋出到我們的資料儲存中。一個系統可以通過資料層來請求並消費這些報價,而非通過特定服務的特定API來獲取。

    因此,整合成本是線性化的。一個DOA架構的變更可能設計N個元件的更新,而非N2個元件。

DOA架構真正的亮點在於,它允許不同的供應商釋出獨立的高層資料型別。如果我們移除了使用某個表的某個服務,那麼後續將不需要做其他變動,特別是當相同的資料型別有多個資料來源時。例如一個交易系統連線到多個市場,每個市場都會將客戶的請求釋出到一個RFQ表,後續下游系統就可以請求該表,而無需關心客戶請求來自哪裡。

元件通訊型別

由於DOA最小化了元件間的互動,那麼該如何使用資料層來移除SOA中的內部元件通訊?

1.資料生產和消費

將元件組織成生產者和消費者是一種主要的DOA系統設計方式。

如果方便的話,可以在上層使用一系列mapfilterreduceflatMap以及其他一元運算來組織業務邏輯,可以將DOA系統分解為一系列元件,每個元件會請求或訂閱業務邏輯輸入,併產生輸出。DOA的挑戰在於這些中間步驟都是可見的,這意味著請求的資料要求封裝良好、表現良好,且能夠對應到特定的業務邏輯。當然,好處是系統的行為是外部可觀察的,可追溯和可審計的。

在一個SOA交易系統中,一個元件接收到一個市場的訂單後,可能會通過RPCs來確定如何進行定價、報價和交易。在DOA中,一個微服務會從市場(通常以SOA的方式)接收請求,併產生RFQs,而其他生產者則產生定價等等。另外一個服務請求RFQs時,會聚合所有需要的定價、產品配額、訂單以及其他自定義響應資料需要的資料。

2.觸發動作和行為

有時,最簡單的元件間通訊方式是RPC,而設計周到的DOA系統可能會使用生產者/消費者模式來替換內部元件間的互動,但也可能會使用直接的方式來讓元件X通知元件Y執行動作Z。

首先,最重要的是考慮是否可以將RPCs重新組織為事件以及事件結果,即相比元件X通過RPCs通知元件Y哪裡發生了事件E,是否可以讓X產生事件E,然後讓元件Y通過消費這些事件來作出響應。

這種方式也被稱為基於資料的事件,跟我們通常使用的方式相反,但很強大。這種方式強大的原因是它升級了鬆耦合的概念。系統不需要了解誰會消費它們的事件(相反,RPC呼叫者需要明確知道正在呼叫的一方),且生產者不需要擔心事件是哪裡產生的,事件僅代表了業務邏輯。

實現基於資料的事件的一種不恰當的方式是將事件持久化到資料庫表中,資料庫表與序列化版本的RPC請求維持1:1的關係。這種情況下,基於資料的事件並不會與系統解耦。為了讓基於資料的事件正常運作,需要將一個請求/響應轉換為持久化的事件,但前提是這些請求/響應具有業務邏輯意義。

有時可能並不適用基於資料的事件。例如,如果想要觸發一個特定元件的行為,這類場景下可能會使用(有限的)元件間的RPCs方式。

面向資料架構的亮點

高整合問題空間

我一直提到交易/金融軟體的原因是它們的整合範圍通常會比較大。一個(允許使用者進行交易的)典型銷售端的公司,通常會整合很多市場來與使用者進行互動、以及其他流動性提供者來進行定價和下單。業務邏輯涉及到市場的請求以及返回給使用者的響應,是一個複雜、多階段的過程。

在一個高整合的問題空間中,一個服務可能需要了解很多其他服務。為了避免複雜度為O(N2)的整合成本以及服務的高扇出比率(一個服務對應多個服務),圍繞資料生產者和消費者來重新設計系統可以簡化整合度。在使用新的整合方式時,相比於修改N個新的系統,或將某個系統扇出到N個其他系統,新的整合過程只需編寫一個介面卡,將產生的資料儲存到通用的DOA schema中,消費最終的資料並以正確的格式進行呈現。

DOA中隱含了一種新的複雜性:資料schema。在整合新的服務時不需要對系統做大的變動,且在擴充套件架構時不需要新增新的中間層、方法或特殊的處理場景。因此資料schema的設計也是一個艱難的過程。但隨著整合複雜度的提升,分攤的難度反而會減少。

沙盒資料,以及對資料隔離的響應

如果你正在手動除錯或測試某些功能,可能會希望在生產之外的環境中做這些事情。然而某些SOA生態架構中經常很難區別哪些服務處理哪些環境以及哪些環境是自包含的。

一個環境是一個內部一致的、始終連線的服務的集合,通常(理想情況下)使用與生產相同的拓撲來組織這些服務。由於SOA服務通常是獨立定址的,環境的一致性要求每個服務與環境中呼叫的其他服務保持一致。RPC以及pubsub不能從一個環境洩露到另一個環境中。

SOA中有一些方法來避免發生上述問題,如使用服務註冊來為服務生成正確的配置,當使用URI訪問服務時,可以使用帶環境字首的不同地址來隱藏(直接的)服務地址。

在DOA中,環境的概念更加簡單。通過元件連線的儲存層就足以描述它所在的環境。由於所有元件儲存內部是無狀態的,資料通過定義進行隔離。由於元件間只會通過資料儲存進行通訊,因此環境之間不存在資料洩露的風險。

面向資料的架構比您想象的更近

現今有很多近似面向資料的架構的例子。一體式資料,即所有資料持久化到一個大型資料儲存的方式,通常透露出該系統的架構正在朝著DOA發展。

例如,知識圖譜是一個概括式的一體式資料,但往往不夠通用,缺少很多與業務邏輯有關的狀態。

與一體式資料類似,GraphQL通常作為範化資料儲存層。使用GraphQL作為DOA系統的後端的程度更多與系統架構設計的選擇有關:使用與業務邏輯概念相關的概括性架構和表,而非特定資料來源的架構和表。

權衡

該架構並不是萬能的。雖然面向資料的架構消除了很多問題,但也產生了新的問題:它需要設計者更多地關注資料所有者。例如,在處理多個編輯者同時修改相同記錄的情況時,通常對該記錄的寫所有權進行劃分。且由於資料中編碼了內部元件API,因此需要認真考慮共享的全域性schema。

提到Google的Protocol Buffers文件,其中有對schema中的欄位設定required時進行警告的討論:Required Is Forever。Broadway Technology的CTO Joshua Walsky 說過類似DOA schema的話:Data Is Forever。出於與Protobuf的告警類似的原因,從一個鬆耦合的分散式系統的表中移除一列是非常非常困難的。

總結

DOA其實是一種事件驅動架構的變種,服務(或元件)使用事件進行互動,而事件來源於資料,因此面向資料的架構準確地說是面向業務邏輯資料的架構,它將資料儲存作為整個架構的中心,服務之間通過資料儲存和訪問簡介進行互動。

使用DOA可以將SOA的整合複雜度從N2 降低到N,大大減低了服務的新增或移除對系統造成的影響。

但DOA也不是萬能的,它同樣帶來了新的複雜度,即資料schema設計上的複雜度。

與所有EDA相同,有些場景下並不適合使用DOA,特別是延遲敏感性服務,可能會導致響應不及時或影響QPS。

相關文章