1. 程式人生 > >單體式應用微服務改造經驗談【上】

單體式應用微服務改造經驗談【上】

昨日好評博文:《如何設計出優美的Web API?》

截止目前閱讀量近 2000,獲得好評無數,小夥伴們不要錯過哦!

 

微服務是當下最流行的應用架構技術了,它跟容器服務、DevOps合稱雲時代的三劍客,可以幫我們化解業務發展過快導致的產品迭代壓力,讓我們可以自由選擇最適合團隊的技術棧,讓系統能夠承載網際網路海量使用者的訪問,讓我們可以更加輕鬆地運維大型的網際網路系統。近些年在廠商、社群和使用者等各方努力推動下,微服務相關的理論和產品都日趨成熟,不同語言的微服務開發及治理套件(例如:Spring Cloud/Dubbo等)讓我們從零開始搭建微服務變得非常簡單快捷,那我們是否就此可以全面進入微服務時代呢?

微服務的演進成熟需要時間,我們熟悉掌握這套新技術也需要時間,除此之外機房裡面還跑著大量的單體式應用,它們需要繼續維護和升級,任何時候我們都不可能拋開歷史輕鬆上陣。這些單體式應用還擔負著公司的核心業務,全部推倒重來、休克式重構是不可取的,投入大週期長,風險完全不可控。我們必須學會邊行車邊換胎的技能,在不影響現網業務的前提下推動微服務改造,讓老系統煥發新的生命力,繼續支援業務下一個十年的發展。本文將跟你一起探討微服務改造相關的經驗方法,讓你更加從容地擁抱微服務!

  • 1. 邊行車邊換胎三步走演進策略

如何從單體式應用演進至微服務呢?這些單體式應用都存在很長時間了,經過這麼長時間的修修補補,體量規模都比較大,尤其是經過幾波人交接維護,業務邏輯也變得異常複雜。同時,它們都線上對外提供服務,全部推倒重建的可能性微乎其微,休克式重構投入大週期長,風險也不好控制,還會影響業務對外服務的連續性。從現實情況出發,最可行的架構優化方案就是漸進式的微服務改造,按照業界的最佳實踐和個人經驗,該演進策略主要包括三個關鍵步驟:

  • 將所有新特性都構建成微服務,遏制單體式應用的生長;
  • 在微服務和單體式應用之間構建反腐層,防止老系統腐化新系統;
  • 按照特定的優先順序由外而內逐步瓦解單體式應用。

 

  • 1.1 新建微服務

通常單體式應用所採用的技術相對較老舊,維護這些系統的同事缺少機會學習實踐當前主流的技術,久而久之就跟不上主流技術的發展,在晉升、加薪和跳槽時都缺乏競爭力,這會影響到個人的價值。隨著系統規模越來越龐大,更新升級和運營維護的難度越來越大,每次發版都要加班加點和心驚膽戰,逐漸滿足不了業務快速發展的需要。在單體式架構之下,團隊無法利用不同技術棧的優勢解決不同場景下的問題,即使解決了問題也是事倍功半。

當意識到有必要將單體式應用改造成微服務時,我們通常會認為改造就是將單體式應用一塊一塊地敲下來改成微服務,這種想法是最直接的,但難度和風險也是最大的。改造初始我們對微服務相關技術也比較生疏,再加上拆解單體式應用本身的難度,雙重困難疊加往往會導致改造失敗或延期。

最靠譜的策略是先停止往單體式應用裡面新增新的特性,所有新特性都構建成微服務,從而遏制單體式應用繼續生長。新特性通常不會太複雜,新建微服務也要比從單體式應用上剝離微服務容易一些,藉助這個過程讓團隊逐漸熟悉掌握微服務技術棧,從小規模練兵再到全面鋪開。常見的微服務架構如下圖所示,主要包含以下幾大必備元件:

  • 註冊中心,提供微服務的註冊、發現和狀態監測等功能;
  • 配置中心,解耦程式碼與配置,通過統一的遠端配置中心管理每個微服務的配置資料,支援動態修改和立即生效等;
  • 治理中心,依賴註冊中心和配置中心,提供服務降級、服務熔斷、流量控制、灰度管理等功能;
  • API閘道器,將每個微服務匯聚一起對外提供服務,閘道器本身會提供安全鑑權、服務路由、流量控制、計量計費等橫切面功能。 
  • 1.2 構建反腐層

新特性全部構建成了微服務,但老特性還依舊在單體式應用當中,許多業務還需要新舊系統彼此協作才能完成,那麼微服務和單體式應用之間還存在彼此互動。但新舊系統對外服務時所採用的協議可能不同,例如:採用Spring Cloud框架開發的微服務主要以RESTful HTTP API對外服務,採用Dubbo框架開發的微服務以Dubbo協議對外服務,而單體式應用可能以Web Service、EJB T3、不規範HTTP API等形式對外服務。除了協議不同之外,新舊系統對領域模型的定義也可能不同,包括名稱和屬性等,如何調和微服務和單體式應用的不同呢?

在微服務和單體式應用之間構建一道反腐層,這或許是最切實可行的辦法。通過反腐層完成新舊系統的對接整合,又可以避免舊系統領域模型對新系統的干擾,讓彼此保持鬆耦合狀態,阻止舊系統的腐爛蔓延至新系統。反腐層還可以對單體式應用進行服務化封裝,讓其像微服務一樣以RESTful HTTP API的方式對外服務。反腐層支援雙向通訊,重點解決新舊系統對接整合、協議適配和模型轉換等問題,按照此功能定位我們可以將反腐層劃分成三個模組:

  • 外觀(Facade),經典設計模式,作為舊系統所有服務介面的門面,簡化新舊系統對接的複雜度;
  • 介面卡(Adapter),經典設計模式,向新系統提供所需的服務實體,負責請求和應答的協議適配;
  • 轉換器(Translator),負責請求和應答中新舊系統領域模型的轉換。

由於單體式應用的架構較為簡單,因此在設計之初它們很少考慮系統整合相關的設計,通常一個應用下的不同服務擁有各自的入口,外觀(Facade)就是解決此問題的,統一單體式應用對外服務的格式,像微服務一樣以RESTful HTTP API的方式對外服務,規範介面的協議型別、URL命名和報文格式等。如果舊系統不屬於我們維護,那反腐層就需要包含Facade模組,微服務通過它對接舊系統。如果舊系統也是由我們自己維護,那建議將Facade模組構建在單體式應用內部,微服務通過Adapter模組對接舊系統。

  • 1.3 圍剿單體式應用

在舊系統周邊構建微服務,遏制舊系統的不斷生長,然後再從舊系統逐步剝離出微服務,最後完成對單體式應用的絞殺。優良的微服務設計同樣遵循高內聚、低耦合原則,將關聯緊密的行為封裝進一個微服務當中,從而可以減少需求變更所影響的範圍。只要服務契約不發生改變,那對單個微服務的升級改造都不會影響到其他服務,因此可以釋出更少的服務來快速地滿足業務需求,並降低同時部署多個微服務時帶來的風險。在從單體式應用剝離微服務之前,我們先看看功能模組之間的邊界有哪些型別:

  • 技術邊界:將系統按照技術棧的不同劃分,形成兩個部件的邊界。它們所採用的技術大相徑庭,對開發人員的技能要求不同。業界將此種架構叫做洋蔥架構,擁有許多水平分層,不利於改造成微服務。
  • 地域邊界:按照組織分佈的地域劃分,相對較容易改造成微服務。
  • 業務邊界:按照業務型別劃分,最適合作為微服務的邊界型別。

領域驅動設計(DDD)理論提出了有界上下文(Bounded Context)概念,這是我們釐清服務邊界的有效工具,我們可以藉助它從單體式應用上剝離微服務。因此,單體式應用的微服務化改造,亦或新建微服務,我們都離不開業務專家的支援,通過他們確定有界上下文的劃分,從而設計出好的微服務。

  • 2. 隔離閘道器接管新舊系統間互動

在前面章節中我們已經知道在微服務改造過程中需要構建反腐層,那在實際專案當中反腐層會以什麼樣的形態存在呢?通常我們會將反腐層設計成隔離閘道器,以單獨的程序執行,在隔離閘道器內部實現Facade、Adapter和Translator等功能模組。隔離閘道器不需要從零開始建設,我們可以在Nginx、Kong、Zuul等開源中介軟體基礎上擴充套件,它們都支援外掛化或過濾器等擴充套件定製模式,我們很容易實現反腐層需要的功能。

通過反腐層(隔離閘道器)微服務可以與單體式應用進行正常通訊,同時彼此之間保持鬆耦合,單體式應用可以不用做傷筋動骨地改動,微服務可以採用最新的技術獨立演進,但這種方案下這些遺留的單體式應用是無法享受到雲原生帶來的好處。有沒有一種方案可以讓這些遺留系統也享受到服務發現、流量控制、服務熔斷、服務降級等新特性呢?

Service Mesh,下一代微服務架構,可以給我們帶來更加完善的解決方案,它將原先通過微服務開發框架(例如:Spring Boot等)侵入到應用內部的服務治理等功能模組封裝進了Sidecar,與應用結對部署,作為獨立的程序存在,這樣可以做到與應用鬆耦合,架構上更加靈活,可以支援微服務治理相關基礎設施的獨立升級部署,還可以支援多語言。如果在Sidecar基礎上再擴充套件隔離閘道器的功能,那遺留的單體式應用也可以更加融入微服務架構了。

 

  • 3. 單體式應用拆解微服務的方法

本章節我們將梳理從單體式應用剝離微服務的一些常見場景和方案。在談具體案例之前,我們有必要先了解一下業界最佳實踐的經驗總結,它主要包含以下幾個基本步驟:

  • 識別出某個業務板塊的上下文邊界,這是拆解單體式應用的關鍵步驟。微服務是按照業務來劃分和組織的,在動手拆解之前先要理清當前一個單體式應用提供了哪些業務功能,例如:使用者管理、商品展示、訂單管理、支付管理和物流管理等,按照垂直方向劃分出來的功能板塊都可以改造成微服務。具體操作時大部分程式語言都提供了名稱空間(NameSpace)特性,我們在重構過程中可以藉助它將同一個上下文相關的程式碼歸集在一起,然後從整個工程中將其拆解出來形成微服務。
  • 釐清業務功能模組之間的依賴,儘量減少依賴關係,從變化頻繁、投入產出比高的模組開始剝離,這樣可以逐步緩解日常開發的進度壓力。經過依賴關係的梳理,冗餘的依賴將會被消除,剩下的依賴將會從程序內部的函式呼叫改造成程序之間的RESTful HTTP API呼叫。
  • 拆解資料,包括資料訪問層和資料庫表等。除了程式碼,資料也要被拆解,資料訪問層要被打散到不同的名稱空間當中,資料庫表之間的外來鍵依賴需要被清理消除等。

從業務開始,再到程式碼,最後才是資料,這就是上述三個步驟的關鍵。業務是所有程式碼和資料的源頭,面向物件設計(OOD)和領域驅動設計(DDD)是做好微服務設計的專業技能,而用好這兩項技能的前提就是對業務有深刻的洞悉,在(下)篇中我們將一起來看看具體的拆解場景,敬請期待!今天先分享到這裡,如果你覺得有價值,麻煩動動手指點下文 「 推薦 」按鈕,讓更多小夥伴可以看到,我也會更加有動力堅持分享。另外,老兵哥我後續還會分享職業規劃、應聘面試、技能提升、影響力打造等經驗,歡迎 關注 本專欄或歪信公主號 「 IT老兵哥 」!

關注「 IT老兵哥 」,賦能程式人生!

  • 軟技能類熱點文章:
  1. “花式”裁員套路深,你知道嗎?
  2. 遭遇裁員,如何渡過心理危機?
  3. 如何在寒冬中找到好工作?
  4. 2C 還是 2B,跟找工作有什麼關係?
  5. 大公司 vs 小公司,你會選哪個?
  6. 記住這一點,不怕找不到好工作!
  7. 跳槽,跳還是不跳,該怎麼跳?
  8. 程式設計師“求包養”攻略揭祕
  9. 很努力了,為什麼我還在原地踏步?

 

  • 硬技能類熱點文章:
  1. 如何設計出優美的Web API?
  2. 程式設計師必須懂的架構入門課
  3. 從程式設計師到架構師,有捷徑嗎?
  4. 圖解 Spring:HTTP 請求的處理流程與機制【1】
  5. 圖解 Spring:HTTP 請求的處理流程與機制【2】
  6. 圖解 Spring:HTTP 請求的處理流程與機制【3】
  7. 圖解 Spring:HTTP 請求的處理流程與機制【4】
  8. 圖解 Spring:HTTP 請求的處理流程與機制【5】
  9. 如何正確使用 Spring Cloud?【上】
  10. 如何正確使用 Spring Cloud?【中】
  11. 如何正確使用 Spring Cloud?【下】
  12. Spring 核心技術與產品理念剖析【上】
  13. Spring 核心技術與產品理念剖析【下】