在前面幾篇,我們討論了幾個「拆分應用程式的做法」,這如先前所說,微服務的拆分中,有一個很麻煩的議題,就是資料庫的拆分 (不是只有技術問題,可能還有軟體授權問題)。為了讓遷移到微服務的過程能夠獲得最大的效益,我們需要思考將原本既有系統資料庫進行拆分的做法。
這是為了讓每個「服務」可以獨立的運作,獨立的開發,獨立的部署。所以,唯有讓每個資料庫擁有自己的「自治權」,這個假設才能夠成立。
(曾經有客戶問我說,當我們切完微服務後,我同時有兩個團隊在修改同一個服務,彼此造成的干擾怎麼處理?)
這時候,只好再給一條限制,一個服務只會有一個團隊負責 (這樣就沒有兩個團隊修改同一個服務的問題,回答不了問題就讓問題不存在!)。
要將一個既有系統的「資料庫」拆分實在是不容易的工作事項,在這個過程中,我們需要考量「移轉過程中的資料同步」、「邏輯與物理分解」、「交易完整性」以及「延遲」等問題。
移轉過程中的資料同步:系統持續在線上,業務持續在營運,所以為了讓新的微服務與既有系統能夠無縫的銜接,所以必須設計一個可以接軌的「資料同步機制」
邏輯與物理分解:我們並沒有無限的鈔能力,我服務的客戶很多使用的資料庫又都是商業授權版本。所以,物理的分割將造成「無限的授權」費用上升。邏輯分解,則可以拆分成不同 Instance \ Schema 等,但邏輯的分割 (特別是 Schema) 的模式,我們往往會忍不住誘惑打破這個限制。
交易完整性:有時候,你會碰到一個尷尬的狀態,例如:你實作一個下單微服務,但是你必須跟庫存微服務確認還有庫存後才能真的完成下單作業。在過去,我們可以透過資料庫實現交易的保護來確保這件事情沒有錯誤。
延遲:微服務的資料特性是「最終一致」,與同一個資料庫中的「交易保護」不同,所以在分拆資料庫後,為了保持整體業務的一致性可能需要額外付出很多代價 (Saga、Event Sourcing 等模式就因此而生)。
如下圖所示,Database per Service 可能會衍伸的議題與解決方案(API Composition、CQRS及Saga 等),相對之下 Shared database 真的是輕鬆多了!(所以,沒事真的不要微服務,先想清楚自己的目標,再來執行這件事。)
所以,很多人做到應用程式的分拆後,就不想再面對「資料庫分拆」的工作。但,在這裡我想分享的一個觀點是,微服務的移轉是一個「漸進」的過程,如同先前討論「絞殺榕模式」一般,將「共享資料庫」視為這個過渡的過程也不需要覺得這樣不能上線。畢竟,在瓶頸真的落到「資料庫」之前,效果基本上是相同的 (至少,在調整前他就是這樣工作!)。
既然,「共享資料庫」這個反模式在系統轉型的過程中是一個會存在的過程(大部分會在這個狀態停留很長一段時間),那麼我們就來檢視一下,共享資料庫的施作可能遇到的問題:
讓多個服務共享一個資料庫,最大的問題就是我們無法知道其他服務需要這個資料庫的哪些內容。這樣的處理模式違反了我們在開發程式時經常提到的「封裝 (information hiding)」的特性,最終就很容易發生哪些改東壞西的情境。
因為應用程式之間彼此綑綁在一起,所以就很難做到「獨立、自治」的需求 (也就是無法管理)。我們無法知道哪個模組在「控制」資料,也無法清楚地指出「操作資料」的業務邏輯撰寫在哪個模組之中。
所以,在微服務中「共享資料庫」一直被視為反模式,但是在特定的時空背景下,我們又不得不接受這個概念 (有時候,你有千千萬萬個理由讓每個服務不能有自己的資料庫,比如說我沒錢再買資料庫的授權 …)。所以,最小可以接受的狀態是模組化並且在資料層做到邏輯隔離的狀態。
除了,上述的那些藉口之外,有沒有真的適用「共享資料庫」的情境?如果是下列種案例,或許直接採用「共享資料庫」並不是一個壞事。
在實際的案例中,有客戶存在那種「代碼」對應「名稱」的相關資料表,每個系統可能都會需要用的參照資料,對大多數的系統來說,它就是一個「唯讀的靜態參考資料」,這時候「共用」也不太會破壞整體的可維護性。
當多個微服務存取同一個資料庫是合理的,那麼將本來要直接存取資料庫的動作包裝成一個獨立的服務,或許是一種解決方案。
在實際的專案經驗上,我目前正在思考一件事,就是作為「批次報表」系統很多時候會需要跨多個「微服務」之間的資料,這時候建置一個類似資料倉儲的資料庫來收攏這些產製報表時需要的資料可能也是「共享資料庫」使用的一個方式 (或者,這就是既有系統資料庫存在的模式)。
我們希望新的服務具有獨立的運作模式,但這不代表所有的系統都需要做上極致的微服務。畢竟,微服務是手段而不是目標。很多時候,我們會在將資料分隔出去後才順道的將資料自治權拆分出去,所以新的服務可能有獨立的資料庫,但既有系統我們可能就不會強求分割了。
正如先前所述,微服務的移轉過程可能涉及一段相當長的施工時間,也可能在過程中遭遇系統或是業務的變遷而使我們變更事情處理的順序,在這些情況下「妥協」也是一種藝術。