今天要厚着脸皮给你们推荐一个本身作的通讯中间件——ServiceAnt,目前已经在咱们团队的两个产品线上投入了使用。html
ServiceAnt是什么
它最初的定位是ESB(企业服务总线),但目前尚未达到这个高度,主要是仍是没有提供分布式的实现,有机会会补上。前端
如今它只能工做于进程内,与 Mediator 的角色很是相似。java
可能有同窗不知道 Mediator, Automapper 总该听过吧?它们的做者是一我的。git
ServiceAnt 部分的设计也参考了 Mediator,固然还有别的一些框架,好比 Abp 中的 EventBus, eShopOnContainer 的 integation event 以及 NServiceBus。github
可能有人会问,通讯中间件的做用是什么?这里咱们先用如今火热的微服务场景来举个例子,假设咱们拥有ABCDEF六个微服务,A须要与DE服务通讯来得到某些信息,而B则是与EF,C与DF,D与AB,E与BC,F与AC。web
那么它们之间的通讯拓扑图将会是以下的样子:面试
看上去至关地混乱,对吧?编程
在真实的互联网应用中,拆分的服务数量和关联度多数都要比上面这张图更加复杂。c#
若是采用RESTful API 的方式来通讯,这会形成每一个服务都须要管理不一样的多方链接信息,给开发带来了至关大的复杂度。api
为了解决这样的问题,咱们在其间引入了一个中介者的角色来负责分发请求,传递结果,这就是通讯中间件。
引入以后的拓扑图以下:
不管你须要与多少方通讯,最终你只须要告诉中间件:目标地址、通讯内容以及通讯模式(Pub Or Request,若是支持的话)。
而不须要关心是谁,以什么方式来处理通讯内容,中间件会帮你处理好这些事情。
这样一来咱们得到如下的优势:
- 解除了服务间的直接耦合,提升了扩展性
- 下降了开发的复杂度,避免管理通讯相关的内容,如通讯协议,安全性,以及监控等。
有同窗忍不住要说了:你说的都是微服务啊,这些我都懂,好比SpringCloud就是这样的,你刚刚说过 ServiceAnt 尚未分布式的实现,那介绍微服务有锤子用啊?
别急,听我慢慢解释。咱们知道在大型企业应用中都会把程序拆分为多个模块对吧?
把以上两图的ABCDEF视做模块,模块间的直接通讯看做引用,就能够将把进程内的单体应用看做特别的“分布式”应用。
事实上,大多数设计良好的单体应用都具有清晰的业务模块边界,而如何让这些模块以更加灵活的方式协做完成业务逻辑是设计中须要仔细考量的一个点,通讯中间件就是一种不错的解决方案。
如今你们应该对 ServiceAnt 是什么有点认识了吧。
注:上面关于模块如何划分,咱们团队是采用的DDD,有兴趣的同窗能够移步个人另外一篇博文,里面分享了咱们实践DDD的一些经验与基础架构。传送门点我
ServiceAnt 的现状
如上所述,目前 ServiceAnt 已经投入到咱们团队所负责的两个线下产品线中使用,发现的坑也都填完了。
为了响应c#的开源氛围,我重构了一下原有的代码,而且补充了多版本的支持,而后上传到了Gihub上。
目前版本号:1.0
支持 .net 版本:.net 4.五、net standard2.0
Github地址:点我进入
Github上有很是详细的文档,这里我只简单介绍,ServiceAnt 支持的两种工做方式:
1.Pub/Sub(发布/订阅)模式,使用这种模式你能够把它视做事件总线。
2.Req/Resp(请求/响应)模式,这种模式是咱们工做中使用最频繁的模式了吧,他跟普通的Http请求相似,发起一个请求而后能够由一个或多个处理函数(这些函数可能位于同一个模块也可能位于多个模块)来处理这个请求并返回结果。
ServiceAnt正在完善例子和英文文档,如今是起步阶段,并且线下应用的需求也较为简单,因此有不少功能都没有实现(好比重试机制,流量监控以及可视化仪表等等)。
若是你有这样的需求,欢迎在Issue上提出,我会在工做之余第一时间回复你。
为何会有ServiceAnt
原由是这样的,咱们团队在开发一个企业应用时采用了DDD,而后将咱们的业务逻辑拆分为了复数个限界上下文,每一个上下文低耦合高内聚的.
但不管再怎么低耦合,总会有一些高层次的交互,这些被称为“边界点”,一般在分布式部署中,咱们会选择Webapi 或者 WebServie 等远程通讯手段来进行交互
遗憾的是,咱们的应用是线下的,并发量也并不须要到集群这样重量级的解决方案,因此咱们使用Abp的插件加载机制为基础设施, 将每一个上下文都实现成了一个个独立的项目模块.
项目初期咱们使用 Abp 提供的事件总线做为模块之间交互的方式, 但它有一个很很差的地方是, 它的事件引用必须是显式的原对象引用。
这也就意味着,你为了在A模块中使用B模块发布的事件,你必须让两个上下文都引用这个事件对象,这显然加深了模块间的耦合。
在参考了Abp, Medirator, NServerBus以及微软的示例项目 EShopContainer 后,我决定本身实现一个服务总线, 它要具备如下特色:
- 支持以委托的方式注册处理函数
- 支持 Req/Resp 模式
- 事件的接收与发布对象是非引用的(指你能够在不一样模块间创建各自的事件类,只须要保证它们名称与结构相同便可)
因此ServiceAnt出现了, ServiceAnt 的初期目标是一个进程内的消息中介者, 后期有时间会逐步完善它。
Req/Resp 模式在上面已经介绍过了,可能不少同窗比较有疑问的地方是:以委托的方式注册处理函数这一点,请看下如下的代码。
static void Main(string[] args) { var serviceBus = InProcessServiceBus.Default; serviceBus.AddRequestHandler<TestRequest>((requestParam, handlerContext) => { Console.WriteLine($"Request Handler get value: {requestParam.RequestParameter}"); handlerContext.Response = "First handler has handled. \r\n"; return Task.FromResult(0); }); // it used when you do not want to create trigger class, you can handle it with a dynamic parameter serviceBus.AddDynamicRequestHandler("TestRequest", (eventParam, handlerContext) => { Console.WriteLine($"DynamicRequest Handler get value: {eventParam.RequestParameter}"); handlerContext.Response += "Second handler has handled. \r\n"; // set IsEnd flag to true then directly return response and ignore the rest handlers handlerContext.IsEnd = true; return Task.FromResult(0); }); // this handler will not be excuted serviceBus.AddRequestHandler<TestRequest>((requestParam, handlerContext) => { Console.WriteLine($"Third Request Handler get value: {requestParam.RequestParameter}"); handlerContext.Response += "Third handler has handled. \r\n"; return Task.FromResult(0); }); var publishEvent = new TestRequest() { RequestParameter = "HelloWorld" }; Console.WriteLine($"Send request parameter value: { publishEvent.RequestParameter }"); var response = serviceBus.Send<string>(publishEvent); Console.WriteLine("The response is : \r\n" + response); Console.ReadLine(); } class TestRequest : IRequestTrigger { public string RequestParameter { get; set; } }
这段代码是从Github上的示例代码上复制过来的,能够看到它的全部处理函数都是以匿名委托的方式注册的,而且演示了Req/Resp的管道工做方式。
Github上的介绍中也简单写了一些与其余相似组件的不一样之处,有兴趣的同窗能够自行查看。
写在最后的话
ServiceAnt 离最初所定位的ESB还有很长的一段路要走,但由于目前公司的主产品是线下的自助系统及其支撑系统,因此一直没有场景需求去开发支持分布式甚至是支持异构系统。
若是有哪些同窗项目正好有这样的场景又想使用 ServiceAnt,我很乐意与你一块儿分析需求而后完善 ServiceAnt 的功能,固然你也能够直接开发完以后发起PR给我。
目前互联网的天下都被 Java, NodeJs, PHP等占了大半江山,致使新出的 .Net Core 生存空间和生态都发展迟缓,虽然我不介意使用其余语言,但我更看好 .net core 和 c# 这个组合一些天生优点(固然也有一点本身使用c#较多的情怀在里面,呵呵),特别是它的设计和性能表现均可以称得上后起之秀了,特别是2.0以后。
关于 .net core 我这里就很少言了,已经偏题了,随手转发一下最近在博客看到的关于.net core 特性的文章吧。
只但愿经过为c#的开源生态多贡献一些东西,尽本身绵薄之力去改善它的生态。
这样作不只是为了你们其实也是为了本身,如今平均待遇偏低不说,更可气的是整个大环境都让人有些难受。
好比如今一个彻底没干过编程,毕业五年的销售,通过某些培训机构培训Java半年,简历包装一下,背背面试题,混进一个互联网公司,他的待遇就要比不少.net的同等经验工做者高。
为何?就是由于业界不少人都以为 .net 仍是那个没法作互联网,封闭的老式技术,因此大环境下一提及线上应用就是 SprintBoot, SSM, SSH,致使目前来看待遇更好,挑战更多的互联网公司都下意识选择了Java。
我曾与公司的Java组同事作过一些集成应用,本身也私下鼓捣过 SprintBoot,也了解过Java多数主流框架。
同时本身如今是web组的牵头人,更多的时候是在作前端的技术工做,对比使用过的这些技术,我以为如今的 c# 在线上应用方向的能力被不少人都看低了。
c#语言的优点,我只说一点,ES2015添加的箭头函数早在c#3.0就已经有了,它就是lambda表达式,而java是在 java8以后才有的,c#语言因为诞生较晚因此吸收不少前车可鉴,加上设计者也很厉害,因此c#相较其余语言会更加优雅。Nuget也一点不比Maven,Npm差。IDE我就很少说了,用过Eclipse和Vs都懂,最新的Idea没用过,但这里很少作评论,只是想说其余语言有的,c# 都不会差。
加之如今微软大力推进开源与跨平台,咱们有理由相信c#是能够在线上应用争得一席之地的。
因此若是你想做为一个c#的开发者能拥有更好的待遇与更多的挑战,除了提高本身能力以外,多多贡献本身力量去推广它, 完善它的生态,让整个业界从新认识它,也不失为良策,对吧。