【CHRIS RICHARDSON 微服務系列】使用微服務重構單體應用-7

編者的話 |本文來自 Nginx 官方博客,是「Chris Richardson 微服務」系列的最後一篇。第一篇介紹了微服務架構模塊,並且討論了使用微服務的優缺點。隨後的文章討論了微服務的不同方面,包括使用 API 網關、進程間通訊、服務發現、事件驅動的數據管理,以及部署微服務。本篇將討論從單體應用遷移到微服務的策略。

作者介紹:Chris Richardson,是世界著名的軟件大師,經典技術著作《POJOS IN ACTION》一書的作者,也是 cloudfoundry.com 最初的創始人,Chris Richardson 與 Martin Fowler、Sam Newman、Adrian Cockcroft 等並稱爲世界十大軟件架構師。

Chris Richardson 微服務系列全 7 篇:

1. 微服務架構概念解析

2. 構建微服務架構:使用 API Gateway

3. 深入微服務架構的進程間通信(本篇文章)

4. 服務發現的可行方案以及實踐案例

5. 微服務的事件驅動數據管理

6. 選擇微服務部署策略

7. 將單體應用改造爲微服務(本篇文章)

使用微服務重構概述

將單體應用轉變爲微服務的過程也是將應用現代化的過程,數十年來開發者們一直致力於此。因此,當把應用重構爲微服務的時候,我們可以借鑑其中的理念。

首先不要大規模地重寫代碼。大規模重寫代碼意味着你需要集中全部開發力量、從頭構建全新的基於微服務的應用;聽起來吸引人,但是充滿風險,有可能以失敗告終。正如 Martin Fowler 所言,“大規模重寫唯一能夠保證的只有大規模!”

相反,應當採取逐步重構單體應用的策略。逐步構建一個由微服務構成的應用,與單體應用並行運行;隨着時間推移,原先由單體應用實現的功能不斷收縮,最後或者完全消失,或者轉變爲微服務。這一方法雖然充滿挑戰,但風險遠小於大規模重寫代碼。

Martin Fowler 將這一應用現代化的策略稱爲“殺手應用”。這一名稱源自熱帶雨林中的殺手藤。殺手藤附生於樹,直達樹冠上方;樹死後,留下樹狀的藤蔓。應用的現代化也是遵循這一模式。微服務構成的新應用圍繞着遺留應用,後者最終完全不復存在。

接下來了解不同的實現策略。

策略一:停止挖坑

挖坑第一法則指出,如果發現自己掉坑裏,馬上停止。這一忠告也適用於難以管理的單體應用。換句話說,應該停止讓單體應用繼續變大,也就是在實現新功能的時候,不應該再增加代碼。相反,這一策略的理念在於,把這部分新代碼開發稱爲獨立的微服務。下圖展示了採用此方法的系統架構。

除了新服務和遺留應用,這個系統還包括另外兩個組件。其一是請求路由,處理傳入(HTTP)請求,與之前文章中描述的 API 網關類似。路由將與新功能對應的請求發送到新服務,將遺留請求發送到已有的單體應用。

另一組件是膠水代碼(glue code),負責集成微服務與單體應用。微服務很少孤立存在,通常需要訪問單體應用擁有的數據。膠水代碼存在於單體應用或微服務中,或者兩者兼有,負責數據集成。微服務使用膠水代碼來讀取和寫入單體應用擁有的數據。

微服務可以通過以下三種方式訪問單體應用的數據:

  • 調用由單體應用提供的遠程 API
  • 直接訪問單體應用的數據
  • 維護一份數據拷貝,與單體應用的數據庫保持同步

膠水代碼也被稱作防崩潰層(anti-corruption layer)。對於擁有自己全新領域模型的微服務,膠水代碼能夠阻止其受到遺留單體應用的領域模型的污染,並且爲這兩種模型提供轉換。防崩潰層這一術語最早出現於 Eric Evans 撰寫的必讀書 Domain Driven Design 中,並被提煉成爲白皮書。開發防崩潰層是項不平凡的工作,要想遠離單體應用的泥淖,創建防崩潰層必不可少。

以輕量級微服務的方式實現新功能有諸多優點。它能夠防止單體應用變得不可管理。微服務能夠獨立於單體服務進行開發、部署和擴展。採用微服務能讓開發者切身感受其好處。

然而,這一方法並沒有解決單體應用的問題。要想解決這些問題,需要分解單體應用。

策略二:拆分前端和後端

縮小單體應用的策略之一是將表示層(presentation layer)與業務邏輯和數據訪問層分離。典型的企業應用包括至少三類組件:

  • 表示層:處理 HTTP 請求並實現 (REST)API 或基於 HTML 的 Web UI。對於包含複雜用戶接口的應用,表示層往往是代碼的實體部分。
  • 業務邏輯層:應用的核心,實現業務邏輯
  • 數據訪問層:訪問諸如數據庫和消息代理這樣的基礎架構組件

在表示邏輯與業務和數據訪問邏輯之間,有着清晰的間隔。業務層的粗粒度的 API 由若干方面組成,內部封裝業務邏輯組件。這個 API 是一道天然分界線,將單體應用分割成兩個較小的應用。一個應用包含表示層,另一個應用包含業務和數據訪問邏輯。拆分後,表示邏輯應用對業務邏輯應用遠程調用。下圖展示了重構前後的構架。

以這種方式切割單體應用有兩大好處。首先,它使得這兩個應用的開發、部署和擴展用各自獨立。尤其是,它使得表示層的開發人員能夠快速迭代用戶接口,輕鬆進行 A|B 測試。其次,它暴露了遠程 API,能夠被微服務調用。

這種策略也只是部分解決方案,很有可能其中一個應用或兩個應用變成難以管理的單體應用。這時需要使用第三種策略來消除剩餘的單體應用。

策略三:提取微服務

第三種重構策略是將單體應用內現有的模塊轉變爲獨立的微服務。每當提取模塊並將其轉化爲服務,單體應用就會收縮。一旦轉化了足夠的模塊,單體應用也不再是問題,它或者徹底消失,或者小到成爲另一個微服務。

爲需要轉化爲微服務的模塊設置優先級

大型、複雜的單體應用由數十甚至數百個模塊組成,每個都是提取的對象。要弄清楚哪些模塊首先被轉化,往往具有挑戰性。從易於提取的模塊開始是個好方法,它能讓開發者熟悉微服務和提取過程。然後就應該轉化能從中獲益最多的模塊。

鑑於把模塊轉變爲微服務非常耗時,一般會根據獲益程度來給模塊排序。從頻繁更改的模塊開始會讓用戶收穫不菲。一旦把模塊轉化爲微服務,也就能獨立開發和部署,從而加速開發進度。

將資源需求大不相同的模塊優先轉化,也頗有好處。例如,把內存數據庫模塊轉化爲微服務,能夠被部署在大內存主機上。同樣,將實現計算算法的模塊提取出來也是非常值得,這一微服務能夠部署在擁有大量 CPU 的主機上。通過將對資源有着特殊需求的模塊轉變爲微服務,應用能夠易於擴展。

找出哪些模塊需要優先提取後,找出現有粗粒度的邊界(即分界線)也大有裨益。這些邊界讓模塊轉變爲微服務更加簡單、省力。例如,通過異步消息與應用的其它部分通信的模塊能夠相對省力、簡便地轉化爲微服務。

如何提取模塊

模塊提取的第一步是定義模塊和單體應用間的粒度接口。由於單體應用和微服務互相需要對方擁有的數據,因此更像是雙向 API。由於模塊和應用其它部分之間存在着互相依賴和細粒度的交互模型,因此實現這樣的 API 充滿挑戰。對於重構微服務,通過領域模型實現的業務邏輯尤爲挑戰,開發人員需要大刀闊斧地修改代碼來打破這些依賴。

粗粒度接口一旦完成,模塊也就變成了獨立的微服務。要做到這一點,開發人員必須編寫代碼,能夠讓單體應用和微服務通過 API 通信,API 使用進程間通信(IPC)機制。 下圖展示了重構前、重構中和重構後的不同架構。

在圖片中,模塊 Z 將要被重構,它用到了模塊 Y 的組件,同時它的組件被模塊 X 使用。重構的第一步就是定義一對粗粒度 API。第一個接口是模塊 X 使用的對內接口,用來喚醒模塊 Z。第二個接口是模塊 Z 使用的對外接口,喚醒模塊 Y。

重構的第二步則是把模塊轉變爲獨立的微服務。對內和對外接口通過 IPC 機制的代碼實現,開發人員可能只需要將模塊 Z 與微服務支撐框架(Microservice Chassis framework)組合起來構建微服務。微服務支撐框架處理與割接相關的問題,比如服務發現。

一旦將模塊提取完畢,相當於得到一個微服務,能夠獨立於單體應用和其它微服務進行開發、部署和擴展。如果要從頭重寫微服務代碼,集成微服務和單體應用的 API 代碼會成爲這兩個領域模型之間的防崩潰層。每重構一個組件,就向着微服務的方向又邁進了一步。隨着時間推移,單體應用逐漸消失,微服務則越來越多。

總結

將現有單體應用遷移到微服務架構是應用的現代化。實現這一結果並不需要從頭重寫代碼,相反,只需要漸進式地將應用重構爲一組微服務。其中有三種策略可以採納:使用微服務實現新功能、將表示組件與業務和數據訪問組件拆分、以及將現有應用內的模塊轉變爲微服務。隨着時間推移,大量微服務形成,團隊的敏捷和效率也會提升。

文章轉載自:http://blog.daocloud.io/microservices-7/

同轉:http://www.gaoxuan1989.com/category/微服務/

查看英文原文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章