分布式部署_业务模块化打造单体和分布式部署同步支持方案
我在2019年中國(guó).NET開(kāi)發(fā)者峰會(huì)上為大家分享了我們的微服務(wù)電商安全工程實(shí)踐,那次會(huì)議分享的高清錄播已經(jīng)上傳到我的騰訊課堂,大家可以通過(guò)底部的小程序打開(kāi)直接觀看(復(fù)習(xí))。
在大會(huì)上跟大家提到,我們當(dāng)時(shí)只有4個(gè)人的創(chuàng)業(yè)團(tuán)隊(duì)。追求的是一個(gè)既可以單體部署,又可以進(jìn)行分布式部署的架構(gòu)方式。我們需要同時(shí)滿足云上SaaS部署(流量偏大)和私有部署(流量小,看重服務(wù)器成本)。當(dāng)然這種架構(gòu)方式我們也是經(jīng)過(guò)好幾次的框架迭代才實(shí)現(xiàn)的,框架暫時(shí)沒(méi)有開(kāi)源的打算,但是現(xiàn)在利用ABP VNext的幾個(gè)核心組件已經(jīng)完全可以方便的實(shí)現(xiàn)業(yè)務(wù)拼接組裝,同時(shí)實(shí)現(xiàn)單體和分布式部署。今天我將這種架構(gòu)風(fēng)格推薦給所有中小企業(yè)。
微服務(wù)架構(gòu)再理解
組織結(jié)構(gòu)的重要性?
人們?cè)谡劦轿⒎?wù)的時(shí)候必須會(huì)提到康威定律:“Communication dictates design(組織溝通方式?jīng)Q定系統(tǒng)設(shè)計(jì))”如果大家想更詳細(xì)的了解一下這個(gè)定律可以自己百度一下。但也許因?yàn)樗嵌?#xff0c;所以大家總把它說(shuō)的很玄乎,導(dǎo)致我們一下子很難真正理解到它的精髓。當(dāng)然這很大的原因其實(shí)在于我們從技術(shù)的角度出發(fā)是不能理解組織結(jié)構(gòu)對(duì)企業(yè)效率的重要性
微軟的現(xiàn)任CEO 薩蒂亞·納德拉,執(zhí)掌微軟的第一件事情就是對(duì)組織結(jié)構(gòu)的調(diào)整。在下面的圖中你可以看到以前大家是如何看待微軟的組織結(jié)構(gòu)的, 騰訊這兩年動(dòng)不動(dòng)就做事業(yè)部的調(diào)整也是出于這個(gè)考量?
任何的組織架構(gòu)之所有存在必然有其特殊性, 蘋果的絕對(duì)中心化那個(gè)時(shí)候能成功是因?yàn)橹行氖菃滩妓?#xff0c;現(xiàn)在中心靈魂人物沒(méi)有了,這種組織結(jié)構(gòu)還適用嗎?
既然在微服務(wù)架構(gòu)中"康威定律"被如此廣泛的引用,我就用大白話給大家解釋一下:“如果你是一個(gè)團(tuán)隊(duì)在一起維護(hù)好幾十個(gè)服務(wù),那你們就沒(méi)有必要用微服務(wù)架構(gòu)。”
一個(gè)服務(wù)一個(gè)團(tuán)隊(duì)
請(qǐng)大家記住上面的這個(gè)鐵律,如果是整個(gè)團(tuán)隊(duì)維護(hù)很多微服務(wù),哪怕是要用這些微服務(wù)拼成多個(gè)產(chǎn)品,那也不是微服務(wù)的最佳實(shí)踐。微服務(wù)強(qiáng)調(diào):一個(gè)服務(wù)一個(gè)完整團(tuán)隊(duì)(這個(gè)團(tuán)隊(duì)中包括產(chǎn)品開(kāi)發(fā)和測(cè)試) 。
微服務(wù)按DDD中的界限上下文來(lái)進(jìn)行拆分之后, 每一個(gè)服務(wù)都可以為這個(gè)領(lǐng)域業(yè)務(wù)的客戶提供最小化服務(wù),直到業(yè)務(wù)做到足夠復(fù)雜,某些業(yè)務(wù)長(zhǎng)大成為另一個(gè)獨(dú)立的上下文。這也完全符合敏捷和精益創(chuàng)業(yè)的思路。
充分授權(quán)小團(tuán)隊(duì)
一個(gè)服務(wù)一個(gè)團(tuán)隊(duì)還不能完全發(fā)揮這種架構(gòu)的威力,這個(gè)團(tuán)隊(duì)需要充分的授權(quán)。任正非說(shuō):“讓聽(tīng)得見(jiàn)炮火的人指揮戰(zhàn)斗”就是這個(gè)原因。大部分情況下直接和客戶打交道的前線最了解實(shí)際情況,知道客戶要什么以及如何去改進(jìn)產(chǎn)品。微服務(wù)架構(gòu)將組織結(jié)構(gòu)拆分之后,每個(gè)團(tuán)隊(duì)都可以集中力量解決自己團(tuán)隊(duì)所在領(lǐng)域內(nèi)客戶最關(guān)心的問(wèn)題,快速做也改進(jìn),快速發(fā)布將改進(jìn)送到客戶面前拿到正確的反饋。所以“每個(gè)服務(wù)獨(dú)立部署,獨(dú)立交付” 如此重要。?
中小企業(yè)不建議采用微服務(wù)架構(gòu)
資源不夠,最嚴(yán)重緊缺的就是產(chǎn)品經(jīng)理。沒(méi)有人去正確、快速地從用戶那里拿到反饋來(lái)快速改進(jìn)產(chǎn)品。最壞的情況可能用更快的速度堆了更多不需要也不那么正確的“功能” 。?
資源不夠,即使我們使用k8s降低和解除了很多運(yùn)維的功能,依舊還有配置中心、分布式追蹤、和集中日志的問(wèn)題解決的不是很好。這是一個(gè)很“重”的話題。?
資源不夠,這是一個(gè)永恒的話題, 孫子兵法以及很多戰(zhàn)略思想中都提到要集中兵力,中小企業(yè)的資源只夠集中優(yōu)勢(shì)資源優(yōu)先解決關(guān)鍵問(wèn)題,企圖想要快速把所有問(wèn)題都解決到最后基本都是失敗。?
利用模塊化打造單體與分布式都適用的架構(gòu)
中小企業(yè)愿意去深度微服務(wù)架構(gòu)的兩個(gè)初衷:
希望最大化避免重復(fù)開(kāi)發(fā),降低開(kāi)發(fā)成本?
防止將來(lái)業(yè)務(wù)做大要整體重構(gòu)
但是實(shí)施微服務(wù)框架會(huì)給企業(yè)帶來(lái)比較高的運(yùn)維成本,即使在使用K8S的情況下依然會(huì)比單體的運(yùn)維成本要高出很多。并且如果是屬于客戶訂制化項(xiàng)目需要部署到客戶現(xiàn)場(chǎng),維護(hù)費(fèi)用會(huì)更高。
業(yè)務(wù)模塊化可以讓團(tuán)隊(duì)把特定的業(yè)務(wù)封裝在一個(gè)模塊內(nèi),由多個(gè)業(yè)務(wù)模塊組裝完成一個(gè)系統(tǒng) 。比如我們常見(jiàn)的租戶、用戶、商品、論壇、博客、訂單、客戶等等。
業(yè)務(wù)模塊化如果部署成分布式那就是微服務(wù)架構(gòu),需要面對(duì)同樣的挑戰(zhàn)。如果部署成單體那將可以收獲以下好處
服務(wù)器成本更低?
不需要考慮服務(wù)治理(比如:服務(wù)發(fā)現(xiàn)與注冊(cè)、分布式追蹤等)
不需要考慮分布式配置中心
當(dāng)然,由于我們同時(shí)需要考慮兼容分布式部署。所以以下問(wèn)題還是一樣的
由于數(shù)據(jù)庫(kù)按模塊獨(dú)立,數(shù)據(jù)一致性依舊是一個(gè)挑戰(zhàn)(實(shí)在不得已集中提供一些面向報(bào)表庫(kù)的查詢服務(wù)也是可以接受的)?
不允許跨模塊join數(shù)據(jù)查詢,所以復(fù)雜數(shù)據(jù)報(bào)表展示也同樣需要找到相應(yīng)的解決辦法
模塊拆分原則
微服務(wù)拆分的大部份原則依舊適用
一個(gè)業(yè)務(wù)模塊對(duì)應(yīng)一個(gè)數(shù)據(jù)庫(kù),不能直接查另一個(gè)業(yè)務(wù)模塊的數(shù)據(jù)庫(kù)
模塊之間的調(diào)用通過(guò)抽象契約接口來(lái)完成?
模塊之間互相依賴只能依賴于抽象契約
模塊項(xiàng)目模板?
abp默認(rèn)的項(xiàng)目模板中將DDD也引入進(jìn)來(lái),但是由于應(yīng)用DDD對(duì)大多數(shù)開(kāi)發(fā)者來(lái)說(shuō)依舊是一個(gè)問(wèn)題。所以我推薦的項(xiàng)目模板中沒(méi)有引入DDD領(lǐng)域?qū)嶓w和領(lǐng)域服務(wù)的概念。也比較簡(jiǎn)單,只包括兩層:
ModuleName.Contracts 契約層
Module 實(shí)現(xiàn)層?
契約層
契約層中主要包括ApplicationService接口和DTO。
實(shí)現(xiàn)層
實(shí)現(xiàn)層主要是ApplicationServer的實(shí)現(xiàn)以及數(shù)據(jù)庫(kù)的Entity。如果你對(duì)DDD有一定的理解的話可以把這里理解為失血模型的領(lǐng)域分層 。在ApplicationService中通過(guò)倉(cāng)儲(chǔ)IRepository來(lái)完成領(lǐng)域?qū)嶓wEntity的持久化操作。需要注意的是這里不是簡(jiǎn)單的BLL和DAL三層架構(gòu)的思路,而是DDD領(lǐng)域分層中的六邊形架構(gòu)。
你可以在我的github上找到demo源碼:https://github.com/jessetalk/Galaxy (請(qǐng)一定要切換到abp分支,master分支是grpc的demo)?
模塊間調(diào)用/通信?
遵循“依賴于接口而不依賴于實(shí)現(xiàn)”原則。業(yè)務(wù)模塊化之后,各個(gè)模塊之間的通信通過(guò)契約接口來(lái)完成。
在我們的場(chǎng)景中,OrderService在創(chuàng)建訂單時(shí)需要使用到IProductService的查詢接口,那么Galaxy.Order項(xiàng)目需要添加Galaxy.Product.Contacts的引用。
private IProductService productService { get; set; }public OrderService(IProductService productService){ this.productService = productService;}public async TaskGetAsync(string id){ var items = await this.productService.GetListAsync(new ProductQueryDto());????var?task?=?await?Task.Run(()?=>????????????????????????{ Thread.Sleep(100);???????return?new?OrderDto()?{?Id?=?id,?OrderNo?=?"1234",?ProductItems?=?items?}; }); return task;}單體部署?
單獨(dú)創(chuàng)建一個(gè)Api項(xiàng)目,通過(guò)nuget引用所有業(yè)務(wù)模塊包。通過(guò)對(duì)外暴露模塊內(nèi)的ApplicationService來(lái)實(shí)現(xiàn)后端的業(yè)務(wù)處理。
各個(gè)模塊之間由于注入的都是本地類,所以模塊之間的調(diào)用也會(huì)是本地方法調(diào)用。
分布式部署
在分布式部署的場(chǎng)景下,需要為每一個(gè)業(yè)務(wù)模塊建立一個(gè)對(duì)應(yīng)的api項(xiàng)目,并將對(duì)應(yīng)的業(yè)務(wù)模塊實(shí)現(xiàn)包引入到項(xiàng)目。我們?cè)谏厦娴哪K間通信上講到了具體模塊之間的調(diào)用是通過(guò)抽象接口來(lái)完成的,所以在分布式部署的情況下需要注入一個(gè)遠(yuǎn)程代理來(lái)替代原來(lái)的本地調(diào)用。?
比如我們可以實(shí)現(xiàn)一個(gè)ProductServiceProxy,并將它注入到OrderService中。但如果是這樣,我們需要為每一個(gè)業(yè)務(wù)模塊都實(shí)現(xiàn)一個(gè)Proxy模塊。好消息是ABP VNext為我們實(shí)現(xiàn)了動(dòng)態(tài)客戶客戶端代理。
關(guān)鍵點(diǎn)
ABP 動(dòng)態(tài)客戶端代理
ABP提供的動(dòng)態(tài)客戶端代理功能,可以讓我們只需要添加一行代碼即擁有通過(guò) http實(shí)現(xiàn)遠(yuǎn)程模塊調(diào)用的功能 。?
[DependsOn(typeof(AbpAspNetCoreMvcModule))][DependsOn(typeof(AbpAutofacModule), typeof(GalaxyOrderModule))]public class GalaxyOrderWebModule : AbpModule{ public override void ConfigureServices(ServiceConfigurationContext context) { //創(chuàng)建動(dòng)態(tài)客戶端代理 context.Services.AddHttpClientProxies(typeof(GalaxyProductContractModule).Assembly, remoteServiceConfigurationName: "ProductStore"); }}ABP框架按約定式的方式默認(rèn)注冊(cè)服務(wù)實(shí)例,所以如果項(xiàng)目添加了對(duì)Galaxy.Product模塊的依賴則ProductService會(huì)自動(dòng)成為IProductService的實(shí)現(xiàn)(即本地方法調(diào)用)。? 如果在模塊配置手動(dòng)添加了HttpClientProxies則會(huì)自動(dòng)為IProductService添加一個(gè)動(dòng)態(tài)的實(shí)現(xiàn)(采用http的方式調(diào)用遠(yuǎn)程服務(wù))。
關(guān)于如何配置遠(yuǎn)程服務(wù)的地址可以參考abp官方文檔(abp.io)。?
ABP動(dòng)態(tài)Controller?
大量使用業(yè)務(wù)模塊化的時(shí)候,單體的情況下所有的Controller都在單體的那個(gè)api項(xiàng)目中,如果我們要轉(zhuǎn)成微服務(wù)的方式部署則需要把原來(lái)在單體中的Controller都轉(zhuǎn)移到對(duì)應(yīng)的微服務(wù)api項(xiàng)目中。如果要同時(shí)在這兩種架構(gòu)下切換則每添加一個(gè)Action都需要在兩個(gè)地方都做對(duì)應(yīng)的調(diào)整 。
ABP提供的動(dòng)態(tài)Controller功能,支持通過(guò)ApplicationService直接暴露成API Controller。這樣我們就可以只寫業(yè)務(wù)的契約接口和本地的實(shí)現(xiàn), 在對(duì)應(yīng)的API項(xiàng)目中只需要引用對(duì)應(yīng)業(yè)務(wù)模塊的nuget包即可。
我們只需要在order api項(xiàng)目的web module中將對(duì)應(yīng)業(yè)務(wù)模塊添加到 ConventionalControllers即可。
[DependsOn(typeof(AbpAspNetCoreMvcModule))][DependsOn(typeof(AbpAutofacModule), typeof(GalaxyOrderModule))]public class GalaxyOrderWebModule : AbpModule{ public override void ConfigureServices(ServiceConfigurationContext context) { Configure(options => { options.ConventionalControllers.Create(typeof(GalaxyOrderModule).Assembly); }); }}ABP會(huì)將ApplicationService中的所有公有方法按照約定自動(dòng)生成Action,具體的生成規(guī)則可以參考abp相關(guān)的文檔。當(dāng)然你也可以在方法上加Route或者HttpVerb的標(biāo)簽來(lái)定制路由。
以上是我們?cè)贠rder的API項(xiàng)目中,只需要把Order相關(guān)的實(shí)現(xiàn)暴露為Web API。如果想通過(guò)一個(gè)API項(xiàng)目把所有的業(yè)務(wù)模塊都通過(guò)web api 暴露出來(lái),也只需要多添加一行代碼。
public class GalaxyWebModule : AbpModule{ public override void ConfigureServices(ServiceConfigurationContext context) { Configure(options => { options.ConventionalControllers.Create(typeof(GalaxyOrderModule).Assembly); options.ConventionalControllers.Create(typeof(GalaxyProductModule).Assembly);???? }); }}由此在Swagger文檔中即可以看到Product和Order兩個(gè)模塊的Web API。
也就是通過(guò)這種方式,我們只需要開(kāi)發(fā)相關(guān)的業(yè)務(wù)模塊然后通過(guò)動(dòng)態(tài)Controller的方式來(lái)靈活控制是進(jìn)行單體部署還是分布式部署。也許你已經(jīng)發(fā)現(xiàn)了,這種情況下我們沒(méi)有Controller層,也就意味著我們所有的邏輯都需要寫在ApplicationService層,包括驗(yàn)證等。
結(jié)尾
在這種架構(gòu)風(fēng)格下,你可以很靈活的決定系統(tǒng)的部署方式。?既沒(méi)有必要被技術(shù)捆綁,也可以進(jìn)行最大化的復(fù)用同時(shí)免除未來(lái)業(yè)務(wù)快速增長(zhǎng)的后顧之憂。
由于篇幅有限,如果有描述不清或者疑問(wèn)的地方歡迎給我留言。希望這些實(shí)踐能給廣大中小企業(yè)的研發(fā)團(tuán)隊(duì)一些啟發(fā)。?我將繼續(xù)關(guān)注中小企業(yè)信息化以及產(chǎn)品研發(fā)中的技術(shù)架構(gòu)、團(tuán)隊(duì)管理、運(yùn)維等領(lǐng)域。如果你有相關(guān)的問(wèn)題或者新思路,歡迎溝通?:)?
這是關(guān)于中小企業(yè)產(chǎn)品研發(fā)體系建設(shè)的第二篇,你也可以查看我的上一篇《中小企業(yè)團(tuán)隊(duì)敏捷產(chǎn)品開(kāi)發(fā)流程最佳實(shí)踐》
我已將去年2019年中國(guó).NET開(kāi)發(fā)者峰會(huì)上為大家的分享上傳到我的騰訊課堂,以及之前為大家錄制的《ASP.NET Core核心模塊》 以及《.Net Core ON K8S快速入門》 兩個(gè)系列都可以免費(fèi)加入。?
總結(jié)
以上是生活随笔為你收集整理的分布式部署_业务模块化打造单体和分布式部署同步支持方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux命令入门篇(linux命令入门
- 下一篇: 怎么修改提交git是的用户名_git 修