Microservices流言大解密 ?

Z-xuan Hong
10 min readDec 12, 2020

--

Microservices(微服務)這個詞,相信大家多少都有聽過,但它代表什麼含義?有人說Domain Driven Design (DDD)就是Microservices,有人說使用Docker執行應用程式就是Microservices,有人說Service Oriented Architecture (SOA)就是Microservices。

眾說紛紜到底哪個是對的?希望本篇文章,能夠幫大家解決以下困惑:

  1. Microservices的定義、優缺點、使用時機
  2. 真Microservices vs 假Microservices
  3. SOA與Microservices之間的關係
  4. DDD與Microservices之間的關係
  5. Docker與Microservices之間的關係

Microservice的定義、優缺點、使用時機

在介紹Microservices之前,我們要先知道為什麼有Microservices的出現。

傳統開發應用程式的方式,我們會使用OOAD等技術建立一個Domain Model (希望你公司有,沒有的話請趕快逃),而整個應用程式圍繞此Domain Model進行開發,在OOAD被發明的年代,不需要太多的Scale、複雜度相較於現在也小非常多,進入到巨量資料時代後,隨著使用者急速暴增、應用程式的複雜指數增加,光靠一個Domain Model開發會導致以下問題:

  1. 僅透過單一Domain Model抽象化非常複雜的應用程式是不夠的,借用韓導的一句話:我談的是大海(複雜的應用程式),你跟我講漱口杯(單一Domain Model)
  2. 使用者個急速暴增,我們需要High Transaction應用程式來處理大量的Request,但在複雜的應用程式內,不同區塊需要Scale的程度不同,如果使用單一Domain Model無法達到個別優化的效果(Independent Optimization)。
  3. 單一Domain Model雖然部署簡單,但即便是微小更新,也需要重新部署,專案Build的時間也會非常長,導致生產力下降。
  4. 複雜應用程式通常會有多個Team負責不同的區塊,由於OOAD過度強調抽象化整個應用程式,會導致Team與Team之間互相影響,舉個例子:Order物件會有物流的責任、財務的責任、餐廳訂單的責任,明顯違反ISP,既便Team僅負責物流的部分,也會受到財務、餐廳訂單的影響。

Microservices comes to rescue

因為認知到上述的問題,才會有Microservices的出現,Microservices針對應用程式不同的商業領域切割成多個Services,每個Service負責單一的商業領域,像是Order Management Service、Customer Management Service等等。

Why Microservices:如果正確使用Microservices,應用程式會由A Set of Loose Couple Services所組成,就能解決上述只用OOAD塑模整個複雜應用程式的問題。

Microservices優點:

  1. 因為應用程式是由A Set of Loose Couple Services所組成,每個Service只負責單一的商業領域,所以可以大幅度降低應用程式複雜度。
  2. Loose Couple Services的特性,也讓Team與Team之間溝通的Overhead大幅度降低,相較於傳統的OOAD,Team與Team之間會在同一個Codebase互相衝突。
  3. Service可以獨立部署,不會影響其他Teasm,相較於傳統OOAD,我們需要重新部署整個應用程式。
  4. 針對單一個Service撰寫測試會比較容易,相較於傳統的OOAD,撰寫測試非常困難,因為一個物件可能牽扯多個Team的功能,導致測試非常Fragile (Multiple Reason to Fail)。

Microservices缺點:

  1. 如何切割Service是一門藝術,如果切得不好,會導致Distribute Monolithic,沒有享受到Microservices帶來的優勢 (Loose Couple Services),修改程式碼從原本單一Codebase轉變成跨Process的Service。
  2. 複雜度高,需要軟體團隊有良好的開發技術、高度自動化部屬環境,台灣的環境可能連傳統的OOAD都做不好 :( 。
  3. 維持多個Services之間的Data Consistency比傳統OOAD的單一Domain Model更困難,需要使用Saga Pattern。
  4. 因為Usecase可能由多個Services完成,相較於傳統OOAD,要在多個Services Trace Log並且除錯,會比較困難。
  5. 相較於傳統OOAD,針對Services進行測試的撰寫較為困難。

When Microservices:當使用OOAD開發應用程式時,遇到一開始介紹的的問題時,強烈建議可以慢慢把Monolithic轉變成Microservices

Microservices真真假假

市面上不乏許多公司聲稱自己的架構是採用Microservices,那我們要如何判斷是否為真?

  1. Database Isolation Level:Microservices的應用程式是由A Set of Loose Couple Services組合而成,而Loose Couple的首要條件就是封裝,當Service之間如果會互相存取對方的Database Table,代表Service之間耦合性過高,會導致Distribute Monolithic。把Database想像成Class的Private Field,我們不會直接存取物件的Private Field (希望你能認同這句話),因此也不會存取Service的Database Table。
  2. Service Per Process:Service之間我們希望可以達到完全的Isolation,因此通常採用IPC (Interprocess Communication)的方式溝通,如果單純用Function Call就不是Microservices,因為Function Call會導致Service之間的耦合過高,也無法達到Microservices所說的Fault Tolerance
  3. Team Organization:多個Team負責一個Service,代表Service切得太大,導致Team之間有溝通的Overhead,降低Microservices的優點:Team與Team之間能夠獨立運作。
  4. Deployment: Service可以單獨部署、單獨Scale,如果說部署一個Service時需要連帶其他Service一起部署,代表Service之間的耦合性太高,等同於Distribute Monolithic。

上面幾個條件看起來很簡單,實際上實作時卻非常困難,公司需要有對的Process (Scrum, XP)、自動化部屬環境 (DevOps)、Organization (Cross Functional Team)、自動化測試 (Unit Test, Integration Test),否則使用Microservices只是自討苦吃,搞死底下的工程師。

這邊附上一句名言:

Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.

— Melvin E. Conway

Microservices與SOA之間的關係

兩者之間最大的差異在於:

Isolation Level:

  • SOA:相較於Microservices,沒有特別強調連Database Table都要Isolate。
  • Microservices:Database Table都要Isolate,溝通只能透過Public API。

Protocol

  • SOA:使用Heavy Weight Protocol,像是SOAP、WS*。
  • Microservices:使用Light Weight Protocol,像是RabbitMq、RESTful。

Granularity:

  • SOA:中等
  • Microservices:較小

DDD與Microservices之間的關係

基本上兩著沒什麼關係,DDD的核心釐清Bounded Context,並且於Bounded Context內使用Ubiquitous Language開發Domain Model,也就是Ubiquitous Language in Code。

DDD與傳統OOAD不同的是,DDD認清到不可能使用單一Domain Model去針對過度複雜的應用程式建模,因此切割多個Bounded Context,在Bounded Context內建立屬於此Context的Domain Model,跳脫Bounded Context外,此Domain Model就沒有意義了,這樣的方式可以大幅度降低系統複雜度

上面我們提到切割Service對於Microservices來說是非常重要的,剛好DDD的Bounded Context能幫助我們去判斷如何切割Microservices。

因此使用DDD不代表一定要用Microservice,而是我們可以藉由DDD的方式來切割Microservice的架構,DDD的Bounded Context也沒有規定溝通一定要用IPC,單純Function Call也可以。

Docker與Microservices之間的關係

傳統開發部署我們可能會使用VM的方式進行部署,因為只有一個應用程式,舉Java為例子,我們只需要一個Jar便能夠進行部署,因此使用VM非常方便。

但在Microservices的Context底下會產生一些問題,

  1. Microservices希望Service之間可以達到完全的隔離,因此如果用Service Per VM的方式去部署,會浪費過多資源 (因為VM需要透過Hardware Virtualization的方式去模擬OS,會吃掉過多資源)。

相較於VM,Docker直接與Linux Kernel溝通,效能比VM更好,也因為有Limit Access Control、Linux Namespace的關係,Container之間可以達到Isolation的效果,所以使用Docker的方式來部署Microservices能夠降低效能的浪費,也比較有效率。

所以我們可以說,因為Microservices的關係,我們需要切割成多個Service,使用VM進行部署,會導致資源浪費,因此Docker可以達到Good Resource Utilization的效果。

但是並不代表光使用Docker包覆一個Monolithic App就是Microservices。

簡單來說,Docker是為了讓Microservices的部署更加方便,更好管理Service。不會因為使用Docker程式就自動變成Microservices。

結論:先有因才有果,如果只看果,永遠看不到因,不要陷入Framework Trap,了解各個工具的Trade Off才能不被工具使用,是你使用工具,不是工具使用你。

--

--

Z-xuan Hong
Z-xuan Hong

Written by Z-xuan Hong

熱愛軟體開發、物件導向、自動化測試、框架設計,擅長透過軟工幫助企業達到成本最小化、價值最大化。單元測試企業內訓、導入請私訊信箱:t107598042@ntut.org.tw。

Responses (1)