业务模块化打造单体和分布式部署同步支持方案

我在2019年中国.NET开发者峰会上为大家分享了我们的微服务电商安全工程实践,那次会议分享的高清录播已经上传到我的腾讯课堂,大家可以通过底部的小程序打开直接观看(复习)。

在大会上跟大家提到,我们当时只有4个人的创业团队。追求的是一个既可以单体部署,又可以进行分布式部署的架构方式。我们需要同时满足云上SaaS部署(流量偏大)和私有部署(流量小,看重服务器成本)。当然这种架构方式我们也是经过好几次的框架迭代才实现的,框架暂时没有开源的打算,但是现在利用ABP VNext的几个核心组件已经完全可以方便的实现业务拼接组装,同时实现单体和分布式部署。今天我将这种架构风格推荐给所有中小企业。

微服务架构再理解

组织结构的重要性 

人们在谈到微服务的时候必须会提到康威定律:“Communication dictates design(组织沟通方式决定系统设计)”如果大家想更详细的了解一下这个定律可以自己百度一下。但也许因为它是定律,所以大家总把它说的很玄乎,导致我们一下子很难真正理解到它的精髓。当然这很大的原因其实在于我们从技术的角度出发是不能理解组织结构对企业效率的重要性

微软的现任CEO 萨蒂亚·纳德拉,执掌微软的第一件事情就是对组织结构的调整。在下面的图中你可以看到以前大家是如何看待微软的组织结构的, 腾讯这两年动不动就做事业部的调整也是出于这个考量 

任何的组织架构之所有存在必然有其特殊性, 苹果的绝对中心化那个时候能成功是因为中心是乔布斯,现在中心灵魂人物没有了,这种组织结构还适用吗?

既然在微服务架构中"康威定律"被如此广泛的引用,我就用大白话给大家解释一下:“如果你是一个团队在一起维护好几十个服务,那你们就没有必要用微服务架构。”

一个服务一个团队

请大家记住上面的这个铁律,如果是整个团队维护很多微服务,哪怕是要用这些微服务拼成多个产品,那也不是微服务的最佳实践。微服务强调:一个服务一个完整团队(这个团队中包括产品开发和测试) 。

微服务按DDD中的界限上下文来进行拆分之后, 每一个服务都可以为这个领域业务的客户提供最小化服务,直到业务做到足够复杂,某些业务长大成为另一个独立的上下文。这也完全符合敏捷和精益创业的思路。

充分授权小团队

一个服务一个团队还不能完全发挥这种架构的威力,这个团队需要充分的授权。任正非说:“让听得见炮火的人指挥战斗”就是这个原因。大部分情况下直接和客户打交道的前线最了解实际情况,知道客户要什么以及如何去改进产品。微服务架构将组织结构拆分之后,每个团队都可以集中力量解决自己团队所在领域内客户最关心的问题,快速做也改进,快速发布将改进送到客户面前拿到正确的反馈。所以“每个服务独立部署,独立交付” 如此重要。 

中小企业不建议采用微服务架构

资源不够,最严重紧缺的就是产品经理。没有人去正确、快速地从用户那里拿到反馈来快速改进产品。最坏的情况可能用更快的速度堆了更多不需要也不那么正确的“功能” 。 

资源不够,即使我们使用k8s降低和解除了很多运维的功能,依旧还有配置中心、分布式追踪、和集中日志的问题解决的不是很好。这是一个很“重”的话题。 

资源不够,这是一个永恒的话题, 孙子兵法以及很多战略思想中都提到要集中兵力,中小企业的资源只够集中优势资源优先解决关键问题,企图想要快速把所有问题都解决到最后基本都是失败。 

利用模块化打造单体与分布式都适用的架构

中小企业愿意去深度微服务架构的两个初衷:

  • 希望最大化避免重复开发,降低开发成本 

  • 防止将来业务做大要整体重构

但是实施微服务框架会给企业带来比较高的运维成本,即使在使用K8S的情况下依然会比单体的运维成本要高出很多。并且如果是属于客户订制化项目需要部署到客户现场,维护费用会更高。

业务模块化可以让团队把特定的业务封装在一个模块内,由多个业务模块组装完成一个系统 。比如我们常见的租户、用户、商品、论坛、博客、订单、客户等等。

业务模块化如果部署成分布式那就是微服务架构,需要面对同样的挑战。如果部署成单体那将可以收获以下好处

  • 服务器成本更低 

  • 不需要考虑服务治理(比如:服务发现与注册、分布式追踪等)

  • 不需要考虑分布式配置中心

当然,由于我们同时需要考虑兼容分布式部署。所以以下问题还是一样的

  • 由于数据库按模块独立,数据一致性依旧是一个挑战(实在不得已集中提供一些面向报表库的查询服务也是可以接受的) 

  • 不允许跨模块join数据查询,所以复杂数据报表展示也同样需要找到相应的解决办法

模块拆分原则

  • 微服务拆分的大部份原则依旧适用

  • 一个业务模块对应一个数据库,不能直接查另一个业务模块的数据库

  • 模块之间的调用通过抽象契约接口来完成 

  • 模块之间互相依赖只能依赖于抽象契约

模块项目模板 

abp默认的项目模板中将DDD也引入进来,但是由于应用DDD对大多数开发者来说依旧是一个问题。所以我推荐的项目模板中没有引入DDD领域实体和领域服务的概念。也比较简单,只包括两层:

  • ModuleName.Contracts 契约层

  • Module 实现层 

契约层

契约层中主要包括ApplicationService接口和DTO。

实现层

实现层主要是ApplicationServer的实现以及数据库的Entity。如果你对DDD有一定的理解的话可以把这里理解为失血模型的领域分层 。在ApplicationService中通过仓储IRepository来完成领域实体Entity的持久化操作。需要注意的是这里不是简单的BLL和DAL三层架构的思路,而是DDD领域分层中的六边形架构。

你可以在我的github上找到demo源码:https://github.com/jessetalk/Galaxy (请一定要切换到abp分支,master分支是grpc的demo) 

模块间调用/通信 

遵循“依赖于接口而不依赖于实现”原则。业务模块化之后,各个模块之间的通信通过契约接口来完成。

在我们的场景中,OrderService在创建订单时需要使用到IProductService的查询接口,那么Galaxy.Order项目需要添加Galaxy.Product.Contacts的引用。

private IProductService productService { get; set; }
public OrderService(IProductService productService)
{this.productService = productService;
}
public async Task<OrderDto> GetAsync(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;
}

单体部署 

单独创建一个Api项目,通过nuget引用所有业务模块包。通过对外暴露模块内的ApplicationService来实现后端的业务处理。

各个模块之间由于注入的都是本地类,所以模块之间的调用也会是本地方法调用。

分布式部署

在分布式部署的场景下,需要为每一个业务模块建立一个对应的api项目,并将对应的业务模块实现包引入到项目。我们在上面的模块间通信上讲到了具体模块之间的调用是通过抽象接口来完成的,所以在分布式部署的情况下需要注入一个远程代理来替代原来的本地调用。 

比如我们可以实现一个ProductServiceProxy,并将它注入到OrderService中。但如果是这样,我们需要为每一个业务模块都实现一个Proxy模块。好消息是ABP VNext为我们实现了动态客户客户端代理。

关键点

ABP 动态客户端代理

ABP提供的动态客户端代理功能,可以让我们只需要添加一行代码即拥有通过 http实现远程模块调用的功能 。 

[DependsOn(typeof(AbpAspNetCoreMvcModule))]
[DependsOn(typeof(AbpAutofacModule), typeof(GalaxyOrderModule))]
public class GalaxyOrderWebModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){//创建动态客户端代理context.Services.AddHttpClientProxies(typeof(GalaxyProductContractModule).Assembly, remoteServiceConfigurationName: "ProductStore");}
}

ABP框架按约定式的方式默认注册服务实例,所以如果项目添加了对Galaxy.Product模块的依赖则ProductService会自动成为IProductService的实现(即本地方法调用)。  如果在模块配置手动添加了HttpClientProxies则会自动为IProductService添加一个动态的实现(采用http的方式调用远程服务)。

关于如何配置远程服务的地址可以参考abp官方文档(abp.io)。 

ABP动态Controller 

大量使用业务模块化的时候,单体的情况下所有的Controller都在单体的那个api项目中,如果我们要转成微服务的方式部署则需要把原来在单体中的Controller都转移到对应的微服务api项目中。如果要同时在这两种架构下切换则每添加一个Action都需要在两个地方都做对应的调整 。

ABP提供的动态Controller功能,支持通过ApplicationService直接暴露成API Controller。这样我们就可以只写业务的契约接口和本地的实现, 在对应的API项目中只需要引用对应业务模块的nuget包即可。

我们只需要在order api项目的web module中将对应业务模块添加到 ConventionalControllers即可。

[DependsOn(typeof(AbpAspNetCoreMvcModule))]
[DependsOn(typeof(AbpAutofacModule), typeof(GalaxyOrderModule))]
public class GalaxyOrderWebModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){Configure<AbpAspNetCoreMvcOptions>(options =>                                   {options.ConventionalControllers.Create(typeof(GalaxyOrderModule).Assembly);});}
}

ABP会将ApplicationService中的所有公有方法按照约定自动生成Action,具体的生成规则可以参考abp相关的文档。当然你也可以在方法上加Route或者HttpVerb的标签来定制路由。

 

以上是我们在Order的API项目中,只需要把Order相关的实现暴露为Web API。如果想通过一个API项目把所有的业务模块都通过web api 暴露出来,也只需要多添加一行代码。

public class GalaxyWebModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){Configure<AbpAspNetCoreMvcOptions>(options =>{options.ConventionalControllers.Create(typeof(GalaxyOrderModule).Assembly);options.ConventionalControllers.Create(typeof(GalaxyProductModule).Assembly);});}
}

由此在Swagger文档中即可以看到Product和Order两个模块的Web API。

也就是通过这种方式,我们只需要开发相关的业务模块然后通过动态Controller的方式来灵活控制是进行单体部署还是分布式部署。也许你已经发现了,这种情况下我们没有Controller层,也就意味着我们所有的逻辑都需要写在ApplicationService层,包括验证等。

结尾

在这种架构风格下,你可以很灵活的决定系统的部署方式。 既没有必要被技术捆绑,也可以进行最大化的复用同时免除未来业务快速增长的后顾之忧。

由于篇幅有限,如果有描述不清或者疑问的地方欢迎给我留言。希望这些实践能给广大中小企业的研发团队一些启发。 我将继续关注中小企业信息化以及产品研发中的技术架构、团队管理、运维等领域。如果你有相关的问题或者新思路,欢迎沟通 :) 

这是关于中小企业产品研发体系建设的第二篇,你也可以查看我的上一篇《中小企业团队敏捷产品开发流程最佳实践》

我已将去年2019年中国.NET开发者峰会上为大家的分享上传到我的腾讯课堂,以及之前为大家录制的《ASP.NET Core核心模块》 以及《.Net Core ON K8S快速入门》 两个系列都可以免费加入。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/311333.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[蓝桥杯][基础练习VIP]FJ的字符串-递归

题目描述 FJ在沙盘上写了这样一些字符串&#xff1a; A1 “A” A2 “ABA” A3 “ABACABA” A4 “ABACABADABACABA” … … 你能找出其中的规律并写所有的数列AN吗&#xff1f; 输入 仅有一个数&#xff1a;N ≤ 26。 输出 请输出相应的字符串AN&#xff0c;以一个换行…

python编程加油_编程学习资料,中途加油站,c++/java/python/小程序/人工智能......等等等等...

资料仅供学习分享用&#xff0c;废话不多说&#xff0c;解压密码为&#xff1a;1024文件是切割压缩的&#xff0c;多个part的压缩包&#xff0c;大家需要先下载到本地在解压&#xff0c;直接百度云解压会提示压缩包损坏。------------------------------学习资料java&#xff1…

[蓝桥杯][算法提高VIP]开灯游戏-dfs

题目描述 有9盏灯与9个开关&#xff0c;编号都是1~9。 每个开关能控制若干盏灯&#xff0c;按下一次会改变其控制的灯的状态(亮的变成不亮&#xff0c;不亮变成亮的)。 具体如下&#xff1a; 第一个开关控制第二&#xff0c;第四盏灯&#xff1b; 第二个开关控制第一&#…

python爬虫百度贴吧代码大全_零基础写python爬虫之抓取百度贴吧代码分享

这里就不给大家废话了&#xff0c;直接上代码&#xff0c;代码的解释都在注释里面&#xff0c;看不懂的也别来问我&#xff0c;好好学学基础知识去&#xff01;# -*- coding: utf-8 -*-#---------------------------------------# 程序&#xff1a;百度贴吧爬虫# 版本&…

Asp.Net Core EndPoint 终结点路由工作原理解读

Asp.Net Core EndPoint 终点路由工作原理解读一、背景在本打算写一篇关于Identityserver4 的文章时候&#xff0c;却发现自己对EndPoint -终结点路由还不是很了解&#xff0c;故暂时先放弃了IdentityServer4 的研究和编写&#xff1b;所以才产生了今天这篇关于EndPoint (终结点…

[蓝桥杯][算法提高VIP]夺宝奇兵-dp

题目描述 在一座山上,有很多很多珠宝,它们散落在山底通往山顶的每条道路上,不同道路上的珠宝的数目也各不相同.下图为一张藏宝地图: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 ”夺宝奇兵”从山下出发,到达山顶,如何选路才能得到最多的珠宝呢?在上图所示例子中,按照5-> 7-> 8-&g…

迁移到其他机器_有赞大数据离线集群迁移实战

‍‍点击关注“有赞coder”获取更多技术干货哦&#xff5e;作者&#xff1a;郭理想 & 任海潮部门&#xff1a;数据中台一、背景有赞是一家商家服务公司&#xff0c;向商家提供强大的基于社交网络的&#xff0c;全渠道经营的 SaaS 系统和一体化新零售解决方案。随着近年来社…

C# 客户端内存优化分析

背景概述C# 开发客户端系统的时候&#xff0c;.net 框架本身就比较消耗内存资源,特别是xp 这种老爷机内存配置不是很高的电脑上运行,所以就需要进行内存上的优化&#xff0c;才能流畅的在哪些低端电脑上运行. 想要对C# 开发的客户端内存优化需要了解以下几个概念。虚拟内存这里…

xshell1分钟就会自动断_手术室自动门不能正常控制开关门维修案例

手术室自动门维修案例遵义市第五人民医院手术室的手术门。用户反映&#xff1a;不能正常控制开关门。一、原因分析&#xff1a;1.红外线安全传感器故障2.控制器故障3.直流电机故障4. 红外感应开关故障5.红外感应探头故障6.电源故障图1图2图3图4图5图6二、维修过程&#xff1a;1…

[蓝桥杯][基础练习VIP]芯片测试-思维

题目描述 有n块芯片&#xff0c;有好有坏&#xff0c;已知好芯片比坏芯片多。 每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时&#xff0c;能正确给出被测试芯片是好还是坏。而用坏芯片测试其他芯片时&#xff0c;会随机给出好或是坏的测试结果&#xff08;即此结果与…

.NET Core开发实战(第18课:日志框架:聊聊记日志的最佳姿势)--学习笔记(下)...

18 | 日志框架&#xff1a;聊聊记日志的最佳姿势除了使用 CreateLogger 指定 logger 的名称&#xff0c;实际上还可以借助容器来构造 logger&#xff0c;通常情况下我们会定义自己的类namespace LoggingSimpleDemo {public class OrderService{ILogger<OrderService> _lo…

[蓝桥杯][基础练习VIP]完美的代价-贪心

题目描述 回文串&#xff0c;是一种特殊的字符串&#xff0c;它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串&#xff0c;它不一定是回文的&#xff0c;请你计算最少的交换次数使得该串变成一个完美的回文串。 交换的定义是&#xff1a;交换两…

安卓手机 python控制_PyAndroidControl:使用python脚本控制你的安卓设备

有的时候玩游戏或者干什么想写写安卓的脚本&#xff0c;不过用 java 或者 kotlin 写图像处理什么的太麻烦了&#xff0c;按键精灵的脚本我也懒得学。adb 倒是可以&#xff0c;但是很多时候要用电脑&#xff0c;又有些不太方便。感觉现在云手机比较方便吧&#xff0c;比如说&…

《ASP.NET Core 微服务实战》送书结果公告

如何构建基于.NET Core和云环境下的微服务技术体系&#xff1f;的送书抽奖结果已经出来了&#xff1a;当前只有一位同学填写了地址。其他几位同学抓紧填写&#xff0c;3/9 日还没有完成填写将作废&#xff0c;奖品可是热门的《ASP.NET Core 微服务实战》。另外我公司商城上上线…

MarkDown的介绍

文章目录markdown是什么优点缺点代码高亮markdown是什么 markdown是一种标记语言&#xff0c;常用文字排版 优点 易读&#xff08;看起来很舒服&#xff09;&#xff0c;易写&#xff08;语法简单&#xff09;跨平台使用&#xff08;mac/win/linux等&#xff09;其他网站和软件…

科学家的假想-substr的妙用

题目背景 DNA是一个神奇的序列&#xff0c;在某科学家的研究中&#xff0c;他发现世界上存在某种病毒入侵到人体内会使人变成小怪兽&#xff0c;按目前技术来说&#xff0c;科学家还无法制造出正义的奥特曼来消灭小怪兽。 题目描述 某科学家收集了世界上几乎所有的DNA病毒&am…

2020 年 Service Mesh 技术展望

背景有外文指出&#xff0c;2020 年 Service Mesh 技术将有以下三大发展&#xff1a;快速增长的服务网格需求&#xff1b;Istio 很难被打败&#xff0c;很可能成为服务网格技术的事实标准&#xff1b;出现更多的服务网格用例&#xff0c;WebAssembly 将带来新的可能。针对 Serv…

搭积木-贪心

题目背景 最近的m天小明都去幼儿园陪小朋友们玩去了~ 题目描述 每个小朋友都拿到了一些积木&#xff0c;他们各自需要不同数量的积木来拼一些他们想要的东西。但是有的小朋友拿得多&#xff0c;有的小朋友拿得少&#xff0c;有些小朋友需要拿到其他 小朋友的积木才能完成他的…

python实现辗转相除法求最大公约数和最小公倍数

辗转相除法数学原理 辗转相除法也称欧几里得算法&#xff0c;是用来求两个正整数的最大公约数的算法。接下来我们用实例来解释一下。假如我们需要求12和21的最大公约数&#xff0c;用辗转相除法是这样实现的&#xff1a; 21 / 12 1 &#xff08;余 9&#xff09; 12 / 9 1&a…

登录系统_执照管理系统登录与执照转换操作指南

执照管理系统登录与执照转换操作指南注&#xff1a;本操作指南适用于所有已经在CCAR-R2执照管理系统中注册的人员(无论是否参加过考试&#xff0c;无论有无考试通过科目).已经在旧系统中完成注册的人员无需在新系统中再次注册。只有完成本指南中的有关操作&#xff0c;才能正常…