遠離錯誤的微服務資料庫架構設計

落實微服務的資料庫私有化(Database per service)

Fred Chien(錢逢祥)
Brobridge - 寬橋微服務
8 min readJul 25, 2020

--

Photo by Alexandre Debiève on Unsplash

坊間討論微服務的文章和演講相當多,到處都在強調微服務必須實現「資料庫私有化(Database per service)」,甚至有文章直接講類似的話:

「如果你正在使用共享資料庫,那你可能沒有把微服務做對。」

資料庫架構設計議題,對於微服務架構來說非常重要,錯誤的設計會導致錯誤的微服務架構,最終得到滿是問題的結果,甚至比不採用微服務架構之前還要糟糕。這幾乎已經是業界的共識,如果你不理解資料如何解耦,如何實現微服務的私有化資料庫(Database per service),建議千萬別輕舉妄動。

循序漸進落實資料庫架構改造

不可否認,而這個議題,一直是微服務中最讓人頭痛的地方。由於應用開發人員太習慣三層式架構的設計,以致總是將資料庫的所有問題,全部都交給傳統的資料庫系統解決方案處理。因此,開發人員對於資料庫架構的設計往往很陌生,甚至害怕去面對。

但是,避開資料庫架構的設計議題,絕對是錯誤的選擇。

的確要設計一個完整的資料庫系統,非常具有難度,也不是一般人可以勝任的工作。對於應用程式開發者來說,討論一個過於理論的底層技術,也並不現實。所以在導入微服務架構時,我們通常也不打算討論太底層的資料庫系統實作議題,而重點會放在應用層面的資料流、資料處理架構。

事實上,微服務的資料解耦、資料庫架構設計並不是一件難事,雖然看似工作繁瑣,但都有道理可循,看似風險很高,卻有方法可以循序漸進。

為什麼不懂處理資料庫議題就做不成微服務?

微服務架構的設計上,通常是圍繞在應用業務的需求上,而這些應用需要妥善的「資料供應和管理」來支撐其運作。如果不懂得解耦資料、處理相關資料庫議題,這代表可能沒有完全搞清楚業務的需求,更代表著沒有完全處理好業務邏輯的解耦和拆分。在這種情況下所設計出來的微服務,肯定是有極大問題存在。

的確,資料層的拆分問題相當麻煩且不易,除了對既有系統進行拆分有巨大風險外,即使重新設計一個全新的系統,亦難以直觀地去設計資料架構,並考量完整的維運策略。

有鑑於此,這導致很多人會取巧以避免資料層的設計,甚至刻意忽略這段工作。不過要注意的是,若只處理商業邏輯層面的服務拆分,而不處理資料分享的問題,這樣所設計出來的架構,除了對開發分工管理的部分有幫助外,對整體系統效能改善是沒有太大的幫助,多半可能還傷害並降低系統整體表現,也同時增加了系統複雜度。

只做了一半的業務拆分工作,本質上並沒有實現微服務的分散式架構想法,不會在系統表現上獲得好處,而且會承攬許多微服務架構所帶來的缺點,例如延遲性、複雜度以及增加資料庫的負擔等。所以,除非系統本來的用量不高,不然這樣半吊子的實作,會帶來更大的麻煩,還不如不要拆分太深,選擇傳統 SOA 的做法就好。

關於更多資料解耦如何影響微服務架構設計的議題,可以參考舊文「為什麼導入微服務架構很容易撞牆?」和「CQRS 的神奇把戲:微服務資料解耦」。

實現資料庫私有化(Database per service)

在微服務架構下,有一個資料庫私有化(Database per service)的設計模式,顧名思義,指的是每個服務擁有自己的資料庫。為了保持服務之間低耦合及具隔離性的設計,我們會避免資料庫共享的情形,所以設計上會讓服務擁有自己的資料庫。由於資料庫只能被擁有者所存取,其他外部的服務或系統,只能透過擁有者所提供的 API 來存取該資料庫的資料。

表面上,實現資料庫私有化,是為服務配置屬於自己的資料庫。但實際上,其意義是為了進行資料解耦的工作,確認資料歸屬。一旦實現資料庫私有化,這代表服務真正的被拆分和獨立運作,滿足微服務架構的需要。

拆既有資料庫風險很高,如何解決?

資料解耦才是微服務資料庫議題的核心,而資料解耦的意義在於確認資料的歸屬,然後圍繞在資料擁有者(服務)的身上,發展出應用和功能。所以,當我們確認了資料歸屬,首先要確定這個資料的擁有者(服務),在使用這個資料時,不會衝擊原有的資料庫的效能,也不會大幅增加其管理的難度。

這時,善用 防腐層設計模式(Anti-Corruption Layer Pattern)來處理這個問題,就是很好的手段。簡單來說,可以利用 CQRS (Command and Query Responsibility Segregation)將服務所擁有的資料,從原有的資料庫系統抽取出來,然後建立一個新的獨立資料庫作為過渡,以滿足資料庫私有化的需求。

雖然這樣做,身為該資料擁有者的服務還不能全權掌控資料,但某程度來說微服務的資料庫架構基礎已經成形,至少,未來不管從哪來的需求,如果要存取這些資料,一定要透過這個身為資料擁有者的服務來進行。

註:防腐層設計模式(Anti-Corruption Layer Pattern)是 Eric Evans 於領域驅動設計中(Domain-Driven Design)所提及的設計模式。

如何看待並導入 CQRS?

在微服務架構設計中,CQRS 被用來解耦資料庫結構並滿足資料一致性,實際上在採用 CQRS 時,需要結合應用的功能設計,才能發揮最大的效用,甚至實現資料和資料歸屬的實體隔離。

若要討論 CQRS 實務上的規劃,花三天三夜也討論不完,這是一個永遠會因應業務需求而不斷調整的議題,所以,針對當下需求去使用 CQRS,並選擇一個能保留彈性的設計,是最優先的考量。

對於初入微服務架構的人,或是希望導入微服務技術來逐漸改善既有系統的企業,可以先嘗試運用 CQRS 來實現「資料庫快取(Cache)」,將部分業務跟原始資料庫進行隔離,並利用快取設計,提高系統的查詢效率。很多企業早已經導入 CDC 或 Replication 等抄寫和讀寫分離解決方案,某種程度上,已經算是實現初步的快取機制。

對於已經很熟悉或是很習慣快取資料庫存在的人,則開始要考慮「規模化的快取」,也就是能快速建置快取資料庫、依照不同需求實現「多視圖(Multiple Views)」的機制。換句話說,就是考量業務需求與系統效能的平衡,去設計各式各樣的快取機制,並能夠快速擴增以滿足未來不斷新增的業務。

到這個階段,逐步或全面引用事件驅動架構(EDA, Event-driven Architecture)來設計資料管線(Data pipeline),會是最主要的工作。

落實應用層交易機制

可以說,交易機制是將所有資料綁死在單一資料庫的關鍵,之所以資料難以解耦,很大一部分是因為要遷就交易機制在單一資料庫內執行。如果能使交易機制,從資料庫系統脫離後在應用層落實,就可以讓資料解耦的工作進展一大步。

這同時也是為什麼,很多人在導入微服務時,會覺得微服務複雜又沒有實際效益。因為許多人考量到交易機制離開了資料庫系統後,就不容易實現,所以仍然把有相關聯、有相互間交易同步需求的資料都放在同一座資料庫裡。這導致實際上的資料和業務並沒有隔離,對系統效能影響最大的關鍵仍然沒有改變。

在這種情況下,資料和交易機制沒有解耦,只會創造出更多的空殼服務和邏輯,伴隨著更複雜的系統架構加上效能低落的資料庫系統,只有壞處沒有好處。因此,應用層交易機制,便是在處理「資料快取」和「資料中繼」後,首要解決的最大議題。

若對於微服務交易機制的實現,可參考舊文「淺談微服務架構交易機制實現」。

強烈不推薦直接打掉重練

很多人學會了領域驅動設計(Domain-Driven Design),開始懂得切割和劃分服務、系統,於是想試圖大刀闊斧進行改革。但這其實是很危險的事,如果不熟悉各種資料一致性、資料解耦的技術,一次導入太多、太少、或是選擇錯誤,只會造成更大的麻煩。不但系統的開發方向不會朝一開始的設計前進,甚至可能左支右絀,與其背道而馳。

所以在導入微服務技術時,通常並不推薦推翻重練的形式來滿足新的架構,而是針對痛點、特定功能、特定服務,以「優化」的方式進行。所以在實務導入時,也要從最不影響系統運作的地方著手。

即便是實現一個新的應用、服務,在沒有包袱的情況下,建議也是要先對資料處理架構進行全面的思考和設計,再來進行。若實在陌生,可以參考本文前面章節,從資料快取、歸屬權等角度逐步引入設計,然後再來討論應用層的交易機制。

本文資料,來源皆參考自 寬橋(Brobridge) 的微服務架構設計教育訓練課程,想要暸解更多關於微服務架構設計的議題,可以與我們聯絡。如果您想要導入「資料快取平台」,為您的微服務導入之路打下堅實基礎,也為未來的「數據中台」和「資料中繼平台」做好準備,歡迎與我們洽詢。

--

--