今天要厚着脸皮给大家推荐一个自己做的通信中间件——ServiceAnt,目前已经在我们团队的两个产品线上投入了使用。

ServiceAnt是什么


它最初的定位是ESB(企业服务总线),但目前还没有达到这个高度,主要是还是没有提供分布式的实现,有机会会补上。

现在它只能工作于进程内,与 Mediator 的角色非常类似。

可能有同学不知道 Mediator, Automapper 总该听过吧?它们的作者是一个人。

ServiceAnt 部分的设计也参考了 Mediator,当然还有别的一些框架,比如 Abp中的 EventBus, eShopOnContainer的 integation event 以及 NServiceBus

可能有人会问,通信中间件的作用是什么?这里我们先用现在火热的微服务场景来举个例子,假设我们拥有ABCDEF六个微服务,A需要与DE服务通信来获得某些信息,而B则是与EF,C与DF,D与AB,E与BC,F与AC。

那么它们之间的通信拓扑图将会是如下的样子:

看上去相当地混乱,对吧?

在真实的互联网应用中,拆分的服务数量和关联度多数都要比上面这张图更加复杂。

如果采用RESTful API 的方式来通信,这会造成每个服务都需要管理不同的多方连接信息,给开发带来了相当大的复杂度。

为了解决这样的问题,我们在其间引入了一个中介者的角色来负责分发请求,传递结果,这就是通信中间件。

引入之后的拓扑图如下:

无论你需要与多少方通信,最终你只需要告诉中间件:目标地址、通信内容以及通信模式(Pub Or Request,如果支持的话)。

而不需要关心是谁,以什么方式来处理通信内容,中间件会帮你处理好这些事情。

这样一来我们获得以下的优点:

  1. 解除了服务间的直接耦合,提高了扩展性
  2. 降低了开发的复杂度,避免管理通信相关的内容,如通信协议,安全性,以及监控等。

有同学忍不住要说了:你说的都是微服务啊,这些我都懂,比如SpringCloud就是这样的,你刚刚说过 ServiceAnt 还没有分布式的实现,那介绍微服务有锤子用啊?

别急,听我慢慢解释。我们知道在大型企业应用中都会把程序拆分为多个模块对吧?

把以上两图的ABCDEF视作模块,模块间的直接通信看作引用,就可以将把进程内的单体应用看作特别的“分布式”应用。

事实上,大多数设计良好的单体应用都具备清晰的业务模块边界,而如何让这些模块以更加灵活的方式协作完成业务逻辑是设计中需要仔细考量的一个点,通信中间件就是一种不错的解决方案。

现在大家应该对 ServiceAnt 是什么有点认识了吧。

注:上面关于模块如何划分,我们团队是采用的DDD,有兴趣的同学可以移步我的另一篇博文,里面分享了我们实践DDD的一些经验与基础架构。传送门点我

ServiceAnt 的现状


如上所述,目前 ServiceAnt 已经投入到我们团队所负责的两个线下产品线中使用,发现的坑也都填完了。

为了响应c#的开源氛围,我重构了一下原有的代码,并且补充了多版本的支持,然后上传到了Gihub上。

目前版本号:1.0

支持 .net 版本:.net 4.5、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();
}); // 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();
}); // 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();
}); 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#的开发者能拥有更好的待遇与更多的挑战,除了提升自己能力之外,多多贡献自己力量去推广它, 完善它的生态,让整个业界重新认识它,也不失为良策,对吧。

出处:https://www.cnblogs.com/RobotZero/p/8360973.html

ESB雏形 -- 项目企业服务总线初始的更多相关文章

  1. 几种ESB(企业服务总线)介绍

    ESB(Enterprise Service Bus,即企业服务总线)是传统中间件技术与XML.Web服务等技术结合的产物.ESB提供了网络中最基本的连接中枢,是构筑企业神经系统的必要元素. 企业服务 ...

  2. ESB(Enterprise Service Bus)企业服务总线介绍

    ESB(Enterprise Service Bus)企业服务总线介绍 ESB全称为Enterprise Service Bus,即企业服务总线.它是传统中间件技术与XML.Web服务等技术结合的产物 ...

  3. 企业服务总线(ESB)

    思考: 1.ESB的定义到底是什么?是一款产品还是一种架构模式? 2.ESB有何实际用处? 定义ESB 对于企业服务总线(Enterprise Service Bus),目前还没有公认的定义,根据供应 ...

  4. ESB企业服务总线到底是什么东西呢?

    顾名思义,企业服务总线(ESB)就是一条企业架构的总线,所有的企业服务都挂接到该总线上对外公布,企业服务总线负责管理服务目录,解析服务请求者的请求方法.消息格式,并对服务提供者进行寻址,转发服务请求. ...

  5. (转) ESB 企业服务总线基本内容概述

    ESB全称为Enterprise Service Bus,即企业服务总线. 它是传统中间件技术与XML.Web服务等技术结合的产物(SOAP协议= HTTP协议+ XML数据格式). ESB提供了网络 ...

  6. ERP_基于Oracle SOA的企业服务总线整合

    2015-01-01 Created By BaoXinjian

  7. 面向服务架构(SOA)和企业服务总线(ESB)

    http://www.cnblogs.com/shanyou/archive/2008/04/19/1161452.html 学习和研究在企业中实施面向服务架构(SOA),简单回顾SOA和ESB,重点 ...

  8. 关于ESB(企业服务总线)的学习笔记

    MQ(消息队列 message queues),它是一种应用程序对应用程序的通信方法.排队指的是应用程序通过队列来通信.队列的使用除去了接收和发送应用程序同时执行的要求. Web Sevice 技术, ...

  9. 在windows环境下部署nuxt项目(线上发布部署)

    因为公司项目需要兼容SEO,同时我们也一直希望能够真正的实现前后端分离,于是毫不犹豫的选择了nuxt. 话说要重构前后端分离真是一个大工程,由于各种原因我们团队花了近两年时间都没有完成,最近才又重启把 ...

随机推荐

  1. Problem B: 平面上的点——Point类 (II)

    Description 在数学上,平面直角坐标系上的点用X轴和Y轴上的两个坐标值唯一确定.现在我们封装一个“Point类”来实现平面上的点的操作. 根据“append.cc”,完成Point类的构造方 ...

  2. L304 What Is Death?

    How should we define the death of a person? Philosophers and physicians have long pondered this ques ...

  3. 字符界面的贪吃蛇--链表--C++

    前天看了下链表,由于平时对链表的使用不多,所以对链表的应用也没什么了解,所以想来想去,就想用链表实现一下贪吃蛇. 下面言归正传,先看效果图,再看代码,其他没有了! 图1: 图2: 代码: #inclu ...

  4. 2019-04-03-day025-异常与日志

    内容回顾 考试 6个小时 120分 (100+20) 15:00-18:00 笔试 60分 19:00-22:00 上机考试 40分 + 20分 60分及格不算附加题 简答题 读程序 简单编程 编程题 ...

  5. 2D转换下的zoom和transform:scale的区别

    一.什么是zoom 在我们做项目和查看别人的网页的时候总会在一些元素的样式里,看到有一个家伙孤零零的待在那里,它到底是谁呢? 它的名字叫zoom,zoom的意思是“变焦”,虽然在摄影的领域经常被提到, ...

  6. JAVA_概念01_跨域

    1.什么是跨域? 协议.域名.端口都相同是同域,否则是跨域. 服务器不允许ajax跨域获取数据 2.解决办法? ①jsonp :Jsonp不是一种数据格式,而json是一种数据格式,jsonp是用来解 ...

  7. 点击图片video全屏

    <!doctype html> <html> <head> <meta charset="utf-8" /> <title&g ...

  8. 河南省第四届ACM省赛(T1) 序号互换

    问题 A: 序号互换 时间限制: 1 Sec  内存限制: 128 MB难度1 题目描述 Dr.Kong设计了一个聪明的机器人卡多,卡多会对电子表格中的单元格坐标快速计算出来.单元格的行坐标是由数字编 ...

  9. python 模块基础 和常用的模块

    模块的定义 一个模块就是以.py结尾的python 文件,用来从逻辑上组织python代码.注意,模块名和变量名一样开头不能用数字,可以是双下划线和字母. 为什么要用模块? 将一些复杂的需要重复使用的 ...

  10. 【leetcode】344. Reverse String

    problem 344. Reverse String solution: class Solution { public: void reverseString(vector<char> ...