標籤:介面的應用 cat ima down 介面 需求 規則 展現 代碼實現
概述
將單體應用改造為微服務實際上是應用現代化的過程,這是開發人員們在過去十年來一直在做的事情,所以已經有一些可以複用的經驗。
全部重寫是絕對不能用的策略,除非你要集中精力從頭構建一個基於微服務的應用。雖然聽起來很有吸引力,但是風險很大,很有可能會失敗。就像MartinFowler所說的: 『The only thing a Big Bang rewrite guarantees is a Big Bang!』
你應該循序漸進地重構你的單體應用。你可以逐步地構建一個部分微服務化的應用,然後和你的單體應用整合起來。單體應用的實現的功能會逐漸層少,最終消失或變成一個新的微服務元件。
種應用現代化的策略為Strangler Application。這個名字來源於在熱帶雨林發現的一種植物Strangler vine, 為了夠到充足的陽光, 它們繞樹生長,一直向上。當樹木死後,只會留下一個樹形的藤蔓。應用的現代化就是類似的模式,我們會在舊有的應用上,構建一個新的包含微服務的應用,慢慢取代舊的應用。下面一起來看下這些策略:
策略1:止損
Law of Holes告訴我們,如果你正在一個洞裡,就不要繼續再挖了。當你的單體應用已經變得無法管理的時候,就不要再繼續擴大它的規模了。 比如你想添加新功能,不要在單體應用中添加代碼,而要將新的代碼放在另一個單獨的微服務中。 展示了使用這種方法後的系統架構:
除了新服務和舊的單體應用,還有兩個組件。一個是 請求路由 (request router),用來處理過來的(比如HTTP)請求,類似於API Gateway。這個路由發送與新功能相應的請求到新的服務上,將舊服務相關的請求路由到單體應用上。
另一個組件是 膠水代碼 (glue code),用來將服務與單體應用整合起來。一個服務很少是隔離存在的,需要訪問單體應用的資料。膠水代碼就負責這些Data Integration。微服務元件可以通過它來讀寫單體應用中的資料。
一個服務可以通過三種方式訪問單體應用中的資料:
通過調用單體應用提供的遠程API
直接存取單體的資料庫
儲存一份資料的副本,和單體資料庫保持同步
膠水代碼有時被稱為 防腐層(anti-corruption layer) ,可以防止擁有自己原始領域模型的服務,被來自單體領域模型的概念所影響。
膠水代碼可以在兩個不同的模型間充當翻譯官,防腐層這個詞最初出現在Eric Evans寫的《Domain DrivenDesign》一書中。開發一個防腐層不是一個小工程,但如果你想從單體地獄中走出來,這是很重要的。
用輕量級的服務實現一個新功能,有很多好處。首先,可以防止單體應用變得更難以管理;其次,這個應用可以被獨立地開發,部署和擴充。
然而,這個方法並不能解決在舊有的單體部分遇到的問題,你還需要破壞原有的單體部分。
策略2:前後端分離
縮減單體應用的一個策略是將表現層從商務邏輯和資料訪問層中分離出來,一個典型的公司專屬應用程式至少包括三種組件:
在表現邏輯與業務和資料訪問邏輯之間通常有著明顯的區分。業務層有一個粗粒度的API,包含一個或多個外立面組成,外立面封裝了商務邏輯組件。這個API是自然的『縫合』,所以可以將單體分割為更小的應用,一個應用程式套件含了表現層,另一個應用程式套件含了業務和資料訪問層。分隔後,表現邏輯層應用可以遠程調用商務邏輯層應用,展示了改造前後的架構:
這樣分隔單體應用有兩個主要好處。 首先你可以獨立地開發,部署和擴充兩個應用, 比如對於表現層開發人員來說,他們可以實現使用者介面的快速迭代,A/B測試也很容易實現; 其次,這樣做會向外開放一個微服務也可以調用的遠程API。
但是這個策略只是部分解決方案,很有可能會變成兩個混亂的單體應用。需要用下面第三個策略去減少單體部分的比重。
策略3:提取服務
第三個策略的目的是將單體中的模組,轉變為單獨的微服務。每次提取一個模組,就改造為微服務,單體部分就縮減了。一旦你轉化了足夠的模組,最後不管單體部分是完全消失了,還是變小成了另一個微服務,都不是問題了。
優先改造哪個模組?
一個大型的複雜的單體應用,通常包含數十甚至上百個模組,都可以被提取出來,選擇先提取哪個是個問題。可以從容易被提取的開始,積累微服務的經驗,然後提取那些能給你帶來最大好處的模組。
通常提取那些頻繁變化的模組很有用 ,一旦你將這個模組提取出來,就可以獨立開發和部署它了,可以加速開發。
另外一個就是提取那些資源需求和其它部分有很大不同的模組。 比如將一個有記憶體資料庫的模組轉變為服務,就可以把它部署在記憶體很大的主機上;同樣的,提取那些實現複雜演算法的模組,就可以把它部署在CPU多的主機上。總之這樣做有助於你擴充應用。
當決定了提取哪個模組後,需要看下現有的粗粒度邊界,可以協助你將模組轉化為服務。比如一個只會通過非同步資訊和其它應用互動的模組,就很容易能被改造為微服務。
如何提取一個模組?
第一步是在模組和單體之間定義一個粗粒度的介面。 由於單體和微服務的資料互相都有需求,所以它 很像一個雙向的API。但是在這個模組和應用的剩餘部分之間,有著混亂的依賴關係和細粒度的互動模式,所以實現這個API還是很有挑戰的。通過領域模型實現的商務邏輯,改造起來尤其困難,因為各個領域模型間的關係複雜。通常需要進行大量的代碼修改,去打破這些依賴。
一旦你實現了細粒度的介面,就可以將模組改造為一個獨立的服務。要寫代碼實現單體和微服務間的通訊,通過使用了IPC機制的API。展現了一個架構在改造前,改造中和改造後的樣子:
在這個例子中,模組Z是待提取的模組。模組X使用了Z的組件,Z又使用了模組Y。
改造的第一步是定義一對粗粒度的API,第一個介面是模組X調用模組Z的入站介面,第二個是模組Z調用模組Y的出站介面;
第二步是將這個模組改造為獨立的服務。入站介面和出站介面都通過IPC機制的代碼實現。可能你需要通過結合模組Z到微服務底盤架構(用來處理橫切關注點,比如服務發現)上,來構建這個服務。
一旦你提取了這個模組,就可以獨立地開發,部署和擴充它了。你甚至可以從頭重寫這個服務,將這個服務和單體結合起來的API代碼就成了防腐層,相當於兩個領域模型之間的翻譯官。每次提取一個服務,都是向著微服務又進了一步,單體的比重會逐步縮減。
總結
將單體架構改造為微服務的過程是一種應用現代化的形式,不應該從頭重寫來實現。而是應該循序漸進地改造你的應用成為一系列微服務。有三種策略可以應用: 用微服務實現新的功能;將表現層組件從業務和資料訪問組件中分離出來;改造單體中的模組為微服務。 隨著時間的推移,你的微服務比重會增大,你的Team Dev的靈活性和速度也會提高
【轉】應用架構一團糟?如何將單體應用改造為微服務