應(yīng)用模塊化系統(tǒng)設(shè)計(jì)原則避免微服務(wù)的操作復(fù)雜性屯曹。
已經(jīng)有很多地方說(shuō)過(guò)從單體應(yīng)用遷移到微服務(wù)。除了動(dòng)動(dòng)嘴皮子外惊畏,好像也不需要花費(fèi)很大的精力就能把單體應(yīng)用拆分為微服務(wù)恶耽。但是這種方式真的對(duì)你的組織是最好的選擇嗎?當(dāng)然也有很多缺點(diǎn)去維護(hù)一個(gè)混亂的單體應(yīng)用颜启。但是經(jīng)常有個(gè)醒目選擇被忽略:模塊化應(yīng)用開發(fā)偷俭。這篇文章,我們將探討這個(gè)并展示它與構(gòu)建微服務(wù)的關(guān)系缰盏。
Microservices for modularity
“有了微服務(wù)我們的團(tuán)隊(duì)終于可以獨(dú)立開發(fā)” 或者 “我們的單塊太復(fù)雜了涌萤,都拖慢我們了”淹遵。這些說(shuō)法僅僅是眾多理由中的一點(diǎn)導(dǎo)致開發(fā)團(tuán)隊(duì)開始使用微服務(wù)。另一個(gè)原因是需要擴(kuò)展性和彈性负溪。似乎開發(fā)者們渴望一個(gè)模塊化的方式進(jìn)行系統(tǒng)設(shè)計(jì)和開發(fā)透揣。模塊化在軟件開發(fā)里可以總結(jié)為三個(gè)原則:
- 強(qiáng)封裝: 在組建里隱藏實(shí)現(xiàn)細(xì)節(jié),降低不同部分的耦合性川抡。團(tuán)隊(duì)可以獨(dú)立工作來(lái)解耦部分系統(tǒng)辐真。
- 好的接口定義: 可能隱藏不了所有的,所以組件之間好的定義和穩(wěn)定的APIs 是必須的猖腕。一個(gè)組件可以被任何符合規(guī)范的接口替換拆祈。
- 顯示依賴: 擁有一個(gè)模塊化系統(tǒng)意味著完全不同的組件共同工作。最好有一個(gè)好的方式描述他們的關(guān)系倘感。
微服務(wù)應(yīng)該知道這些原則放坏。一個(gè)微服務(wù)可以通過(guò)很多方式實(shí)現(xiàn),只要為其他服務(wù)暴露了好的接口定義(經(jīng)常是REST API)老玛。它的實(shí)現(xiàn)細(xì)節(jié)在服務(wù)里面淤年,并且可以改變不會(huì)影響到系統(tǒng)和協(xié)調(diào)。各個(gè)服務(wù)的依賴通常在開發(fā)期間不是顯式的蜡豹,可能會(huì)導(dǎo)致服務(wù)在運(yùn)行期編排失敗麸粮。我們可以說(shuō)最后一個(gè)模塊化原則可以使用在大多數(shù)微服務(wù)架構(gòu)里。
所以镜廉,微服務(wù)遵循這些重要的模塊化原則弄诲,會(huì)有實(shí)實(shí)在在的好處:
- 團(tuán)隊(duì)可以獨(dú)立工作和擴(kuò)展。
- 微服務(wù)可以更下更專注娇唯,減少?gòu)?fù)雜性齐遵。
- 服務(wù)可以在內(nèi)部里改變或者替換,不影響全局塔插。
為什么不喜歡梗摇?好吧,只要你已經(jīng)從單塊應(yīng)用(雖然有點(diǎn)臃腫)到微服務(wù)的分布式應(yīng)用想许。就會(huì)帶來(lái)超級(jí)操作復(fù)雜性伶授。突然,你需要持續(xù)部署不同的服務(wù)(可能是容器化)流纹。新的問(wèn)題:服務(wù)發(fā)現(xiàn)糜烹,分布式日志,跟蹤等等∈現(xiàn)在可能就是分布式計(jì)算謬論疮蹦。接口的版本和配置管理成為了主要關(guān)心的。這個(gè)列表還將會(huì)繼續(xù)碉哑。
原來(lái)處理微服務(wù)連接有多復(fù)雜挚币,組合各個(gè)微服務(wù)的業(yè)務(wù)邏輯就有多復(fù)雜。為了使用微服務(wù)扣典,不能只是拆分單塊應(yīng)用妆毕。而在單體應(yīng)用代碼庫(kù)里的“面條代碼”是有問(wèn)題的,在這些問(wèn)題里改成微服務(wù)的網(wǎng)絡(luò)連接更痛苦贮尖。
模塊化選擇
這是否就意味這我們要么使用混亂的單體應(yīng)用笛粘,要么淹沒在微服務(wù)的復(fù)雜性里了嗎?模塊化可以通過(guò)其他手段實(shí)現(xiàn)湿硝。重要的是我們可以有效的在開發(fā)期間實(shí)現(xiàn)和定義邊界薪前。但是我們也可以通過(guò)創(chuàng)建好的結(jié)構(gòu)的單體應(yīng)用實(shí)現(xiàn)。當(dāng)然关斜,這意味著我們可以接受任何從編程語(yǔ)言里得到的幫助和開發(fā)組件定義模塊化原則示括。
比如,在Java里痢畜,有很多模塊化系統(tǒng)可以幫助結(jié)構(gòu)化應(yīng)用垛膝。OSGi是最著名的一個(gè),但是隨著Java 9的發(fā)布丁稀,原生模塊系統(tǒng)已經(jīng)加入到Java自己的平臺(tái)里吼拥。模塊化現(xiàn)在已經(jīng)是語(yǔ)言和平臺(tái)的一部分作為一等構(gòu)造。 Java模塊可以在其他模塊上表達(dá)依賴线衫,發(fā)布類實(shí)現(xiàn)的強(qiáng)封裝接口凿可。甚至Java平臺(tái)已經(jīng)可以使用新的Java模塊系統(tǒng)模塊化∈谡耍可以從Java 9 Modularity書里了解Java 9的模塊化枯跑。
其他語(yǔ)言也提供了相似的機(jī)制。比如JavaScript在ES2015里獲得了模塊系統(tǒng)矗积。在這之前,Node.js也為JavaScript后端提供了非標(biāo)準(zhǔn)的模塊化系統(tǒng)全肮。但是,作為一個(gè)動(dòng)態(tài)語(yǔ)言棘捣,JavaScript對(duì)于 執(zhí)行接口類型和模塊之間的封裝不是很強(qiáng)辜腺。你可以使用微軟的TypeScript獲得這塊的優(yōu)勢(shì)。.Net框架和Java一樣是強(qiáng)類型乍恐,但是還沒有一個(gè)直接和Java模塊系統(tǒng)相等的強(qiáng)封裝和程序集里的顯示依賴评疗。仍然,好的模塊化架構(gòu)可以通過(guò)控制反轉(zhuǎn)實(shí)現(xiàn)和創(chuàng)建邏輯關(guān)聯(lián)程序集茵烈。甚至C++都考慮在未來(lái)的修訂添加模塊化系統(tǒng)百匆。
當(dāng)你很想在你的開發(fā)平臺(tái)使用模塊化特性時(shí),可以像之前提到實(shí)現(xiàn)微服務(wù)的模塊化好處呜投。本質(zhì)上加匈,模塊系統(tǒng)越好存璃,在開發(fā)中就越有幫助。不同的團(tuán)隊(duì)解決不同的部分雕拼,只有定義好的接口是團(tuán)隊(duì)接觸的點(diǎn)纵东。仍然,部署時(shí)模塊都在同一個(gè)部署單元里啥寇。這樣可以防止大量的復(fù)雜性和部署與管理微服務(wù)相關(guān)聯(lián)的成本偎球。當(dāng)然,這意味著你不能再不同的技術(shù)棧里實(shí)現(xiàn)模塊辑甜。不過(guò)你的團(tuán)隊(duì)真的需要使用不同的技術(shù)棧嗎衰絮?
設(shè)計(jì)模塊
創(chuàng)建好的模塊和創(chuàng)建好的微服務(wù)都需要嚴(yán)格設(shè)計(jì)。一個(gè)模塊應(yīng)該塑造一個(gè)有界限的域的上下文磷醋。如果錯(cuò)誤的決定了微服務(wù)的邊界猫牡,代價(jià)是昂貴的。模塊邊界在模塊化應(yīng)用里是容易改變的邓线。類型系統(tǒng)和編譯器通常支持重構(gòu)模塊镊掖。重寫微服務(wù)邊界設(shè)計(jì)到很多內(nèi)部個(gè)人溝通防止不會(huì)再運(yùn)行時(shí)掛掉。說(shuō)實(shí)話褂痰,你有多少次在第一次的時(shí)候就能設(shè)定好邊界亩进,或者即使是第二次?
在許多方面缩歪,模塊在靜態(tài)類型語(yǔ)言里通常為定義好的接口提供好的構(gòu)造器归薛。調(diào)用一個(gè)其他模塊暴露出來(lái)的類型接口比調(diào)用微服務(wù)提供的REST端點(diǎn)更加健壯。REST + JSON是很常見的匪蝙,但畢竟在編譯檢查語(yǔ)法里不是一個(gè)好的互操作性方式主籍。而且通過(guò)網(wǎng)絡(luò)(反)序列化并不是免費(fèi)的,甚至更加黯淡逛球。更多的是千元,許多模塊系統(tǒng)允許你在其他模塊里傳遞你的依賴。當(dāng)這些依賴不合規(guī)颤绕,模塊系統(tǒng)會(huì)禁止它的幸海。而微服務(wù)之間的依賴只會(huì)在運(yùn)行時(shí)實(shí)現(xiàn),給調(diào)試系統(tǒng)帶來(lái)困難奥务。
模塊同樣在代碼所有權(quán)利是自然單位物独。團(tuán)隊(duì)可以在系統(tǒng)為一個(gè)或者多個(gè)模塊負(fù)責(zé)。唯一需要與其他團(tuán)隊(duì)分享的是他們模塊里的public API氯葬。在運(yùn)行期間挡篓,相對(duì)于微服務(wù),幾乎沒有隔離帚称。畢竟都運(yùn)行在同樣的進(jìn)程里官研。
沒有理由為什么一個(gè)單體里的模塊不能像好的微服務(wù)一樣擁有自己的數(shù)據(jù)秽澳。通過(guò)定義好的接口或者信息在模塊直接共享數(shù)據(jù),而不是同一個(gè)數(shù)據(jù)源戏羽。與微服務(wù)最大的不同是肝集,它都是在同一個(gè)進(jìn)程里。最終一致性問(wèn)題不應(yīng)該被低估蛛壳。在模塊里,最終一致性是成熟的策略選擇所刀⊙眉觯或者你可以只是邏輯地
分開數(shù)據(jù),但存在同一個(gè)數(shù)據(jù)源里并且仍然使用跨域事務(wù)浮创。對(duì)于微服務(wù)忧吟,沒有選擇:最終一致性是給定的并且你需要適應(yīng)。
什么時(shí)候你才需要微服務(wù)斩披?
所以到底什么時(shí)候適合轉(zhuǎn)向微服務(wù)溜族?直到現(xiàn)在,我們主要集中在如何通過(guò)模塊解決復(fù)雜性垦沉。對(duì)于這個(gè)煌抒,微服務(wù)和模塊化應(yīng)用都應(yīng)該解決。但是除了這個(gè)以外還有其他需要解決厕倍。
如果你的團(tuán)隊(duì)像Google或者Netflix的規(guī)模寡壮,完全可以擁抱微服務(wù)。你有能力去構(gòu)建你自己的平臺(tái)和工具讹弯,并且工程師們拒絕任何合理的單體方式况既。但是大多數(shù)的都沒有這個(gè)規(guī)模。即使你認(rèn)為你的團(tuán)隊(duì)有一天會(huì)成為十億級(jí)的獨(dú)角獸组民,從一個(gè)模塊化的單體應(yīng)用不會(huì)有傷害棒仍。
另一個(gè)適合使用微服務(wù)的理由是,不同的服務(wù)適合不同的技術(shù)棧實(shí)現(xiàn)臭胜。同樣莫其,你必須有規(guī)模來(lái)吸引人才在這些不同的堆棧并且保持這些平臺(tái)上運(yùn)行。
微服務(wù)可以獨(dú)立部署系統(tǒng)的不同部分耸三,有些在大多數(shù)模塊化平臺(tái)里很難甚至不可能榜配。隔離部署給系統(tǒng)添加了彈性和容錯(cuò)。此外吕晌,每個(gè)微服務(wù)的擴(kuò)展特性可能不同蛋褥。不同的微服務(wù)可以部署到合適的硬件上。雖然模塊化單體應(yīng)用也可以擴(kuò)展睛驳,但是所有的模塊一起擴(kuò)展烙心。這不總是最好的膜廊,但在實(shí)踐中,你可以通過(guò)這種方式走的很遠(yuǎn)淫茵。
總結(jié)
能找到一個(gè)中間項(xiàng)總是最好的選擇爪瓜。選擇這兩種的方式,最好是取決于環(huán)境匙瘪、組織和應(yīng)用本身铆铆。為什么不從模塊化應(yīng)用開始?你可以稍后遷往微服務(wù)丹喻。然后薄货,不是動(dòng)手清理單體應(yīng)用,你已經(jīng)有合理的模塊邊界碍论。不是獨(dú)家的選擇:你同樣可以使用模塊內(nèi)部構(gòu)造微服務(wù)谅猾。那么問(wèn)題來(lái)了,為什么微服務(wù)需要“微”鳍悠?
即使你離開單體應(yīng)用税娜,服務(wù)不需要小到不用維護(hù)。接著藏研,在服務(wù)里使用模塊化原則允許他們超過(guò)微服務(wù)的復(fù)雜性里擴(kuò)展敬矩。真正省成本的是減少架構(gòu)里的服務(wù)數(shù)量。模塊能幫助構(gòu)造和擴(kuò)展服務(wù)就像他們能幫助構(gòu)造一個(gè)單體應(yīng)用蠢挡。
如果你追求模塊化的好處谤绳,就不要把你自己局限于微服務(wù)里。探索進(jìn)程內(nèi)模塊化特性或你最喜歡的技術(shù)堆椞桓纾框架缩筛。你會(huì)加強(qiáng)你的模塊化設(shè)計(jì)能力,而不是不得不依賴于約定來(lái)避免面條代碼堡称。好好考慮你是否想成單微服務(wù)的復(fù)雜性瞎抛。有時(shí)候你不得不,但經(jīng)常你能找到更好的方式却紧。
轉(zhuǎn)自:https://www.oreilly.com/ideas/modules-vs-microservices