NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成...

本篇内容属于非实用性(拿来即用)介绍,如对框架设计没兴趣的朋友,请略过。 

快一个月没有写博文了,最近忙着两件事;

   一:阅读刘墉先生的《说话的魅力》,以一种微妙的,你我大家都会经常遇见的事物,来建议说话的“艺术和魅力”,对于我们从事软件开发、不太善于沟通和表达的朋友来说,也算是一项软技能了,推荐喜欢阅读的朋友有时间阅读,给你不一样的阅读体验。

640?wx_fmt=png

二:编写基于Net Core的Rpc框架。之前有朋友说如何将Rpc等整个体系集成到dotnet框架中,我想这篇博文会给你一个答案。

哦,对了,我不建议直接将代码直接复制下来然后去运行的朋友,因为这样你达不到学习的目的,也违背了笔者的初衷。谢谢理解。

 

一:简单回顾一下之前的介绍

继续贴上之前的一张图片

 

640?wx_fmt=png

 

根据上面图,服务化原理可以分为3步:

  1. 服务端启动并且向注册中心发送服务信息,注册中心收到后会定时监控服务状态(常见心跳检测);

  2. 客户端需要开始调用服务的时候,首先去注册中心获取服务信息;

  3. 客户端创建远程调用连接,连接后服务端返回处理信息;

 

  第3步又可以细分,下面说说远程过程调用的原理:

目标:客户端怎么调用远程机器上的公开方法

  1. 服务发现,向注册中心获取服务(这里需要做的有很多:拿到多个服务时需要做负载均衡,同机房过滤、版本过滤、服务路由过滤、统一网关等);

  2. 客户端发起调用,将需要调用的服务、方法、参数进行组装;

  3. 序列化编码组装的消息,这里可以使用json,也可以使用xml,也可以使用protobuf,也可以使用hessian,几种方案的序列化速度还有序列化后占用字节大小都是选择的重要指标,对内笔者建议使用高效的protobuf,它基于TCP/IP二进制进行序列化,体积小,速度快。

  4. 传输协议,可以使用传统的IO阻塞传输,也可以使用高效的nio传输(Netty);

  5. 服务端收到后进行反序列化,然后进行相应的处理;

  6. 服务端序列化response信息并且返回;

  7. 客户端收到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甩掉好几条街吧。

  言归正传,一个远程过程调用,会涉及到如下几个方面的技术点(功能):

  1. 路由转发:当服务部署在多个节点上时,调用方需要知道自己的目标服务在什么地方。

  2. 通信协议:当管道存在,还需要在管道的两端建立处理程序(宿主),以处理管道中的数据包。DotEasy.Rpc基于DotNetty进行通信处理和协议实现。

  3. 动态生成:我们知道,基于二进制的RPC传输,每当新增接口,或修改接口,都需要生成相关协议的protobuf文件(或 thrift 文件),本框架基于protobuf-net的传输框架和Rosyln的预生成,动态生成相关的CS文件。

  4. 运行时代理:本框架采用一次请求创建一个客户端的模式,进行S端的服务请求,本框架基于Rosyln运行时创建客户端代理。

  5. 接口扫描:需要实现多个接口的添加和注册,本框架采用Attribute特性来扫描接口,并添加到相关的注册中心,比如consul或etcd。

 

2.1 解决方案介绍:

640?wx_fmt=jpeg

  整体解决方案不做过多介绍,相信单词的词义已经表达了这个项目的作用。

  小插曲:笔者曾用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 主项目介绍:

640?wx_fmt=png

Attributes:用于标注该接口为某一特性的方法体,当系统通过Microsoft.Extensions.DependencyInjection自动构建成功后,框架将自动扫描接口上标注过[RpcTagBundle]的接口,形成目标接口列表,以供下面的方法调用。

Core:该核心分为Server和Client以及核心通用三个部分组成:

640?wx_fmt=png

  Client:主要用于通过Ip地址远程调用的方法Invoke实现,以及远程服务端的检查检查实现。

  Communally:通用方法库,包括唯一ID生成器(用于标识每次请求所产生的唯一客户端)、通用对象转换器(将复杂对象转换为喜欢默认对象)、异常处理器、序列化生成器。

  Server:提供服务宿主,服务执行者、服务入口处理、服务管理、服务定位、服务管理工厂的接口及默认实现。

Proxy:运行时预生成及客户端动态代理模组的接口和方法实现。

640?wx_fmt=png

Routing:提供地址定位、服务描述、服务路由的接口和方法实现。

640?wx_fmt=png

Transport:基于protobuf-net和dotnettey构建的二进制序列化、和通信管道和宿主的接口和实现。

640?wx_fmt=png

所有主要类均已接口的形式提供接口名称,和已默认实现的具体方法体(虚方法),方便在这个基础上进行扩展和重写。

 

2.3 主项目接口

本节简单介绍一下DotEasy.Rpc主框架的接口的作用。

640?wx_fmt=png

RpcTagBundleAttribute.cs:所有标记过[RpcTagBundle]特性的接口均会被扫描至doteasy.rpc框架中;

IAddressResolver.cs:地址解析器,提供IPv4地址解析作用,用于IServiceRouteFactory和IRemoteInvokeService定位操作;

IRemoteInvokeService.cs:远程调用服务接口,提供远程服务调用的关键接口,通过IServiceProxyFactory接口代理调用;

IServiceEntryFactory.cs:服务入口工厂接口,对全局服务入口的统一的工厂操作,例如添加,监听,移除,修改服务入口等;

IServiceEntryLocate.cs:服务入口定位接口,通过IAddressResolver过滤和解析,实现服务入口的定位;

IServiceEntryManager.cs:服务入口管理全局管理接口,功能同IServiceEntryFactory相似,但提供更多的服务管理操作,比如负载均衡(采用轮询实现);

IServiceEntryProvider.cs:服务入口提供者接口,一个简单的服务入口提供者程序;

IServiceExecutor.cs:执行服务方法接口,执行远程服务的IRemoteInvokeService;

IServiceHost.cs:服务宿主接口,DotNetty的服务宿主,类似own框架的自宿主程序,提供请求和响应操作;

IServiceProxyFactory.cs:服务代理工厂接口,客户端代理(预编译)的所有操作实现;

IServiceProxyGenerater.cs:服务代理生成接口,客户端代理(预编译)生成器;

IServiceRouteFactory.cs:服务路由工厂接口;

IServiceRouteManager.cs:服务路由全局管理接口;

ITransportMessageCodecFactory.cs:管道消息传输工厂接口;

ITransportMessageDecoder.cs:管道消息解码器接口;

ITransportMessageEncoder.cs:管道消息编码器接口;

IMessageListener.cs:管道消息监听接口,可实现一个消息的接受者和处理程序;

IMessageSender.cs:管道消息发送接口,可实现一个消息的发送者;

 

  通过上面的框架和㢟就能实现客户端到服务端的RPC通信了吗?当然不是,还需要服务注册中心(例如Consul,etcd,zookeeper)来实现。上面只是提供了路由转发,服务定位,客户端预编译的实现等等功能而已,而服务的注册并没提供,因为它不属于基础框架的范畴,笔者对zookeeper的笨重太反感(当然不是说它不好),而consul和etcd十分轻量级,特此又专门新增了两个项目:DotEasy.Rpc.Consul和DotEasy.Rpc.Etcd,用于实现不同注册中心的注册(获取)方法,和健康检测机制。

 

  当然,介绍Consul和Etcd如何实现不是本节的重点,DotEasy.Rpc这个框架的完全剖析也将在日后新开篇章中专门介绍如何去实现一个框架,想必大部分朋友关心的是这个框架能做什么,有什么样的功能,那么,接下来开始吧。

 

三:如何使用

本系列一直重复的那张图片,噼里啪啦噼里啪啦......此处省略三百字。绕来绕去,难以入手,正如上一篇有朋友推荐如何在Asp.net core中集成、等等。

功能和特性如下:

  1. Apache许可证2协议开放源代码;

  2. 统一组件装配和构造;

  3. 基于protobuf-net实现字节流序列化;

  4. 基于Rosyln的运行时客户端代理生成;

  5. 基于Rosyln的预生成的客户端代理;

  6. 基于DotNetty的传输信道;

  7. 支持客户端以轮询的方式实现负载平衡;

  8. Net Core结构及跨平台;

就这么点,不啰嗦,让我们开始做DEMO。

 

3.1 建立服务接口和服务实现

既然是服务,那么肯定需要以接口interface的方式实现对外暴露,并且,接口的实现不能和接口封装在同一个DLL中,不然还叫什么远程过程调用呢(RPC)呢,如果不了解什么叫接口,去翻一翻C#语言规范。

先定义一个接口,接口方法签名如下:

640?wx_fmt=png

很简单,不解释。

其中接口上有个重要特性叫[RpcTagBundle],该特性只允许标记在interface接口上,用于启动时方便框架扫描所有标有该特性的接口。 

在看实现类

640?wx_fmt=png

再次重申:注意两篇代码中的命名空间,就是两个不同的程序集(两个项目),千万不能以为笔者仅仅是为了区分而已。

 

3.2 建立asp.net core mvc应用程序

新建一个asp.net core mvc应用程序,模版默认webapi,添加一个控制器HeathController,当然,控制器名称你也可以自由发挥,键入如下代码:

640?wx_fmt=png

也十分简单,对外暴露一个路由地址为"api/Health"的API接口,提供GET方法,返回OK信息。

这个接口的作用是用于Consul对服务的健康状态检查回调地址,Consul可以基于HTTP做健康检查,也可以通过gRPC验证服务健康状态。

至此,一个WebApi就建立完成,对外不在通过HTTP做任何接口暴露。

接下来我们添加一个IApplicationBuilder的扩展,用于启动Rpc服务端,代码如下:

640?wx_fmt=png

(1):实例化一个BaseServer的服务类型,并使用IConfiguration作为参数。该BaseServer类是封装太DotEasy.Rpc.Entry中的一个实现,主要是简化调用者的代码构建能力,不然,截图一个部分源码瞧瞧

640?wx_fmt=png

框架的目的是简化编码工作,构建RPC实例也不例外,100多行的构建代码只用3行实现,偷懒者必备。

(2):调用一次RegisterEvent委托事件,用于将接口和实现注册到ServiceCollection容器中。

(3):启动这个RPC服务,其实方法内还有构建ServiceCollection容器等等一大堆方法,你可以自己实现,也可以问笔者要源码。

 

配置文件在哪儿,难道这样就可以了?

当然不是,我们还需要一个appsettings.json的默认配置文件,代码如下:

640?wx_fmt=png

这篇配置文件很容易理解,这里不再重复啰嗦的解释。

 

至此,一个寄宿于Asp.net core的rpc服务就这样搭建完成,可以启动随Consul启动看看。

友情提示:建议将Asp.net core的默认日志功能关闭,否则Consul会5秒发送一个健康检查请求过来,日志会慢慢的变得十分臃肿,ConfigureLogging((context, logging) => { logging.ClearProviders(); })即可移除Logging日志功能。当然,你也可以做其他修改,毕竟日志在项目中非常重要。

 

3.3 测试启动Consul和Asp.net core

consul如何启动这个,笔者就不再复述了吧,想必看过之前的文章,应该都会启动和使用consul了,截个图,喜悦一下

640?wx_fmt=png

3.1中的六个接口全被注册到consul服务中,不信,我们访问一个具体接口,看看meta信息。

640?wx_fmt=png

路由和服务均通过这个信息进行定位,我们可以知道,在127.0.0.1的9881端口上,可以访问名为“doteasy.rpc.interfaces.IUserService.Exists_id”的接口。当然,目前是没有任何验证机制的,下一篇会介绍RPC中的统一验证机制。

 

3.4 建立一个客户端

废话不多说,直接上代码:

640?wx_fmt=png

如你所见,我们就像在调用接口一样的去调用了RPC远程服务,中间的所有操作都是透明的,不需要关心的,唯一多了一句是Proxy<IUserService>();使用代理模式动态生成了RPC远程客户端,该操作又被笔者封装在了BaseClient中,一切都为了使用者简单。

 

3.5 跑跑客户端看看结果

640?wx_fmt=png

640?wx_fmt=png

注意加粗的文字,是否跟调用接口一样的结果呢,其他的调试日志目前请忽略。 

四:总结

这样,通过asp.net core + consul + doteasy.rpc便实现了一个简单的远程服务调用,你可以尝试部署到外网,看看是否是远程调用,当然,目前并没有任何的统一网关验证,所以,任何人的机器都可以调用。


原文地址:https://www.cnblogs.com/SteveLee/p/rpc_framework_easy.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

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

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

相关文章

花店橱窗布置(洛谷P1854)(动态规划)

传送门 文章目录解析问题代码解析 一道很正常的动态规划 dp[i][j]表示到第j个花瓶放了第j朵花的dp最优值 注意&#xff1a;是严格使第i朵放在j瓶 找到最优解递归输出即可 问题 又是初始化的问题&#xff01;&#xff01;&#xff01; 一开始把dp赋值成负无穷时落掉了j0的一行…

P4009 汽车加油行驶问题

题目描述&#xff1a; 题解&#xff1a; 看了很多题解&#xff0c;无论什么解法都绕不开分层图 在本题中加满油的车每次可以移动K步&#xff0c;那么我们就可以建立一个K1层的分层图&#xff0c;表示汽车油量k的状态&#xff08;油量0…k&#xff09;&#xff0c;然后根据题目…

.net core i上 K8S(五).netcore程序的hostip模式

正文上一章讲了pod的管理&#xff0c;今天再分享一个pod的访问方式1.Pod的HostIP模式Pod的HostIP模式&#xff0c;可以通过宿主机访问pod内的服务&#xff0c;创建yaml文件如下apiVersion: v1 kind: Pod metadata: name: netcore-podlabels:app: netcorepod spec:containers: …

状态压缩:枚举子集(最优组队)(ybtoj)(动态规划)

解析 很裸的状压dp 但是直接暴力的话状态2n,枚举2n 乘在一起会T诶 怎么办呢&#xff1f; 使用下面这个循环&#xff0c;就可以保证只会枚举当前状态s的子集 for(int i(s-1)&s;i;i(i-1)&s){........ }证明 举举例子就挺明显了 为什么不重不漏呢&#xff1f; 首先i肯…

【活动(深圳)】告别2018之12.22 大湾区.NET Meet 大会 ,同时有网络直播

今年的 Connect(); 主题更加聚焦开发者工具生产力、开源&#xff0c;以及无服务器&#xff08;Serverless&#xff09;云服务。Visual Studio 2019 AI 智能加持的 IntelliCode、实时代码协作共享 Live Share&#xff0c;.NET Core 3.0的预览版本附带了大量更新&#xff0c;旨在…

最短路径(状压dp)(ybtoj)

解析 “bug总有de完的一天” 头疼 暴力写的话本题显然复杂度是假的 有一个很好的思路优化时间复杂度 先用dp[k][i]表示**从第k个关键点到任意i点的最短路 跑k遍 SPFA或迪杰斯特拉 即可 然后转移时可以只考虑关键点 使状态转移数大大降低 细节 头真疼 边界条件&#xff1a; …

P2403 [SDOI2010]所驼门王的宝藏(强连通分量)(拓扑排序)

文章目录题目描述解析代码洛谷传送门题目描述 解析 看题目要求很容易想到强连通分量缩点加拓扑dp 但是问题在于存图 第一感就是和暴力和每个点连边 但那样无论点数和边数都很爆炸 随后我们发现这个图非常稀疏 所以我们可以只连有宝藏的点 然而这样边数会被一行横门这样的数据…

Xamarin.Forms之UserDialogs 重制版本

在 forms 里面&#xff0c;目前使用比较多的弹出组件是 Acr.UserDialogs &#xff0c;但是这个组件有些小问题&#xff0c;比如 loading .hide 会同时把 toast 给一起关掉&#xff0c;android 下的 toast 希望是 安卓原生的toast 样子&#xff0c;而不是 底部弹出一个横条&…

H.Minimum-cost Flow

H.Minimum-cost Flow 题目&#xff1a; 其实就是给出每条边的单位费用&#xff0c;q次查询&#xff0c;每次查询改变所有边的容量&#xff08;所有边容量一样&#xff09;&#xff0c;问最后流出1流量的最小花费是多少&#xff1f; 题解&#xff1a; 暴力做法肯定是每次询问…

eShopOnContainers 看微服务③:Identity Service

引言通常&#xff0c;服务所公开的资源和 API 必须仅限受信任的特定用户和客户端访问。那进行 API 级别信任决策的第一步就是身份认证——确定用户身份是否可靠。在微服务场景中&#xff0c;身份认证通常统一处理。一般有两种实现形式&#xff1a;基于API 网关中心化认证&#…

P2168 [NOI2015] 荷马史诗(哈夫曼编码树)

传送门 文章目录题目描述解析细节代码题目描述 解析 其实就是构造一棵树 另所有带权点都为叶子节点 其代价为权值与深度的乘积 求最小代价及最小代价下的最小深度 可以看成一开始有n棵小树 每次把k棵合并在一起 最后合成一棵大树就行了 每次合并的代价是k棵树的权值和 看到这…

B-Suffix Array

B-Suffix Array 题意&#xff1a; 一个字符串只含有a和b&#xff0c;先给出b数组的构造方式&#xff1a; 对于每个位置i来说&#xff1a; 如果存在一个位置j&#xff0c;使得j<i,且s[j] s[i],则b[i]i-j否则b[i]0 现在对字符串每个后缀都构造B数组&#xff0c;并按照字典…

线段树合并、分裂

基本概念&#xff1a; 如果需要维护许多个大小为 \(10^5\) 级别的多重集&#xff0c;可以看做给每一个多重集建立一棵线段树。线段树的合并、分裂就是多重集的累加、分开。 这里使用动态开点的方式存储线段树树。 如果一个节点为空&#xff0c;那么它的编号为 \(0\) 。 变量释义…

(神奇的)虚树(初步了解)

参考文献&#xff1a; 博文1 博文2 博文3 引入 在一类树上动态规划问题中,题目给出的询问往往包含树上的很多各节点,并保证总的点数规模小于某个值. 如果我们直接在整颗树上进行dp的话,时间复杂度与询问的次数有关,这显然是不可接受的,如果我们可以找到一种动态规划的方法,使…

P2048 [NOI2010] 超级钢琴(RMQ 贪心)

文章目录题目描述解析代码传送门题目描述 解析 首先&#xff0c;如果只有一个和弦&#xff0c;那么问题显然简单了 用前缀和结合ST表随便做做即可 然而 这次要求前k大的 怎么办呢&#xff1f; 参照之前有一道序列合并的做法 我们想到&#xff0c;可以先建一个优先队列&#xf…

微服务架构基础之Service Mesh

ServiceMesh(服务网格) 概念在社区里头非常火&#xff0c;有人提出 2018 年是 ServiceMesh 年&#xff0c;还有人提出 ServiceMesh 是下一代的微服务架构基础。那么到底什么是 ServiceMesh&#xff1f;它的诞生是为了解决什么问题&#xff1f;企业是否适合引入 ServiceMesh&…

P1081 [NOIP2012 提高组] 开车旅行(倍增)(动态规划)

洛谷传送门 文章目录题目描述解析代码题目描述 解析 利用倍增&#xff0c;设计dp慢慢敲即可。。。 注意距离累加在一起会爆int&#xff0c;需要ll 特判条件非常之复杂。。。 心力交瘁&#xff0c;就酱了 代码 #include <bits/stdc.h> using namespace std; #define ll…

dotnet core调试docker下生成的dump文件

最近公司预生产环境.net core应用的docker容器经常出现内存暴涨现象&#xff0c;有时会突然吃掉几个G,触发监控预警&#xff0c;造成容器重启。分析了各种可能原因&#xff0c;修复了可能发生的内存泄露&#xff0c;经测试本地正常&#xff0c;但是发到预生产还是会有内存暴涨现…

Quadratic Form

Quadratic Form 题意&#xff1a; 一个n * n 的正定矩阵和一个n维的向量b&#xff0c;现在找一个x1&#xff0c;x2&#xff0c;…xn满足以下条件&#xff1a; 求这个式子&#xff0c;最后输出P * Q-1 mod 998244353. 题解&#xff1a; 参考 线性代数学过n阶正定的实矩阵等…

8分钟学会Consul集群搭建及微服务概念

Consul介绍&#xff1a;Consul 是由 HashiCorp 公司推出的开源软件&#xff0c;用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案&#xff0c;Consul 的方案更“一站式”&#xff0c;内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Valu…