CQRS 的神奇把戲:微服務資料解耦

以快速實現 Open API 需求為例

Fred Chien(錢逢祥)
Brobridge - 寬橋微服務
10 min readMay 4, 2020

--

Photo by Tobias Fischer on Unsplash

除非你的應用程式,是無資料需求或是資料不落地的樣態(可參考舊文:「三種不同實現難度的微服務應用」),否則資料解耦是無法忽略的終極議題。由於所有應用都依賴著資料去支撐,資料的管理、拆分、解耦問題,就變得極為重要,錯誤的資料拆分或沒有實現資料解耦,都會導致微服務架構無法實現。

事實上,如果你能熟悉如何應用 CQRS 模式,就算不重構資料,其實也可以達成某程度上的資料解耦目標。即便是使用在非微服務架構的應用,善用 CQRS 也能得到許多好處。

對於不暸解為什麼要做資料解耦,以及不知道怎麼做的人。本文將藉由服務拆分探討在資料解耦上遭遇的問題,最後並以 Open API 為例子說明 CQRS 的實務應用方法。

一個應用的組成和拆分解耦

一個應用的組成,通常主要分為「商業邏輯(Bussiness Logic)」和「資料(Data)」兩個部分,缺一不可。我們在進行微服務的拆分工作時,將這兩個部分切開是一個要達成的目標。

相對來說,邏輯與功能面的拆分比資料去耦合來得容易,簡單的實作甚至只需要在程式碼上動動手腳便能達成,最難也不過是對業務進行梳理工作,甚至是導入領域驅動設計(DDD, Domain-Driven Design) 就能完成。

但是資料層面的拆分和去耦合就沒這容易,要考慮的除了有結構的複雜度問題,還有系統效能的問題,不是說要拆、要重構就能動手。在實務上,拆分舊有系統時如果更動到資料結構,伴隨而來的還有許多風險和資料管理問題。

所以,多半的企業都會對資料去耦合的問題,再三評估討論,甚至放棄這項工作都不在少數。以致執行服務拆分時,錯將主要重點只放在邏輯業務的拆分。

只拆分邏輯會發生什麼事?

如圖所示,過去在三層式或 n-tier 架構下,我們已經體驗了許多共用資料庫系統的痛苦,也面對了物理極限的困擾。若只拆分邏輯,首先會受到衝擊的是資料庫系統,如果服務之間的資料交換,是透過單一資料庫進行,資料庫的效能會是整個應用程式的瓶頸,未來也難以隨業務需求而橫向擴展。

若只拆分邏輯,除了程式碼實體分開以外,從架構面來看,本質上與不拆分沒有太大不同,反而還多了更多管理、部署以及網路連線的成本和風險。

共用資料庫意味著你將資料庫獨立出來成一個服務,用於供應資料其他服務使用。如果我們將這個服務視為一個物件,其擁有狀態、屬性等資料,其價值也主要是來自狀態和屬性等資訊,就會發現,這直接牴觸了大師級架構師 Martin Fowler 提出的「分散式物件設計第一定律 — Don’t distribute your objects」。

註:Martin Fowler 是企業架構師必看之經典「Patterns of Enterprise Application Architecture 」一書的作者。

高風險資料結構拆分之真正目的

在微服務架構的建議下,資料私有化(Database per service)是最理想的狀態。但如果要照表面上的意義,實現資料拆解,這也意味著對於拆解舊系統而言,是一件非常大的工程,也要冒非常大的風險,這是所有企業都無法忍受的艱難問題。

但是,我們目標是資料解耦,有必要一定得冒極大風險重構資料嗎?

從業務功能角度來看,其實所有資料都有其對應的擁有者,其他業務對該資料的需求,多半是查詢以及「資訊的提取」,而不負責管理。所以通常在微服務拆分的設計上,任何資料一定會有專責的服務來處理變更管理。

說穿了,資料結構拆分的目的,就是「整理並確定資料的歸屬權」,資料分割並反而不是重點。當我們確定了資料的歸屬權,才不會有多頭馬車的問題,在其對應的服務上,也才會有辦法妥善實作資料管理的方法和架構。

所以,如果你無法對既有資料庫和資料結構進行變更,並不代表你就可以不做資料解耦,先搞清楚每筆資料、每個欄位的資料歸屬權,以及其對應的服務,才是你要做的事。

服務間一定有資料分享的需求

試想,若進行拆解資料後仍然要處理資料分享的議題,而且會造成服務之間呼叫過於頻繁甚至嚴重影響網絡或系統運作,那又何必拆呢?可是如果不拆,又會掉回老架構的圈圈,無法真正實現微服務架構。

到底資料結構拆與不拆,怎麼選擇?

事實上,無論你拆與不拆資料,你的服務之間一定有資料分享的需求,逃不掉也躲不掉。如果你不管怎麼選擇,都要解決資料共享問題,這代表,處理「資料共享需求」才是資料解耦的主要任務,而不是重構或實體拆分資料了。

資料解耦的真正目標

其實資料解耦的目標,是要解決兩個業務領域的資料重疊處,因為兩個領域有相關聯的資料需要共享,所以怎麼讓外部服務能取得所需資訊,以滿足業務需求,又不至於過度影響系統既有效能,就是其中最主要的議題。

導入 CQRS 進行資料解耦

為了滿足資料共享的需求,又不衝擊系統效能。在微服務架構中,就會建議以 CQRS 模式來解決這個問題。利用 CQRS 將查詢操作分離出來,無需整個資料集複製,而是提取其中一部分、另一個業務邏輯所需的資料,並進行快取設計。

提取出來的資料,此時歸屬權已經改變,不屬於原本的服務,而是由另一個服務擁有。若有需要,也可以對提取出來的資料,結合資料管線的設計,進一步做加工處理,生成一份新的資料供業務需求使用。

藉由這樣分散式系統常見的「重複大於重用」原則,減少對既有系統的衝擊,讓資料的讀取和查詢效率提升,是 CQRS 在這種情境下的用途。

關於更多 CQRS 的說明和介紹,可以參考舊文「淺談 CQRS 的實現方法」。

如何快速實現 Open API 需求

引入 CQRS 實作不衝擊既有系統效能,又兼具安全隔離性的 Open API

討論了這麼多資料解耦的重要性,以及如何運用 CQRS 解決其相關問題,那麼在實務上,我們究竟可以在哪些應用或需求中導入 CQRS 呢?其實,對外開放的 Open API 就是一個最好的導入場域,完全可以利用 CQRS 機制的優點來實現或改善。

由於大多數的 Open API 都是以查詢為主,主要對外開放給第三方服務、應用程式所使用。與過去關起來開發的情境不同,開放允許來存取 Open API 的都是外部服務,這些外部服務多半都不在我們的控制範圍,所以也通常比較難預估 API 的使用狀況。這樣的情況,對 API 的設計和維運控管上,通常需要更加注意。

一般來說,我們考量 Open API 的設計時,大概圍繞在三個重點上:

  1. 【安全及管理
    對許多企業來說,直接接上既有系統,可能會導致許多安全疑慮。新舊系統橋接,也會有更多組織、管理層面的議題會存在。
  2. 【系統效能、穩定性與擴展性
    由於對外開放的 API,無法準確預估實際上有多少外部的系統、多少的查詢需求。甚至,因應特殊節日、狀況,導致的流量劇增問題,都可能是麻煩之一。所以設計上,我們會要求盡量提升 API 的吞吐量,並試著讓它保持橫向擴展的彈性,以滿足未來需求增加的可能。
  3. 【舊有系統的影響
    因為 Open API 的資料來源都來自既有系統,這對既有系統來說是一個衝擊,大量的存取要求會長驅直入,直接影響既有系統、以及相關的業務效能和運作。

這些因素,都導致我們在設計 Open API 以及部署維運上,會有很多麻煩。倒底我們該如何滿足這些考量,並快速實作出具擴展彈性的 Open API 呢?

如圖裡的例子所示,如果有一個 Open API 是要取得某年齡層、某性別的平均收入的查詢資料,可以想像,光是關聯式查詢造成的既有資料庫衝擊,就非常嚇人。

但如果引入 CQRS 和事件化設計,對需求欄位及資料進行提取、聚合(Aggregate)和快取,最後實現實體分離,儲存資料在舊有系統之外,就可以在不影響既有系統運作的前提之下,滿足外部大量查詢的需求。這種 CQRS 的使用方式,即為多視圖(Multiple Views)的方法,是微服務架構下相當常見的設計。

更棒的是,在進行資料提取的過程中,甚至可以實現去敏感資料的機制,使外放的資料,有絕對安全的隱私資料保護。

在這種架構下,Open API 的設計和維護也相對單純,只要選擇需要從源頭提取的資料,實現資料解耦,存入自己的資料庫系統。然後再查詢自己擁有的資料庫即可滿足查詢需求,重點是,因為提前資料解耦和關聯,再也無需使用太過複雜的關聯式查詢,以提升查詢效能。未來若吞吐量需求增加,也只需要對資料庫或服務本身進行橫向擴展即可,與舊系統無關、不影響舊有系統。

此外,除了從事件中進行資料提取的工作外,服務本身基本上可以完全獨立運作,又因為沒有其他方式可以連回既有系統,可以與舊系統最大程度脫鉤並保持距離。甚至可以將服務放在公有雲或其他資料中心,實現混合雲的架構。

實作 CQRS 困難嗎?有開箱即用的解決方案嗎?

自行實作 CQRS 於採用既有解決方案(Gravity) 的比較

實作 CQRS 並不困難,只是需要處理的議題相當多。極簡的做法誰都能隨手設計出來,但到要考量資料完整性、快速復原等需求,以及客制和部署維運的問題,就是一件會極為麻煩、讓開發人員頭痛的事。沒有妥當設計,甚至會造成另一個大型單體式應用程式的誕生,也不是不可能,需要小心謹慎。

這也是為什麼,我們寬橋(Brobridge)提供了「開箱即用的 CQRS 解決方案 — Gravity」,使客戶專心在服務拆分,以及自家商業邏輯的實作,無需擔心資料解耦的問題。

如果你對如何實現 CQRS 的議題有極大興趣,也可以閱讀舊文「應用層 CQRS 的實現與困難」,其中會討論 CQRS 各種實務上可能會遇到的需求和實現細節。

本文資料,來源皆參考自 寬橋(Brobridge) 的微服務架構設計教育訓練課程,如果想要暸解更多關於微服務架構設計的議題,可以與我們聯絡。若對 CQRS 解決方案 Brobridge Gravity 及其資料解耦的議題感興趣,也歡迎與我們接洽。

開箱即用,資料解耦的微服務解決方案

--

--