微服務(wù):如何拆分服務(wù)?
在微服務(wù)的落地中,第一步就需要進(jìn)行微服務(wù)的拆分,服務(wù)的拆分很困難也很重要,本文就講講怎么進(jìn)行服務(wù)的拆分。
技術(shù)發(fā)展到現(xiàn)在,還沒(méi)有一個(gè)具體的,設(shè)計(jì)完善的標(biāo)準(zhǔn)方法來(lái)完成服務(wù)的拆分,服務(wù)的拆分是一門(mén)技術(shù)更是一門(mén)藝術(shù)。
對(duì)于服務(wù)的拆分,有兩種情況 :
1、從零開(kāi)始開(kāi)發(fā)新的產(chǎn)品,采用微服務(wù)架構(gòu),進(jìn)行服務(wù)拆分。
2、將現(xiàn)有的單體架構(gòu)的產(chǎn)品重構(gòu)成微服務(wù)架構(gòu),進(jìn)行服務(wù)拆分。
如果做的是 ToB 業(yè)務(wù),最終在企業(yè)內(nèi)部私有化部署落地,那么在大多數(shù)的場(chǎng)景下,微服務(wù)拆分后系統(tǒng)的復(fù)雜度和引發(fā)的新問(wèn)題會(huì)大于帶來(lái)的好處。
隨著業(yè)務(wù)的發(fā)展,產(chǎn)品需要進(jìn)行 SaaS 化改造,團(tuán)隊(duì)也引入多種技術(shù)棧,進(jìn)行微服務(wù)的拆分應(yīng)該就是勢(shì)在必行了。所以下面介紹的是怎樣將現(xiàn)有單體架構(gòu)拆分成微服務(wù)。
服務(wù)的拆分不是看代碼量或是工程的大小,而是要根據(jù)當(dāng)前業(yè)務(wù)的情況、團(tuán)隊(duì)的情況綜合考慮,還是拿零代碼平臺(tái)作為例子。
零代碼平臺(tái)中有菜單、流程、表單、頁(yè)面等模型,這些模型各自都能獨(dú)立成一個(gè)服務(wù),但前期為了快速交付,可以都放到一個(gè)工程中,但在代碼組織和架構(gòu)層面,為了后續(xù)的拆分,可以在邏輯和上進(jìn)行隔離,物理文件可以用目錄來(lái)區(qū)分,整體還是在一個(gè)大的工程中,如下圖:
服務(wù)的拆分的一個(gè)最大的作用就是解耦,但并不是說(shuō)一定要拆開(kāi)才是解耦,在一個(gè)工程中,合理地使用面向?qū)ο蟮囊恍┰瓌t,比如依賴(lài)倒置、接口隔離等,也能做到解耦。
平臺(tái)的功能在不斷地迭代,現(xiàn)在需要添加 BI 模塊,整個(gè)架構(gòu)也調(diào)整為支持多租戶(hù)模式,同時(shí)也需要開(kāi)發(fā)應(yīng)用商城,將零代碼平臺(tái)推上互聯(lián)網(wǎng),構(gòu)建一個(gè)應(yīng)用生態(tài),用戶(hù)可以直接安裝應(yīng)用或者將自己的應(yīng)用發(fā)布到應(yīng)用商城中。這里添加的 BI 和應(yīng)用商城就可以作為一個(gè)單獨(dú)的服務(wù),而原來(lái)的整個(gè)零代碼平臺(tái)可以先作為一個(gè)大的服務(wù)存在,修改后的架構(gòu)圖如下:
上面的例子是從全局的維度來(lái)考慮應(yīng)該怎樣去拆分,不一定對(duì),但以我目前的認(rèn)知和現(xiàn)有的場(chǎng)景來(lái)看,我認(rèn)為是適合的。
具體到一個(gè)特定的服務(wù),最基本的要求是具有能訪(fǎng)問(wèn)的 API , 并且可以獨(dú)立部署,至于數(shù)據(jù)庫(kù)是獨(dú)立還是跟其他服務(wù)共用,也是需要具體問(wèn)題具體分析,如果存在較多的跨服務(wù)的查詢(xún)操作,建議多服務(wù)共用一個(gè)數(shù)據(jù)庫(kù)。
服務(wù)與服務(wù)之間需要做到高內(nèi)聚低耦合,如果因?yàn)槠渌?wù)的變更導(dǎo)致需要頻繁更新你的服務(wù),或者說(shuō)你的服務(wù)的一個(gè)小的改動(dòng)會(huì)導(dǎo)致很多其他的服務(wù)要進(jìn)行同步修改,那么說(shuō)明服務(wù)之間的耦合性太高,拆分了享受不到微服務(wù)帶來(lái)的好處,反倒是將缺點(diǎn)無(wú)限放大了。所以在拆分服務(wù)時(shí)要遵循兩個(gè)原則:
1、通用功能,使用共享庫(kù),比如工具類(lèi),提取成 NuGet 包或者 Maven 包,在服務(wù)中進(jìn)行引用;
2、業(yè)務(wù)相關(guān)的公共部分,使用單獨(dú)的服務(wù),提供 API 的方式供其他服務(wù)調(diào)用。
每個(gè)服務(wù)都可以使用不同的架構(gòu)和技術(shù)棧來(lái)實(shí)現(xiàn),有一種推薦的做法就是使用六邊形架構(gòu),六邊形架構(gòu)在一些 DDD 的書(shū)籍和微服務(wù)的書(shū)籍中都有提到,下面是一張六邊形架構(gòu)的架構(gòu)圖:
六邊形架構(gòu)也稱(chēng)為端口適配器架構(gòu),可以替代傳統(tǒng)的三層,解決三層架構(gòu)的一些弊端。端口和適配器都分為入站和出站。
- 入站適配器:通常就是對(duì)外的 RestAPI,通過(guò)調(diào)用入站端口來(lái)處理外部的請(qǐng)求,也可以是消息隊(duì)列的消費(fèi)者,進(jìn)行一些事件的監(jiān)聽(tīng),來(lái)處理異步業(yè)務(wù),當(dāng)接收到消息時(shí)也是調(diào)用入站端口來(lái)進(jìn)行處理。
- 入站端口:業(yè)務(wù)服務(wù)對(duì)外暴露的公有方法。
- 出站適配器:出站適配器實(shí)現(xiàn)出站接口,調(diào)用外部的服務(wù)來(lái)實(shí)現(xiàn)一個(gè)完整的業(yè)務(wù)邏輯,出站適配器也可以是消息隊(duì)列的生產(chǎn)者。
- 出站端口:出站端口是一組方法的接口定義,提供一種規(guī)范,供出站適配器來(lái)實(shí)現(xiàn)。
舉一個(gè)例子:在零代碼平臺(tái)中,表單上拖一個(gè)控件保存后,最后的效果是列表上也會(huì)有這一列了,而表單和列表屬于兩個(gè)獨(dú)立的服務(wù),按照六邊形架構(gòu),調(diào)用關(guān)系如下圖:
六邊形架構(gòu)一個(gè)最大的好處就是將業(yè)務(wù)邏輯和適配器中包含的展示層和數(shù)據(jù)訪(fǎng)問(wèn)層的邏輯分離開(kāi),實(shí)現(xiàn)了解耦。
學(xué)習(xí)微服務(wù),我覺(jué)得有必要同時(shí)學(xué)習(xí)領(lǐng)域驅(qū)動(dòng)開(kāi)發(fā)(DDD),微服務(wù)是一種架構(gòu)風(fēng)格,DDD 是具體的架構(gòu)設(shè)計(jì)方法,互相配合能夠更好地落地,因?yàn)椋?/p>
1、DDD 中子域和限界上下文的概念可以對(duì)應(yīng)到微服務(wù)中的服務(wù)。
2、微服務(wù)中一個(gè)服務(wù)可以由一個(gè)團(tuán)隊(duì)進(jìn)行開(kāi)發(fā),DDD 的一個(gè)領(lǐng)域模型也是建議由一個(gè)獨(dú)立的團(tuán)隊(duì)負(fù)責(zé)。
進(jìn)行服務(wù)拆分后,之前在一個(gè)進(jìn)程內(nèi)就能完成的事情,現(xiàn)在需要在進(jìn)程間進(jìn)行通信了,有關(guān)進(jìn)程間通信后面再繼續(xù)分享。
零代碼現(xiàn)在越來(lái)越火熱,通過(guò)高度的抽象,將基礎(chǔ)設(shè)施、重復(fù)性的工作作為平臺(tái)本身的能力提供,讓用戶(hù)只用關(guān)注業(yè)務(wù),這其實(shí)也是另一個(gè)層面的解耦和拆分。