重構(gòu)單體應(yīng)用到微服務(wù)

原文鏈接:Refactoring a Monolith into Microservices

  1. 微服務(wù)介紹
  2. 構(gòu)建微服務(wù)之使用API網(wǎng)關(guān)
  3. 構(gòu)建微服務(wù)之:微服務(wù)架構(gòu)中的進(jìn)程間通信
  4. 微服務(wù)中的服務(wù)發(fā)現(xiàn)
  5. 微服務(wù)之事件驅(qū)動(dòng)的數(shù)據(jù)管理
  6. 選擇一種微服務(wù)部署策略
  7. 重構(gòu)單體應(yīng)用到微服務(wù)(本文)

這是使用微服務(wù)架構(gòu)構(gòu)建應(yīng)用系列的第七篇也是最后一篇文章,第一篇文章介紹了微服務(wù)架構(gòu)模式匾效,并討論了使用微服務(wù)架構(gòu)的優(yōu)勢(shì)和劣勢(shì)舷蟀,接下來(lái)的文章討論微服務(wù)架構(gòu)的不同方面:使用API網(wǎng)關(guān)、進(jìn)程間通信面哼、服務(wù)發(fā)現(xiàn)野宜、事件驅(qū)動(dòng)的數(shù)據(jù)管理以及部署微服務(wù),本篇文章魔策,讓我們看下如何把一個(gè)單體應(yīng)用重構(gòu)為微服務(wù)架構(gòu)的應(yīng)用匈子。

我希望這個(gè)系列的文章使你對(duì)微服務(wù)架構(gòu)有一些好的理解,比如它的優(yōu)勢(shì)和劣勢(shì)闯袒,何時(shí)使用微服務(wù)等 虎敦,或許微服務(wù)架構(gòu)對(duì)您的組織將非常合適。

然而政敢,你現(xiàn)在更可能正在為一個(gè)龐大的其徙、復(fù)雜的單體應(yīng)用而工作,你每天正經(jīng)歷著開發(fā)和部署單體應(yīng)用的緩慢和痛苦 喷户,微服務(wù)看起來(lái)更像一個(gè)遙遠(yuǎn)的極樂世界唾那。幸運(yùn)的是,我們有幾個(gè)策略可以使你逃離單體的地獄摩骨。本篇文章我將描述如何漸進(jìn)的把單體應(yīng)用重構(gòu)為一系列的微服務(wù)通贞。

重構(gòu)為微服務(wù)架構(gòu)的概覽

把一個(gè)單體應(yīng)用轉(zhuǎn)化為微服務(wù)實(shí)際是應(yīng)用現(xiàn)代化的一種形式朗若,這個(gè)事情開發(fā)者已經(jīng)做了十多年了,因此昌罩,有一些經(jīng)驗(yàn)在我們重構(gòu)應(yīng)用為微服務(wù)時(shí)候可以重用哭懈。

策略之一是不要使用“Big Bang”式的重寫,也就是不要集中所有的力量從頭構(gòu)建一個(gè)新的基于微服務(wù)的應(yīng)用茎用,盡管那個(gè)方式聽起來(lái)很誘人遣总,實(shí)際會(huì)有極大的風(fēng)險(xiǎn),最終也會(huì)以失敗告終轨功。正如 Martin Fowler 所說(shuō):“the only thing a Big Bang rewrite guarantees is a Big Bang!”旭斥。

避免使用Big Bang重寫,我們應(yīng)該漸進(jìn)式的重構(gòu)我們的單體應(yīng)用古涧,我們逐步的構(gòu)建由微服務(wù)組成的新應(yīng)用垂券,并與我們的單體應(yīng)用一起運(yùn)行。隨著時(shí)間的推移羡滑,單體應(yīng)用實(shí)現(xiàn)的功能將會(huì)縮水菇爪,直到完全消失或者變成另外一個(gè)微服務(wù)。這種策略可以類比于在高速路上只把車開到70邁-有挑戰(zhàn)性但是比Big Bang重寫危險(xiǎn)小柒昏。

Martin Fowler 提到了這種應(yīng)用現(xiàn)代化的策略凳宙,稱其為Strangler Application,名稱來(lái)源于熱帶雨林中的扼殺藤蔓职祷,扼殺藤蔓生長(zhǎng)在大樹的周圍企圖得到樹冠處的陽(yáng)光氏涩,最后樹木會(huì)死掉,只留下一堆樹狀的藤蔓有梆。應(yīng)用現(xiàn)代化 遵循這樣的模式是尖,我們將會(huì)圍繞的遺留應(yīng)用構(gòu)建由一系列微服務(wù)組成的新的應(yīng)用,最終遺留應(yīng)用將會(huì)消失泥耀。

Paste_Image.png

讓我們來(lái)看實(shí)現(xiàn)該目標(biāo)可采用的不同策略:

策略一:停止挖掘

Law of Holes 告訴我們一旦你落入洞穴析砸,你應(yīng)該停止繼續(xù)挖洞!一旦你的單體應(yīng)用變的難以管理爆袍,這是一個(gè)需要聽取的極好的建議。換句話講作郭,你應(yīng)該停止讓單體應(yīng)用繼續(xù)變的更加龐大陨囊,這意味著,當(dāng)你需要實(shí)現(xiàn)新功能的時(shí)候夹攒,你不應(yīng)該往單體應(yīng)用中添加新的代碼蜘醋。相反的,這個(gè)策略的重要一點(diǎn)是咏尝,把新代碼放到一個(gè)獨(dú)立的微服務(wù)中去压语。下圖展示了應(yīng)用該方法后的系統(tǒng)架構(gòu):

Paste_Image.png

除了新服務(wù)和遺留的單體應(yīng)用啸罢,還多出來(lái)其他的兩個(gè)組件:第一個(gè)組件是請(qǐng)求路由器,用來(lái)處理HTTP請(qǐng)求胎食,這和我們前面所說(shuō)的API網(wǎng)關(guān)類似扰才,路由器發(fā)送請(qǐng)求到對(duì)應(yīng)新功能的新服務(wù)上去,路由遺留應(yīng)用的請(qǐng)求到單體應(yīng)用中去厕怜。

另一個(gè)組件就是膠水代碼衩匣,用來(lái)集成服務(wù)和單體應(yīng)用。一個(gè)服務(wù)很少獨(dú)立存在粥航,一般都需要訪問(wèn)單體應(yīng)用擁有的數(shù)據(jù)琅捏。膠水代碼存在于服務(wù)端,或者單體端递雀,或者兩端均有柄延,用來(lái)負(fù)責(zé)數(shù)據(jù)的集成,服務(wù)使用膠水代碼對(duì)單體擁有的數(shù)據(jù)進(jìn)行讀寫操作缀程。

服務(wù)有三種策略可以用來(lái)訪問(wèn)單體的數(shù)據(jù):

  • 調(diào)用單體提供的遠(yuǎn)程API
  • 直接訪問(wèn)單體擁有的數(shù)據(jù)庫(kù)
  • 維護(hù)自己的數(shù)據(jù)副本搜吧,副本需要從單體應(yīng)用端同步過(guò)來(lái)

膠水代碼有時(shí)也被稱為anti-corruption layer,這是因?yàn)槟z水代碼防止了擁有自己純凈領(lǐng)域模型的服務(wù)被來(lái)自遺留單體應(yīng)用的領(lǐng)域模型的設(shè)計(jì)理念所污染杠输。膠水代碼在兩種不同的模型間進(jìn)行轉(zhuǎn)換赎败。anti-corruption layer一詞首次出現(xiàn)在Eric Evans 所著的必讀之書 Domain Driven Design 中,并在white paper中被提煉修正蠢甲。開發(fā)一個(gè)anti-corruption layer不是一項(xiàng)簡(jiǎn)單的事情僵刮,但如果不想陷入單一地獄,還是有必要搞一個(gè)的鹦牛。

把新功能實(shí)現(xiàn)為輕量級(jí)的服務(wù)有諸多優(yōu)勢(shì):它避免單體應(yīng)用最終變的不可管理搞糕,服務(wù)同時(shí)可以被獨(dú)立于單體去開發(fā)、部署和擴(kuò)展曼追。你可以通過(guò)創(chuàng)建每一個(gè)新的服務(wù)體會(huì)到微服務(wù)架構(gòu)的優(yōu)勢(shì)窍仰。

然而,這種方式并沒有解決單體中的問(wèn)題礼殊,為了解決這些問(wèn)題驹吮,你需要拆分單體。讓我們看一下拆分的策略:

策略二:前后端分離

縮小單體應(yīng)用的策略之一是把展示層從業(yè)務(wù)邏輯層和數(shù)據(jù)訪問(wèn)層中拆分出來(lái)晶伦。一個(gè)典型的企業(yè)應(yīng)用一般包含至少三種不同的組件:

  • 展示層:用來(lái)處理HTTP請(qǐng)求并實(shí)現(xiàn)基于REST API或者基于HTML的Web UI碟狞,在一個(gè)用戶界面復(fù)雜的應(yīng)用中,展示層通常包含大量的代碼
  • 業(yè)務(wù)邏輯層:應(yīng)用的核心并實(shí)現(xiàn)業(yè)務(wù)規(guī)則的組件
  • 數(shù)據(jù)訪問(wèn)層:訪問(wèn)諸如數(shù)據(jù)庫(kù)和消息中介等基礎(chǔ)架構(gòu)的組件婚陪。

通常展示邏輯對(duì)于后臺(tái)業(yè)務(wù)邏輯與數(shù)據(jù)訪問(wèn)邏輯來(lái)講族沃,彼此有清晰的劃分。業(yè)務(wù)層有由一個(gè)或多個(gè)門面組成的粗粒度API,它封裝了業(yè)務(wù)邏輯組件脆淹,這些API是拆分單體應(yīng)用到兩個(gè)更小應(yīng)用時(shí)候的自然縫隙常空。一個(gè)應(yīng)用包含展示層,另一應(yīng)用包含業(yè)務(wù)邏輯和數(shù)據(jù)訪問(wèn)邏輯盖溺,經(jīng)過(guò)拆分漓糙,展示邏輯的應(yīng)用向業(yè)務(wù)邏輯應(yīng)用發(fā)起遠(yuǎn)程調(diào)用,下圖展示了重構(gòu)前后的架構(gòu):


Paste_Image.png

這種方式拆分單體應(yīng)用有兩個(gè)大的優(yōu)勢(shì):它使得兩個(gè)應(yīng)用可以獨(dú)立的開發(fā)咐柜、部署和擴(kuò)展兼蜈,尤其是它允許展示層開發(fā)者快速迭代用戶界面并容易的進(jìn)行A|B測(cè)試,這種方式的另一優(yōu)勢(shì)是它暴露了可以被其他微服務(wù)調(diào)用的遠(yuǎn)程API拙友。

這種策略为狸,也僅僅是部分解決方案,這樣重構(gòu)完之后遗契,很可能兩個(gè)應(yīng)用逐步變成兩個(gè)不可管理的單體辐棒。你需要使用第三者策略消除剩余的單體部分。

策略三:提取服務(wù)

重構(gòu)第三個(gè)策略是把單體中存在的模塊變成獨(dú)立的微服務(wù)牍蜂。每一次你提取模塊并把其轉(zhuǎn)化為服務(wù)辜御,單體就會(huì)縮小递胧,一旦你覆蓋了足夠多的模塊杠袱,單體就將不再是一個(gè)問(wèn)題铲觉,單體要么消失掉要么小到變成另外一個(gè)微服務(wù)。

確定需要轉(zhuǎn)化為服務(wù)的模塊的優(yōu)先級(jí)

一個(gè)龐大从绘、復(fù)雜的單體應(yīng)用有數(shù)十甚至上百個(gè)模塊組成寄疏,所有的模塊都是需要提取的候選。確定哪一個(gè)模塊需要首先被提取是很有挑戰(zhàn)性的問(wèn)題僵井,一個(gè)好的方式是先選擇容易提取的模塊作為開始陕截,這將給你一些微服務(wù)總體上概覽以及尤其是提取過(guò)程上的經(jīng)驗(yàn)。在這之后批什,你可以提取那些可以給你帶來(lái)最大優(yōu)勢(shì)的模塊农曲。

把一個(gè)模塊轉(zhuǎn)化為一個(gè)服務(wù)通常是需要一定時(shí)間的。你想要根據(jù)你可以獲得優(yōu)勢(shì)的大小排列你的模塊驻债,通常轉(zhuǎn)換經(jīng)常變化的模塊帶來(lái)的優(yōu)勢(shì)最大乳规。一旦你把一個(gè)模塊轉(zhuǎn)化為服務(wù),你就可以獨(dú)立于單體來(lái)開發(fā)合呐、部署它 了驯妄,這會(huì)極大的加速你的開發(fā)效率。

提取那些對(duì)資源有獨(dú)特需求的模塊也會(huì)帶來(lái)很多優(yōu)勢(shì)合砂,比如,把擁有內(nèi)存數(shù)據(jù)的模塊轉(zhuǎn)化為服務(wù),就可以把服務(wù)部署到擁有大量?jī)?nèi)存的主機(jī)上翩伪,同樣的微猖,提取一個(gè)需要實(shí)現(xiàn)計(jì)算密集型算法的模塊也是很值得的,因?yàn)樵摲?wù)可以被部署到有多顆CUP的主機(jī)上缘屹,通過(guò)把有獨(dú)特資源需求的模塊轉(zhuǎn)化為服務(wù)凛剥,可以使得應(yīng)用更容易擴(kuò)展。

當(dāng)決定哪個(gè)模塊需要提取時(shí)轻姿,查看已存在的粗粒度的邊界(也就是縫隙)是很有用的犁珠,這會(huì)使模塊轉(zhuǎn)化到服務(wù)更加簡(jiǎn)單和低廉。邊界的例子之一是互亮,一個(gè)模塊只通過(guò)異步消息與應(yīng)用的其他部分進(jìn)行通信犁享,把該模塊轉(zhuǎn)化成微服務(wù)是相當(dāng)廉價(jià)和簡(jiǎn)單的。

如何提取模塊

提取模塊的第一步是確定模塊與單體應(yīng)用間的粗粒度接口豹休,由于單體和模塊需要訪問(wèn)彼此擁有的數(shù)據(jù)炊昆,一般是一些雙向的API。由于依賴的錯(cuò)綜復(fù)雜以及模塊與應(yīng)用其他部分間細(xì)粒度的交互威根,實(shí)現(xiàn)這些API一般非常有挑戰(zhàn)性凤巨。重構(gòu)使用領(lǐng)域?qū)ο竽J?/a> 設(shè)計(jì)的業(yè)務(wù)邏輯尤其困難,因?yàn)轭I(lǐng)域模型類中彼此包含大量的關(guān)聯(lián)關(guān)系 洛搀。你一般需要進(jìn)行大的代碼改動(dòng)才能打破這些依賴敢茁,下圖展示了重構(gòu)過(guò)程:

一旦你實(shí)現(xiàn)了粗粒度的接口,你就可以把這些模塊轉(zhuǎn)化為獨(dú)立的服務(wù)留美。為了實(shí)現(xiàn)這個(gè)目標(biāo)彰檬,你必須寫代碼使得單體應(yīng)用和服務(wù)可以通過(guò)進(jìn)程間通信機(jī)制的API進(jìn)行交互。下圖展示了應(yīng)用重構(gòu)前独榴、中僧叉、后的架構(gòu):


Paste_Image.png

在這個(gè)例子中,模塊Z是要被提取的候選模塊棺榔,它的組件被模塊X使用瓶堕,它本身使用到模塊Y。重構(gòu)第一步是定義一組粗粒度的API症歇,第一個(gè)接口是模塊X調(diào)用模塊Z的入端接口郎笆,第二個(gè)接口是模塊Z調(diào)用模塊Y的出端接口。

重構(gòu)的第二步是把模塊轉(zhuǎn)化為獨(dú)立的服務(wù)忘晤,出端和入端的接口使用IPC機(jī)制的代碼實(shí)現(xiàn)宛蚓,你最有可能需要通過(guò)模塊 Z 結(jié)合 Microservice Chassis framework來(lái)處理諸如服務(wù)發(fā)現(xiàn)這樣的橫切關(guān)注點(diǎn)。

一旦你提取了某個(gè)模塊设塔,你就擁有了另一個(gè)可以獨(dú)立于單體應(yīng)用和其他服務(wù)來(lái)開發(fā)凄吏、部署、擴(kuò)展的新服務(wù),你甚至可以從頭重寫這個(gè)服務(wù)痕钢; 在這種狀況下图柏,API代碼集成單體和微服務(wù),變成了用以轉(zhuǎn)換兩種領(lǐng)域模型的anti-corruption層任连。每次你提取一個(gè)模塊蚤吹,你就又向微服務(wù)的方向邁出一步,隨著時(shí)間的推移随抠,單體應(yīng)用將會(huì)縮水裁着,你也會(huì)擁有更多的微服務(wù)。

總結(jié)

從一個(gè)現(xiàn)存應(yīng)用遷移到微服務(wù)的過(guò)程是應(yīng)用現(xiàn)代化的一種形式拱她,你不應(yīng)該以從頭完全重寫的方式把現(xiàn)存應(yīng)用變?yōu)槲⒎?wù)二驰,相反的,你應(yīng)該逐步的把應(yīng)用重構(gòu)為一系列的微服務(wù)椭懊。你可以使用三種策略:使用微服務(wù)實(shí)現(xiàn)新的功能诸蚕;把表現(xiàn)層從業(yè)務(wù)邏輯和數(shù)據(jù)訪問(wèn)組件中拆分出來(lái);把單體應(yīng)用中的現(xiàn)有模塊轉(zhuǎn)化為服務(wù)氧猬。隨著時(shí)間推移背犯,微服務(wù)的數(shù)量將會(huì)增長(zhǎng),你團(tuán)隊(duì)的敏捷性和開發(fā)速度也會(huì)提升盅抚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末漠魏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妄均,更是在濱河造成了極大的恐慌柱锹,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丰包,死亡現(xiàn)場(chǎng)離奇詭異禁熏,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)邑彪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門瞧毙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人寄症,你說(shuō)我怎么就攤上這事宙彪。” “怎么了有巧?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵释漆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我篮迎,道長(zhǎng)男图,這世上最難降的妖魔是什么示姿? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮享言,結(jié)果婚禮上峻凫,老公的妹妹穿的比我還像新娘。我一直安慰自己览露,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布譬胎。 她就那樣靜靜地躺著差牛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堰乔。 梳的紋絲不亂的頭發(fā)上偏化,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音镐侯,去河邊找鬼侦讨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛苟翻,可吹牛的內(nèi)容都是我干的韵卤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼崇猫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼沈条!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起诅炉,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蜡歹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后涕烧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體月而,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年议纯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了父款。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡痹扇,死狀恐怖铛漓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鲫构,我是刑警寧澤浓恶,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站结笨,受9級(jí)特大地震影響包晰,放射性物質(zhì)發(fā)生泄漏湿镀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一伐憾、第九天 我趴在偏房一處隱蔽的房頂上張望勉痴。 院中可真熱鬧,春花似錦树肃、人聲如沸蒸矛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)雏掠。三九已至,卻和暖如春劣像,著一層夾襖步出監(jiān)牢的瞬間乡话,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工耳奕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绑青,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓屋群,卻偏偏與公主長(zhǎng)得像闸婴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谓晌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容