NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成
本篇内容属于非实用性(拿来即用)介绍,如对框架设计没兴趣的朋友,请略过。
快一个月没有写博文了,最近忙着两件事;
一:阅读刘墉先生的《说话的魅力》,以一种微妙的,你我大家都会经常遇见的事物,来建议说话的“艺术和魅力”,对于我们从事软件开发、不太善于沟通和表达的朋友来说,也算是一项软技能了,推荐喜欢阅读的朋友有时间阅读,给你不一样的阅读体验。
二:编写基于Net Core的Rpc框架。之前有朋友说如何将Rpc等整个体系集成到dotnet框架中,我想这篇博文会给你一个答案。
哦,对了,我不建议直接将代码直接复制下来然后去运行的朋友,因为这样你达不到学习的目的,也违背了笔者的初衷。谢谢理解。
一:简单回顾一下之前的介绍
继续贴上之前的一张图片
根据上面图,服务化原理可以分为3步:
-
服务端启动并且向注册中心发送服务信息,注册中心收到后会定时监控服务状态(常见心跳检测);
-
客户端需要开始调用服务的时候,首先去注册中心获取服务信息;
-
客户端创建远程调用连接,连接后服务端返回处理信息;
第3步又可以细分,下面说说远程过程调用的原理:
目标:客户端怎么调用远程机器上的公开方法
-
服务发现,向注册中心获取服务(这里需要做的有很多:拿到多个服务时需要做负载均衡,同机房过滤、版本过滤、服务路由过滤、统一网关等);
-
客户端发起调用,将需要调用的服务、方法、参数进行组装;
-
序列化编码组装的消息,这里可以使用json,也可以使用xml,也可以使用protobuf,也可以使用hessian,几种方案的序列化速度还有序列化后占用字节大小都是选择的重要指标,对内笔者建议使用高效的protobuf,它基于TCP/IP二进制进行序列化,体积小,速度快。
-
传输协议,可以使用传统的IO阻塞传输,也可以使用高效的nio传输(Netty);
-
服务端收到后进行反序列化,然后进行相应的处理;
-
服务端序列化response信息并且返回;
-
客户端收到response信息并且反序列化;
至于C类和S类之间的通信方式,是采用RPC还是采用RESTful,读者可以参考之前的介绍,根据实际业务进行决定
https://www.cnblogs.com/SteveLee/p/service_discovery_and_service_governance.html
二:DotEasy.Rpc框架介绍
单论Rpc框架市场,且不论Java上的Spring Boot和Spring Cloud这样大名鼎鼎的开源框架,目前Net上的Rpc整合性框架确实并不多,我们Net程序员也要混口饭吃,不能总被Java甩掉好几条街吧。
言归正传,一个远程过程调用,会涉及到如下几个方面的技术点(功能):
-
路由转发:当服务部署在多个节点上时,调用方需要知道自己的目标服务在什么地方。
-
通信协议:当管道存在,还需要在管道的两端建立处理程序(宿主),以处理管道中的数据包。DotEasy.Rpc基于DotNetty进行通信处理和协议实现。
-
动态生成:我们知道,基于二进制的RPC传输,每当新增接口,或修改接口,都需要生成相关协议的protobuf文件(或 thrift 文件),本框架基于protobuf-net的传输框架和Rosyln的预生成,动态生成相关的CS文件。
-
运行时代理:本框架采用一次请求创建一个客户端的模式,进行S端的服务请求,本框架基于Rosyln运行时创建客户端代理。
-
接口扫描:需要实现多个接口的添加和注册,本框架采用Attribute特性来扫描接口,并添加到相关的注册中心,比如consul或etcd。
2.1 解决方案介绍:
整体解决方案不做过多介绍,相信单词的词义已经表达了这个项目的作用。
小插曲:笔者曾用Easy.Rpc做为项目的主库名称,但上传到nuget后才发现,原来也有名为easy.rpc的包,不过笔者并没找到这个开源作者的网站,无赖之下,想到“点”这个词,也是dotnet的dot开头部分,索性干脆也叫DotEasy了吧。
笔者的目的,是想通过这个框架(或类库集),来简化微服务的部署和开发,让希望从事微服务NET开发的朋友不再找不到从何入手的窘境。
在Nuget.org上能直接下载编译过的包,地址:
https://www.nuget.org/packages/DotEasy.Rpc/,推荐使用这种方式进行安装。
如果喜欢研究源码,笔者同样也贴上地址:
https://github.com/steveleeCN87/doteasy.rpc,不过源码不包含任何依赖,如果编译中出现版本问题,可联系笔者。目前Github和Nuget上就放上了DotEasy.Rpc核心库和DotEasy.Rpc.Consul扩展包,etcd和entry还在测试阶段,就不方便拿出来献丑了。o(∩_∩)o 哈哈
当然,也欢迎广大爱好开源的朋友加入,共同为NET开源项目做贡献。
2.2 主项目介绍:
Attributes:用于标注该接口为某一特性的方法体,当系统通过Microsoft.Extensions.DependencyInjection自动构建成功后,框架将自动扫描接口上标注过[RpcTagBundle]的接口,形成目标接口列表,以供下面的方法调用。
Core:该核心分为Server和Client以及核心通用三个部分组成:
Client:主要用于通过Ip地址远程调用的方法Invoke实现,以及远程服务端的检查检查实现。
Communally:通用方法库,包括唯一ID生成器(用于标识每次请求所产生的唯一客户端)、通用对象转换器(将复杂对象转换为喜欢默认对象)、异常处理器、序列化生成器。
Server:提供服务宿主,服务执行者、服务入口处理、服务管理、服务定位、服务管理工厂的接口及默认实现。
Proxy:运行时预生成及客户端动态代理模组的接口和方法实现。
Routing:提供地址定位、服务描述、服务路由的接口和方法实现。
Transport:基于protobuf-net和dotnettey构建的二进制序列化、和通信管道和宿主的接口和实现。
所有主要类均已接口的形式提供接口名称,和已默认实现的具体方法体(虚方法),方便在这个基础上进行扩展和重写。
2.3 主项目接口
本节简单介绍一下DotEasy.Rpc主框架的接口的作用。
Attribute: |---RpcTagBundleAttribute.cs Core: |---Client: |-------Address: |-----------IAddressResolver.cs |-------IRemoteInvokeService.cs |---Server: |-------IServiceEntryFactory.cs |-------IServiceEntryLocate.cs |-------IServiceEntryManager.cs |-------IServiceEntryProvider.cs |-------IServiceExecutor.cs |-------IServiceHost.cs Proxy: |---IServiceProxyFactory.cs |---IServiceProxyGenerater.cs Routing: |---IServiceRouteFactory.cs |---IServiceRouteManager.cs Transpor