架構

從300萬行到50萬行代碼,遺留系統的微服務改造

在傳統企業甚至互聯網企業中往往存在大量的遺留系統,這些遺留系統大多都能夠正常工作,有的可能還運行著關鍵業務或者持有核心數據。但是,大部分遺留系統通常經常存在技術陳舊、代碼復雜、難以修改等特點。筆者曾經維護過一個Perl實現的網站,在2015年被解耦前,它已經工作了十幾年,為公司占領市場立下了汗馬功勞。奈何技術陳舊,維護困難,最后在微服務化過程中慢慢淡出。

可見,隨著時間的推移,遺留系統的維護和管理的成本越來越大。在向微服務架構全面轉型的過程中,這些遺留系統就像一只只“攔路虎”,阻擋微服務轉型之路。如何在不影響業務的同時,以更安全、更高效、更低成本的方式將這些遺留系統進行微服務改造,使之順利融入微服務架構,并充分利用到微服務架構的優勢呢?本章將詳細介紹如何解決遺留系統的微服務改造問題。

一、遺留系統綜述

1. 什么是遺留系統

“遺留系統是一種舊的方法、技術、計算機系統或者應用程序,它意味著系統過時了或者需要被取代。”

這是維基百科上對于遺留系統的定義,對于“遺留”的含義有明確闡釋,即過時或者需要被取代的系統。正因為如此,遺留系統通常具有一些類似的特征。

  • 龐大的單體應用:遺留系統大多是多年積累下來的“巨無霸”系統,以單體應用形式呈現。
  • 難于修改:多年的代碼累積過程中疏于重構,導致代碼的可讀性和可擴展性較差。
  • 維護成本很高:在龐大的代碼中尋找bug的根本原因可能會比較困難。此外,運維也是難題,比如在本章開頭提到的Perl系統,沒有APM工具支持它的監控。
  • 學習成本高昂:由于設計陳舊或技術過時,可能了解遺留系統技術和業務的人已經很難找到。
  • 缺乏質量保障:由于過去缺少投入,許多功能基本上沒有自動化測試來保障質量。

這些問題隨著日積月累,可能會給團隊帶來越來越多的負擔,直到無法承受其管理和維護成本。所以遺留系統在微服務架構下如何進行改造,是大多數企業在面向微服務轉型時都不得不面對的問題,而且急需盡早考慮、盡快解決,才能避免問題累積到一定程度后集中爆發。

2. 直接重寫遺留系統可行么

遇到遺留系統的改造問題時,不少人可能會首先想到一個直截了當的方案:推翻重寫,用全新的系統一次性替換掉遺留系統。采用這種方式,在落地過程中總會發現種種問題,導致新系統無法順利切換,舊系統又無法完全替代。常見的問題有以下幾種:

  • 上線困難,業務阻塞風險高:在遺留系統重寫的過程中,往往會有新增需求對遺留系統的功能進行修改,在新系統未上線前,這些需求要么被阻塞,要么需要付出雙倍的工作量在遺留系統和新系統上同時實現,無論哪種選擇對團隊都是很難接受的。
  • 影響面不可控,系統改造周期長:遺留系統往往運行著關鍵業務或者持有核心數據,會被多個上層服務所調用。一旦決定開始重寫,其影響面無法評估,需要極為小心,考慮周全,客觀上會造成系統改造周期被無限期拉長。
  • 學習成本高,知識傳遞周期長:遺留系統的改造周期越長,對系統的學習成本就會隨之升高。在這個過程中隨著人員的正常流失,團隊對業務和技術的熟悉程度會逐漸降低,而新人需要花費更多的時間才能熟悉遺留系統改造過程中必要的知識和技術。

綜上所述,寄希望于直接重寫遺留系統、進行一次性替換而解決微服務改造問題是不現實的,必須探索一條能夠持續可演進的道路,實現快速、低成本、影響面可控的改造效果。

二、遺留系統改造策略

對遺留系統的改造,既要不影響業務,實現平滑、安全的過渡,又要保證能夠高效、穩步地推進,這對于軟件開發者來說是個不小的挑戰。

結合筆者的經驗,在遺留系統改造過程中可以采取以下思路:

  • 遵循“演進式改造流程”,優先改造最具價值的部分,并保證改造過程中的風險可控。
  • 采用“絞殺者模式”,通過逐步替換而非一次性替換的方式,來保證新舊系統的平滑過渡。
  • 采用“挎斗模式”,將不容易改造的遺留系統接入微服務環境中。

1. 演進式改造流

演進式改造流程是一種以逐步演進的方式對遺留系統進行改造的流程,其過程如圖6-1所示。

圖6-1  對遺留系統的演進式改造流程

1.1 構建服務路標圖

動手進行改造之前,首先需要構造出一個服務路標圖,來粗粒度地展示在理想情況下所期望的各個服務及相互之間的依賴關系。以該圖作為路標,指導我們著手進行服務化改造。當然,服務路標圖可以不必苛求完整,可以隨著開發過程的演進而不斷完善。構建路標圖的過程可由架構師、業務分析師及技術負責人共同參與,構建路標圖的方法可以參考3.1.1小節的“服務拆分策略”。服務路標圖構建好之后應在團隊中共享并接受來自各個方面人員的反饋。

1.2 服務選擇

有了服務路標圖之后,也許會發現改造過程千頭萬緒,不知如何選擇合適的部分優先進行改造。此時不妨遵循價值最大化的原則,從多種角度去制定優先拆分策略,比如:

  • 優先拆分相對獨立的部分,獨立業務與舊系統之間的耦合相對較小,比較容易實施。
  • 優先拆分頻繁變更的部分,可以通過拆分為新的服務實現獨立部署與快速上線,對于提高團隊總體交付效率價值較大。
  • 優先拆分有特殊資源占用需求的部分,比如將計算密集型任務拆分為新服務,并恰當地利用云基礎設施的彈性伸縮能力對新服務實例進行擴縮容,有助于提高系統總體性能并降低成本。

1.3 服務改造

選好優先需要改造的部分后,著手將這部分業務功能遷移到微服務架構下實現。改造過程中,通常需要解決這樣的問題:

  • 新舊系統可能需要不同的數據源,或具有不同的數據庫結構,怎樣解決數據之間的同步和依賴問題?
  • 單體的舊系統需要拆分為多個服務時,怎樣實現安全的漸進式拆分?

根據改造需求的不同以及數據依賴關系,具體可以分為三種不同的改造場景,每種場景下的技術實現各有不同。

1.4 業務驗證

業務功能遷移到微服務架構下實現后,需要驗證新的服務是否滿足業務需求。在新服務上線投入使用并穩定后,可以從遺留系統中移除原有的代碼模塊,如有需要時,一并移除數據同步任務。

1.5 迭代優化

至此已經對一部分遺留系統的業務完成了微服務改造,對于剩余的部分,可以按照類似的方法迭代進行,重新審視服務路標圖,選出下一個需要改造的業務,繼續進行優化,直到完成既定的微服務改造目標。

2. 絞殺者模式

在微服務架構還未流行起來之前,對于增量式的大規模軟件改造,常用的是名為“抽象分支”的方法,如圖6-2所示。

圖6-2  抽象分支

組件解耦:在需要被替換的組件與組件消費者之間創建一個抽象層,這一層只根據需要聲明抽象的接口或協議,具體的實現仍存留于待替換組件中。這樣就通過引入抽象層實現了待替換組件與組件消費者之間的解耦。

  • 新舊組件共存:開發新組件實現同一套抽象層接口,并與待替換組件同時在系統中工作,但開始時只將少部分功能在新組件中實現,或者只有少部分生產環境流量導入到新組件上。
  • 逐步替換:隨著功能逐漸完備和技術逐漸成熟,新組件承擔越來越多的生產環境流量。經過全面考驗后,新組件可以完全替代舊組件之時,舊組件就可以正式下線了。此時如果有需要也可以移除抽象層。

對遺留系統的微服務改造策略,也可以借鑒“抽象分支”的思路,只不過在微服務架構下,抽象層是由一個獨立的門面(Facade)服務實現,該服務將請求轉發到新系統或者舊系統,起到路由作用。

在改造過程中,新舊系統會同時存在,共同協作對外提供價值。隨著改造過程的推進,新系統提供的功能和價值越來越多,逐步地取代原有遺留系統的功能,用戶流量也會越來越多地導入到新系統上,最后原有遺留系統不再被使用時,就可以安全地下線了,此時門面服務也可以安全地移除。

這種平滑的過渡方法通常被稱為“絞殺者模式”。遺留系統被逐步“絞殺”的過程,如圖6-3所示。

圖6-3  絞殺者模式

絞殺者模式特別適合用于對復雜度較高的大型遺留系統進行逐步改造,但在遷移過程中也需要注意以下問題:

  • 考慮新系統和遺留系統之間的數據共享或者同步方式。
  • 確保絞殺者門面服務不會出現單點故障或成為性能“瓶頸”。

3. 挎斗模式

傳統企業中存在大量的遺留系統,要對這些遺留系統全部進行微服務化改造的成本會很高,并不現實,而且有些遺留系統甚至是無法完全改造的。對于這些系統,我們的選擇并不一定是將其進行微服務化改造,而是將其接入到微服務環境中,與其他服務共同協作來實現業務需求。

  • 然而將各種形態各異的遺留系統接入到微服務環境中并不容易,存在以下常見問題:
  • 需要對原有代碼進行一定修改,但遺留系統有時本身已經難于修改,而且如果原系統是由多種語言構成的,就要為每種語言考慮解決方案。

接入代碼如果是和原系統運行在同一進程中,就意味著沒有很好的隔離,可能會因為接入代碼的一點小問題造成原系統無法工作。那么是否存在低成本的方法,將遺留系統接入到微服務環境中呢?一種方法是使用挎斗模式,如圖6-4所示。“挎斗”一詞來源于帶挎斗的摩托車。

圖6-4  挎斗模式

如圖6-4所示,具體到遺留系統接入場景下,挎斗模式就是將接入功能代碼集中在一起,作為一個獨立的進程或服務,為不同語言的遺留系統提供一個同構的接入接口。在部署結構上,挎斗服務與原遺留系統緊密相關,原遺留系統在哪里它就在哪里。對于原遺留系統應用程序的每個實例,旁邊都部署和托管了一個挎斗實例。挎斗是支持與原應用一起部署的進程或服務。

使用挎斗模式的好處有以下幾個:

  • 挎斗服務是獨立運行的進程或服務,與原遺留系統的實現語言無關,不需要為每種語言各開發一種挎斗。
  • 由于是非侵入式的接入方法,通常不需要改寫原遺留系統的代碼,可以實現零修改成本的接入。
  • 挎斗服務與原遺留系統相鄰部署,可以訪問與原系統相同的資源,有時可以拿來作為監控服務的接入代理。
  • 雖然增加了一些通信成本,但是由于挎斗與原系統相鄰部署,增加的通信成本往往很少,延遲很低。

在使用挎斗模式時,也需要注意以下問題:

  • 注意與原系統相鄰部署,降低通信時延。
  • 注意進程間采用與語言無關的通信機制,如REST。
  • 考慮使用容器化的部署方式,比如將跨斗服務和遺留系統部署在同一個Pod中。
  • 考慮放入挎斗的功能,是作為單獨的服務或是傳統的守護進程運行方式。

ServiceMesh就是采用了挎斗模式的思路,在每個服務近端部署一個代理,幫助遺留系統接入ServiceMesh,享受服務治理帶來的好處。

三、遺留系統改造場景

在進行具體的改造前,可能會遇到如下的挑戰:

  • 新舊系統可能需要不同的數據源,或具有不同的數據庫結構,怎樣解決數據之間的同步和依賴問題呢?
  • 單體應用下的舊系統需要拆分為多個服務時,怎樣實現安全的漸進式拆分?

下面根據遺留系統改造過程中的常見場景,來一一解答這些問題。遺留系統的常見改造場景,如圖6-5所示。

圖6-5遺留系統的常見改造場景

如圖6-5所示,對于某個具體改造需求,可以分為以下兩種不同的場景。

  • 實現新業務:需要在系統中增加新業務,與現有業務相對獨立。根據新業務與現有業務之間.
  • 否存在數據依賴關系,又可分為兩種子場景,即與現有業務數據獨立或者與現有業務數據依賴。
  • 對現有業務微服務化:需要將系統的現有業務改造為微服務架構,比如對現有業務的拆分和服務化工作。

改造場景1:實現新業務時與現有業務數據獨立

適用場景:新業務與現有業務數據獨立,不存在依賴。

實現方案:新業務可以通過單獨的服務和數據庫來實現。在消費者請求和底層系統之間引入一個絞殺者門面服務,該服務負責將請求按照業務不同路由到遺留系統和新業務服務上即可,如圖6-6所示。

圖6-6改造場景1:業務數據獨立

由于和遺留系統的數據之間無耦合,新服務的技術棧、工具選型就比較靈活,充分利用到微服務技術的異構性。

改造場景2:實現新業務時與現有業務數據依賴

新業務與現有業務有數據依賴時,根據數據持有者不同,有兩種處理方案。

  • 方案A:遺留系統持有數據,新業務訪問共享數據。
  • 方案B:新業務服務持有數據,通過數據同步解決數據依賴問題。

方案A:遺留系統持有數據,新業務訪問共享數據

適用場景:允許新業務訪問遺留系統的共享數據,或者數據庫分離成本較高。

實現方案:在允許新業務服務直接訪問遺留系統的數據庫的情況下,最簡單的一種實現方案是新業務服務直接連接遺留系統數據庫獲得數據,如圖6-7所示。

這種方案的實施成本相對較低,與原有數據源進行集成即可,但缺點也在于此,由于直接使用了數據庫作為集成方式,新業務服務仍與原遺留系統數據存在直接耦合,原數據庫的變動會直接影響到新業務服務的實現,而且對于新舊業務的數據訪問權限與控制也需要納入考慮范圍內。針對這些問題,也可以考慮另外一種方案,即新業務服務通過遺留系統所提供的API來獲得數據,如圖6-8所示。

圖6-7改造場景2:直接訪問遺留系統數據

圖6-8改造場景2:通過API訪問遺留系統數據

這種方案的優點是可以通過API隔離數據變化,避免新業務服務與原遺留系統數據之間的直接耦合。可以在API中實現對數據的處理邏輯,滿足新業務服務的數據需求。API只對外提供新業務服務允許訪問的數據域,從而實現數據權限的控制,更適用于數據庫直接訪問受限制的場景。但其引入的額外成本是需要在原遺留系統上增加API實現的工作,有時因為遺留系統的技術陳舊、結構復雜等原因,會使得這部分工作比較難于執行。

方案B:新業務服務持有數據,通過數據同步解決數據依賴問題

不難看出,方案A中的方法多多少少都對原系統有一定的侵入性,或與原數據庫直接耦合,或需要對原遺留系統進行修改。面向對象設計原則中的“開閉原則”,即“對擴展開放,對修改封閉”,可以幫助我們實現靈活可擴展的軟件架構,在這里也同樣適用。因此可以考慮在原有系統基礎上進行擴展,而不是直接修改原遺留系統,于是誕生了另一個方案:新業務服務持有數據,通過數據同步解決數據依賴問題。

適用場景:不允許新業務訪問遺留系統的共享數據,或者數據庫分離成本不高。

實現方案:具體實現方法是建立獨立的數據庫供新業務服務所使用,而新數據庫與遺留系統數據庫之間通過一個專門的數據同步服務進行同步,將新數據庫中的數據轉化為與遺留系統數據可兼容的形式,并遷移過去。數據同步服務又稱ETL(Extract、Transform、Load)服務,其主要職責是讀取、轉換和同步數據,如圖6-9所示。

圖6-9改造場景2:通過ETL進行數據同步

該方案的優點在于使用了獨立的數據庫,對原遺留系統的侵入性較低,新業務服務持有新的數據庫,與原遺留系統解除了直接耦合,新業務服務和新數據庫的選型都可以比較靈活。所有新舊數據之間的轉換邏輯都在ETL服務中實現,以后任何數據轉換與同步的邏輯變化都只與ETL服務有關,無須再去修改原遺留系統和新業務服務。但該方案帶來的成本是需要額外實現一個ETL服務。另外由于需要在獨立的兩個數據庫之間進行同步,可能只能滿足數據的最終一致性而無法做到強一致性。另外也要考慮ETL服務的可用性,避免引入新的單點故障。

如果進一步考慮到數據隔離問題,避免直接暴露新服務的數據庫數據,還可以讓ETL服務通過新業務服務的API來訪問數據,如圖6-10所示。這種方案進一步解除了ETL服務與新業務數據庫之間的耦合,新增的API還可以進一步被復用,作為其他服務消費者訪問數據庫的接口。

圖6-10改造場景2:通過ELT訪問新業務服務的API進行數據同步

改造場景3:對現有業務微服務化

大多數遺留系統在單體應用架構下已經承載了許多關鍵業務或持有核心數據,對其進行微服務化改造時,一次性的重構風險是比較大的。因此,更為提倡通過數次小的重構來逐步實現微服務化改造。

適用場景:對遺留系統承載的現有業務微服務化,實現漸進式的重構。

實現方案:以一個含有多模塊的單體應用遺留系統改造為例,通過以下三個步驟拆分為業務數據分離的兩個服務。

1.將內部代碼調用修改為本地REST接口調用:將被調函數修改為REST接口暴露出來,調用者模塊通過對本地REST接口調用完成與原有業務等價的功能。此時還未拆分服務,仍然是作為一個服務整體上線。

2.將本地REST接口調用改為服務間REST接口調用:拆分服務,將原有的調用者模塊拆分為獨立服務,REST接口調用地址改為目標接口所在的服務地址。這一步接口變動的成本相當小,重點在于讓拆分后的服務能夠獨立部署與上線。同時,為避免一次引入過多變更,此階段拆分后的服務仍然直接訪問原數據庫的共享數據。

3.業務數據分離:將拆分后的服務所需的數據分離出來,作為新服務的獨享數據庫所持有。兩個數據庫之間的數據依賴問題,可以借前文所述的數據同步方案(ETL服務)解決。

按照上述過程,根據需要不斷迭代,將原遺留系統的業務逐步微服務化,總體過程的示意圖,如圖6-11所示。

圖6-11改造場景3:對現有業務微服務化

如何對遺留系統的數據庫進行拆分

在上述幾個改造場景中,有些步驟涉及對遺留系統的數據庫進行拆分。那么在多服務共享數據庫的情況下,如何決定首先拆分哪個服務的數據庫?哪種拆分順序的工作量最小呢?一種方法是采用數據“讀依賴最小”的順序進行拆分,這種方法的實施可以概括為以下三個步驟:

1.表拆分,解除服務之間的數據關系耦合:列出各個服務對表的讀寫關系,如果只有一個服務對某個表進行寫操作,不用拆分該表;當有多個服務對某個表進行寫操作時,首先考慮將這張表拆分成多張有連接關系的表,將其轉化為被某個服務單獨進行寫操作的表。

2.繪制服務依賴關系圖:在每張表被獨立服務單獨進行寫操作的情況下,按照如下規則構造有向圖,即將所有服務作為有向圖中的點,當服務A需要從服務B的數據庫讀取數據時,畫一條由B指向A的有向邊,表示服務A依賴于服務B;依此類推,直到繪制完整個依賴關系圖。

3.庫拆分,解除服務之間的數據庫耦合:以有向圖中各節點的出度(即從節點出發的邊的條數)作為該服務被依賴數,進行排序,挑選被依賴數最小的服務,首先對其進行數據庫解耦,把該服務下的數據庫表獨立出來,并在該服務里提供數據接口,以供依賴于它的服務調用。

重復第3步,直到所有數據庫被拆分為由各個服務獨享的數據庫。

例如,如圖6-12所示,是一組包含四個服務的依賴關系圖,服務右上角的角標表示該服務的被依賴數。得知短信服務的被依賴數為0,為當前被依賴最少的服務,可以首先將該服務的數據庫拆分出來。其次再按順序依次拆分積分服務、訂單服務和賬戶服務的數據庫,直至所有數據庫被拆分為由服務所獨享的數據庫。

圖6-12服務依賴關系圖示例

四、遺留系統改造案例

本節以筆者曾親身參與改造的遺留系統為案例,介紹如何將一個大型遺留系統向微服務架構進行遷移。

1. 改造前的系統情況

該系統是一個用于提供全球房產信息搜索服務的大型門戶平臺,核心功能主要包括如下幾點,如圖6-13所示。

  • 為用戶提供基于地理位置、關鍵字的房產信息搜索功能。
  • 提供基于定制搜索條件的房源信息訂閱。
  • 提供桌面端、平板端、手機端等多種不同方式的訪問。

圖6-13系統現狀

該系統是從多年前收購的一個通用搜索平臺改造而來的,整體為一個規模龐大的單體應用,使用同一個代碼庫,技術棧主要以Java為主,數據庫為Postgre,搜索引擎使用FASTSearch(歷史原因),代碼量大約在300萬行左右。

隨著業務演進的速度越來越快,單體應用的弊端導致系統變更成本越來越高。即使修改幾行代碼也需要經過冗長的測試以及發布流程,系統發布才能生效。面對這些問題,團隊決心使用微服務架構,將未來的新功能全部以微服務實現,并將系統原有功能逐步遷移到微服務架構下。

2. 改造過程

步驟1:通過遺留系統API提供數據

當時,研發團隊接到的第一個特性需求如下所示:

  • 支持NativeApp提供核心功能
  • 三個月上線首個版本

此時,面臨的挑戰主要包括以下兩個:

  • 該系統的主要研發成員在海外,國內團隊剛成立,新人多,知識遷移成本高。
  • 系統本身是基于商業通用搜索平臺上進行的二次開發,邏輯復雜,代碼耦合度高,變更成本高。

采取的方案主要包括如下幾部分:

  • 在遺留系統上封裝現有邏輯,提供基礎API。
  • 重新實現一個服務,類似之前章節提到的BFF模式,為NativeApp提供數據。
  • 該服務通過訪問遺留系統提供的基礎API獲得所需要的數據。
  • 該服務內實現必要的轉換,提供給NativeApp界面進行呈現。

利用微服務架構的異構性,新服務命名為AppService,使用RubyOnRails實現,并實現相關的數據轉換邏輯,為NativeApp提供數據API。通過這種方式實現的新服務,不僅能滿足NativeApp的需求,而且可以快速開發,獨立部署。

改造后的系統架構圖,如圖6-14所示。其中AppService服務提供兩組API,分別是提供房源信息的EstateAPI和提供地理位置信息的LocAPI。

圖6-14

步驟1:通過遺留系統API提供數據

通過如上所述的方式,極大地減少了對原門戶平臺的修改,同時通過在新服務上實現相關邏輯,不僅提升了交付效率,而且該服務能夠獨立部署上線。

步驟2:通過遺留系統數據源提供數據

接下來,研發團隊接到的特性需求如下:

  • 支持房產發布者的信息展示。
  • 支持地理興趣點(POI)信息顯示。

但是這兩部分的數據在原門戶平臺的基礎搜索API中并未包含,在面臨人手有限和交付時間緊的挑戰下,如果要在門戶平臺中新增接口,變更成本會比較高,可能無法按時交付。

面對這些挑戰,團隊決定盡量避免對原有遺留系統的直接修改,改為在AppService微服務中實現新業務邏輯,做了如下修改:

  • 直接訪問遺留系統數據源:由于原門戶平臺的基礎搜索API提供的數據不足,便讓AppServic
  • 通過直接訪問遺留系統數據源的方式,獲得所需的房源、發布者、地理興趣點等數據信息。
  • 構建基礎搜索模塊:在AppService中構建基礎搜索模板(EngineAPI),實現與原門戶平臺的基礎搜索API同樣的功能,提供數據給上層API。
  • 構建業務層API:在AppService中構建業務層API,新增兩組API,分別是提供地理興趣點數據的POIAPI和房產發布者信息的PubAPI。
  • 獨立地理位置服務:將之前相對獨立的LocAPI,拆分出來作為獨立的地理位置服務LocService。

改造后的系統架構圖,如圖6-15所示。通過這步改造,將基礎搜索數據的查詢功能重構到了AppService微服務內,減少了對原門戶平臺相關功能的修改。

步驟3:拆分基礎搜索服務,替換數據源

產品的需求持續演進,接下來,團隊需要為桌面端用戶新增支持多邊形的地理位置搜索功能。但在現有架構下,FASTSearch搜索引擎并不支持這個功能,這就意味著需要替換原有的搜索引擎,需要對原門戶平臺的代碼做大量的修改。

如何有效地實現這個特性呢?具體操作方法如下:

1.將基礎搜索API拆分出來作為獨立服務EngineService,這樣以后關于搜索相關的邏輯,都可以放在EngineService中實現了。

圖6-15步驟2:通過遺留系統數據源提供數據

2. 在EngineService中實現基于多邊形的搜索。

3. 對原門戶平臺的搜索機制重構,讓其使用EngineService獲取相關數據(之前是使用FASTSDK)。基于這種方式,門戶平臺和AppService與底層搜索引擎隔離開來,可以方便地替換底層數據源。

該方案的實現,如圖6-16所示。

圖6-16步驟3:拆分基礎搜索服務,替換數據源

步驟4:構建移動端專屬的后端服務

團隊在預期時間內很快地完成了前面的各項需求,隨著業務發展迅猛,接下來需要在手機端和平板端增強用戶體驗。然而,目前手機端、平板端的實現邏輯較落伍,均是基于JSP的模板方式實現。如果要直接修改,成本高。

考慮到在屏幕尺寸、性能和顯示限制等方面,移動設備與桌面瀏覽器的能力存在顯著差異。因此,移動應用對后端的需求與桌面UI是不一致的。

如果仍然使用原有的門戶平臺邏輯,則需要同時為這兩種客戶端提供數據,這極大地增加了維護的成本。于是,團隊借鑒了BFF模式,將手機端和平板端網站的特定后臺需求,拆分為一個獨立的后臺服務SPA-Web,作為后端實現。為前端提供數據。然后基于最新的前端技術,采用輕量級、更有效的單頁面方式實現前端,如圖6-17所示。

圖6-17

步驟4:構建移動端專屬的后端服務

通過為移動端創建一個專屬的后端服務,可以為移動端的用戶進行專門的優化,量身打造最佳體驗。同時,由于微服務架構下的這個新服務足夠的小而簡單,就更容易進行修改、部署和上線了,也更容易在性能和行為方面進行精心的優化。

步驟5:基于數據繼續劃分微服務

隨著團隊的微服務化實踐越來越成熟,整個系統的架構趨向于朝更細的粒度演進。

系統典型的業務場景分為待售房源(Buy)、已售房源(Sold)、待租房源(Rent)等。所以,團隊基于這些業務繼續劃分單獨的搜索API以及獨立的數據存儲機制,每種數據由獨立的ElasticSearch 集群存儲,并利用前后端分離的機制實現前后端的解耦。

解耦后的系統,如圖6-18所示。

圖6-18步驟5:按照數據劃分微服務

最終實現的服務,如下表所示。

服務名稱主要描述
UserService處理用戶信息的認證和鑒權
SavedSearchService處理用戶保存的訂閱條件
POIService處理POIService相關的信息
LocService提供地理位置相關接口
BuyService提供待售房源相關的接口
SoldService提供已售房源相關的接口
RentService處理待租房源相關的邏輯

對于系統中使用的服務支撐組件,如服務注冊發現機制、集中化配置信息等機制,其實現和在之前的章節中闡述的差不多,這里就不展開贅述了。

3. 改造結果

可以看到,經過上面一系列步驟后,原有的門戶平臺已逐漸遷移為微服務的系統,原有的大約300萬行的代碼也只剩下了大約50萬行,繼續提供著業務價值。團隊對遺留系統的修改和變更成本已經大大減少,總體交付周期也大大縮短,技術的升級帶來性能、可維護性的提升,充分享受到了微服務架構小而美的好處。

小結

本章介紹了遺留系統的特點、改造策略和場景,并結合一個實戰案例進行了講解。目的是幫助讀者從以下方面掌握對遺留系統的微服務改造方法:

  • 遺留系統是“需要被替代的系統”,往往存在類似的特征,如難于修改、學習和維護成本高、缺乏質量保障等。
  • 通過直接重寫并一次性替換遺留系統解決微服務改造問題是不現實的,可能會導致上線困難、影響面不可控、學習成本高等問題的產生。
  • 對于遺留系統的改造過程,應當采取逐步替換而非一次性替換的策略。通常采用“演進式改造流程”和“絞殺者模式”來保證整個改造過程可控,并實現平滑過渡。

另外,對于遺留系統的改造需求,本章將其細分為三種場景,如新業務數據獨立、新業務數據依賴以及現有業務服務化。通過對這些場景的分析,能有效地指導讀者進行微服務的演進。

本文節選自《微服務架構與實踐(第2版)》一書,王磊等著,電子工業出版社出版。

原文鏈接:https://mp.weixin.qq.com/s/Z6Tk7FMLX9PIdbcL3iyIHA

最干貨的java+分布式技術公眾號,兼及研發管理。本號專家陣容:螞蟻金服右軍、易寶CTO陳斌、米么金服總監李偉山、奧琪金科首席架構曲健、螞蟻金服高級技術專家張翔、美團高級技術專家楊彪等。

如何成為數據庫管理員(DBA)

上一篇

Docker容器實現原理及容器隔離性踩坑介紹

下一篇

你也可能喜歡

從300萬行到50萬行代碼,遺留系統的微服務改造

長按儲存圖像,分享給朋友

ITPUB 每周精要將以郵件的形式發放至您的郵箱


微信掃一掃

微信掃一掃
大丰收注册
贵州11选5近20 宁夏体彩11选五开奖查询 股票开盘前五分钟 网上做任务赚钱的网 网上棋牌可以玩吗 贵州快了3开奖结果 山东十一运夺金开奖结果查询 浙江12选5开奖结果 急速赛车手 大乐乐透牛彩网 11选五5走势图河北 广东推倒胡麻将技巧 河南十一选5开奖结果 股票交易规则 免费大众麻将 内蒙古快3同步时间软件