Redola.Rpc 集成 Consul 服务发现

Redola.Rpc 解决了什么问题?

Redola.Rpc 是一个使用 C# 开发的 RPC 框架,代码开源在 GitHub 上。目前版本仅支持 .NET Framework 4.6 以上版本,未来待系统稳健后再考虑移植 .NET Standard 和 .NET Core。

Redola.Rpc 在 0.3.2 版本中,尝试解决几个 RPC 设计问题:

  • 我是谁?(Local Actor)

  • 如何告诉别人我是谁?(Actor Directory)

  • 我提供什么服务?(Service Catalog Provider)

  • 如何告诉别人我提供什么服务?(Service Directory)

  • 我需要的服务在哪里?(Service Discovery)

  • 如何调用该服务?(Service Dynamic Proxy)

  • 如何找到该服务?(Actor Directory)

  • 如何发消息给该服务?(Remote Actor)

Actor 是什么?

Redola 定义的 Actor 模型代表着一个通信节点,使用 ActorIdentity 描述,包括节点类型 Type、节点名称 Name、节点地址 Address、节点端口 Port。

Actor 与 Actor 之间是基于 TCP Socket 通信的,Actor 并不区分 TCP 的 Server/Client 端,它将 Server 和 Client 封装在底层,为上层应用提供更便捷的传输定义和调用接口。Actor 模型提供了面向通道 Channel 的双工通道,可以接收来自对端的消息,也可以发送消息给对端。

Actor 收发的消息是面向二进制数组的,它不关心具体发送的是什么消息,也不关心序列化格式。Actor 使用 ActorFrameHeader 定义传输消息头,Header 携带消息体长度。

Actor 一旦建立连接,生成的 Channel 通道会自动进行 KeepAlive 双向保活机制。通过 Actor 服务发现,可以与任意的 Actor 进行通信,无需再配置对端节点地址和端口。并且,针对相同 Type 的 Actor,还可以实现消息分发的负载均衡功能。

RPC 契约定义

Redola.Rpc 是基于契约模型通信的,使用 Protobuf 2 格式定义 IDL,并通过自动生成工具生成 Contract 契约定义。

例如,下面是定义 ICalcService 服务的 IDL 定义。

package Redola.Rpc.TestContracts;message AddRequest
{required int32 X = 10;required int32 Y = 20;
}message AddResponse
{required int32 Result = 10;
}service CalcService
{rpc Add (AddRequest) returns (AddResponse);
}

上述 IDL 生成的 ICalcService 接口定义为:

public interface ICalcService
{AddResponse Add(AddRequest request);
}

RPC 消息序列化

Redola.Rpc 选择使用 Protobuf 2 进行消息序列化,默认集成 protobuf-net 类库,稳定使用 protobuf-net v2.0.0.668 版本。

RPC 消息信封

使用 ActorMessageEnvelope 封装消息信封,携带如下信息:

  属性名称

 属性类型 

 属性描述 

 MessageID

string

 消息 ID,唯一 ID,通常使用 GUID。

 MessageTime

DateTime

 消息产生时间

 CorrelationID

string

 如果是 Response 则回填 Request 的 MessageID。 

 CorrelationTime 

DateTime 

 如果是 Response 则回填 Request 的 MessageTime。

 SourceEndpoint 

 ActorEndpoint  发送端节点描述,消息路由使用,默认不需要填写。

 TargetEndpoint

ActorEndpoint 目的端节点描述,消息路由使用,默认不需要填写。 

 MessageType

string 消息类型,使用字符串描述。

 MessageData

byte[] 消息体,消息序列化后的二进制数组。

RPC 消息定义

RPC 消息分为 2 类:

  1. InvokeMethodRequest / InvokeMethodResponse 用于定义请求回复模型的方法调用;

  2. InvokeMethodMessage 用于定义请求无回复模型的方法调用;

通常 RPC 消息会包含如下属性信息:

  属性名称

 属性类型 

 属性描述 

 MethodLocator

string

 RPC 方法描述,使用字符串描述。

 MethodArguments 

object[]

 RPC 方法的入参,object 对象数组。

例如,对于 ICalcService 中的 Add 方法:

  • MethodLocator = "Rodola.Rpc.TestContracts.ICalcService/Add_AddRequest";

  • MethodArguments = new object[] { new AddRequest(1, 2)};

鉴于 protobuf 本身是面向契约设计的,而 object[] 中的 object 是有不确定性的,并不能具体描述一个契约,则要求每一个 Argument 都需要支持 protobuf 的序列化,传输时系统会携带该 Argument 类型的 AssemblyQualifiedName,在对端通过反射进行反序列化。

Actor Directory 节点目录

Actor Directory 负责注册本地 Local Actor 到注册中心,Local Actor 也可以在 Shutdown 时将自己从注册中心移除掉。

通过 Actor Directory,Local Actor 可以使用 Type 和 Name 进行 Remote Actor 的检索,进而进行 Channel 的建立和通信。

Actor Directory 通过 IActorDirectory 的抽象定义,可以与不同的目录方案进行集成。例如,自实现基于 Actor 的 CenterActorDirectory,使用 XML 配置文件的 LocalXmlFileActorDirectory,使用 Consul 进行中心注册的 ConsulActorDirectory。

使用 Consul 时,实际上是调用了 Consul HTTP API 中的 Agent Register Service 接口 '/v1/agent/service/register',通过指定 ServiceID 和 ServiceName 进行注册。

通过如下 cmd 启动 Consul Server 和 Consul Agent。

consul.exe agent -config-dir "C:\Consul\config\server-01" -bootstrap -ui
consul.exe agent -config-dir "C:\Consul\config\client-01" -join 192.168.1.133:7774 -ui

下面为启动本地 Consul 进行测试的配置文件。

server-01.json

{ 
 
"datacenter": "dc1",
 
"data_dir": "C:\\Consul\\data\\server-01",
 
"log_level": "INFO",
 
"node_name": "server-01",
 
"server": true,
 
"ports": {  
 
"http": 7771,  
 
"rpc": 7772,  
 
"dns": 7773,  
 
"serf_lan": 7774,  
 
"serf_wan": 7775,  
 
"server": 7776} }


client-01.json

{  
"datacenter": "dc1",
 
"data_dir": "C:\\Consul\\data\\client-01",
 
"log_level": "INFO",
 
"node_name": "client-01",
 
"ports": {  
 
"http": 8881,  
 
"rpc": 8882,  
 
"dns": 8883,  
 
"serf_lan": 8884,  
 
"serf_wan": 8885,  
 
"server": 8886} }


Service Catalog Provider 服务提供者

作为 RPC Service 的 Provider 提供方,需要显式定义指定 Contract 的服务实例。例如,下面将不同的服务契约与服务实例进行了注册。

var serviceCatalog = new ServiceCatalogProvider();
serviceCatalog.RegisterService<IHelloService>(new HelloService());
serviceCatalog.RegisterService<ICalcService>(new CalcService());
serviceCatalog.RegisterService<IOrderService>(new OrderService());

实际上,可以通过对于 IServiceCatalogProvider 接口的不同实现,进行不同方式的本地服务发现和注册。例如,可以使用 Attribute 标记服务,通过对 Assembly 进行反射进行服务的实例化。

Service Directory 服务目录

本地服务聚集到 Catalog 中后,系统会将服务逐个注册到 Service Directory 服务目录中,使得其他节点可以检索服务进行使用。

通过 IServiceDirectory 的抽象定义,可以与不同的目录方案进行集成。例如,使用 XML 配置文件的 LocalXmlFileServiceDirectory,使用 Consul 进行中心注册的 ConsulServiceDirectory。

使用 Consul 时,注册服务的 log 如下所示。

当 Redola 将服务注册至 Consul 中后,可通过 Consul 内置的 UI 进行查看。

http://localhost:8881/ui/#/dc1/services

Service Discovery 服务发现

通过 ConsulServiceDiscovery 实现 IServiceDiscovery 服务发现接口,从 Consul 检索指定服务类型的服务。

通过 Postman 测试 GET /v1/catalog/services,得到如下 JSON 数据。

http://localhost:8881/v1/catalog/services


{   
 
"Redola.Rpc.TestContracts.ICalcService": [],    "Redola.Rpc.TestContracts.IHelloService": [],    "Redola.Rpc.TestContracts.IOrderService": [],    "consul": [],    "server": [] }


通过 Postman 测试 GET /v1/catalog/service,得到如下 JSON 数据。

http://localhost:8881/v1/catalog/service/Redola.Rpc.TestContracts.ICalcService


[{      
 
"ID": "359e8dfe-262d-6eb7-260c-e6e3ad208a14",  
     
"Node": "client-01",  
     
"Address": "192.168.1.133",  
     
"Datacenter": "dc1",      
    
"TaggedAddresses": {      
     
"lan": "192.168.1.133",      
     
"wan": "192.168.1.133"},        "NodeMeta": {},  
     
"ServiceID": "redola/server/server-33333/Redola.Rpc.TestContracts.ICalcService",        "ServiceName": "Redola.Rpc.TestContracts.ICalcService",        "ServiceTags": [],    
   
"ServiceAddress": "localhost",  
     
"ServicePort": 33333,        "ServiceEnableTagOverride": true,    
   
"CreateIndex": 2147,      
 
"ModifyIndex": 2151} ]

服务检索方,可通过指定 IServiceLoadBalancingStrategy 的具体实现实施不同的负载均衡策略,默认指定的是 IServiceLoadBalancingStrategy 随机选择。

Service Dynamic Proxy 动态代理

为简化 RPC 调用发起方的封装,通常会使用 Dynamic Proxy 动态代理技术来动态生成给定契约的服务实例,将整体 RPC 的过程透明化。

例如,通过下面的代码来动态生成 ICalcService 的动态代理。

var calcClient = rpcNode.Resolve<ICalcService>();

目前 Redola.Rpc 默认集成了 Castle.Core 中的 Dynamic Proxy 模块,通过对实例方法的 Intercept 拦截进行 RPC 消息的收发处理。

当然,如需集成其他 Dynamic Proxy 类库,可通过 ISeviceProxyGenerator 接口进行方案实现。

Redola.Rpc 类库依赖

Redola.Rpc 当前实现依赖了如下开源类库。

<?xml version="1.0" encoding="utf-8"?><packages><package id="Consul" version="0.7.2.3" targetFramework="net46" /><package id="Cowboy.Sockets" version="1.3.14.0" targetFramework="net46" /><package id="protobuf-net" version="2.0.0.668" targetFramework="net46" /><package id="Castle.Core" version="4.1.0" targetFramework="net46" /><package id="Logrila.Logging" version="1.0.3.0" targetFramework="net46" /><package id="Logrila.Logging.NLogIntegration" version="1.0.3.0" targetFramework="net46" /><package id="NLog" version="4.2.3" targetFramework="net46" /></packages>


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

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

相关文章

springboot+springm vc+mybatis实现增删改查案例!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。前言最近这几天都在看关于springboot的内容&#xff0c;每天新会获得点新收获&#xff0c;并且都总结发在公众号中&#xff1b;最后经过不懈努力&#xff0c;不断查找相关网页&#xff0c;解决各种…

<table/>默认适应内容宽度造成滚动条不显示的解决方法

一、现象重现 <html><head></head><body> <table style"width: 100%;"> <tbody> <tr> <td style"width: 50%;overflow-x:auto"> <pre> 瞎子打灯笼一个盲人到亲戚家做客&#xff0c;天黑后&#xf…

java中,如何实现输入一个正整数,并将这个数字反转输出,比如输入123,输出321

如题所示&#xff0c;在java中如何实现输入一个正整数&#xff0c;然后将这个正整数反着输出来&#xff0c;代码如下&#xff1a; public static void test7(){System.out.println("请输入一个正整数&#xff1a;");Scanner sc new Scanner(System.in);int num sc…

asp.net core 1.1 项目升级至 asp.net core 2.0 preview 2

这两天把一个 asp.net core 1.1 的项目迁移到了 asp.net core 2.0 preview 2 &#xff0c;在这篇随笔中记录一下。 如果项目在有 global.json 文件&#xff0c;需要删除或修改为 .net 2.0 preview 2 的 sdk 版本号。 对于类库项目的 .csproj&#xff0c;需要把 TagetFramewo…

JSP的<c:foreach/>标签只输出一次标签体内容的坑

一、场景复现 <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <% String[] arr{"a","b","c","d"}; request.setAttribute("arr", arr); %><!DOCTYPE HT…

springboot访问jsp页面变成直接下载?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。前言大家在写springboot的时候不知道你们遇没遇到过这样的问题&#xff0c;当我们满怀信心的在浏览器中输入&#xff1a;localhost://8080/default&#xff0c;然后回车的时候&#xff0c;期待的页…

ASP.NET WebAPI 中的参数绑定

当 WebAPI 调用 Controller 上的方法时&#xff0c; 必须为其参数赋值&#xff0c; 这个过程就是参数绑定。 本文介绍 WebAPI 如何绑定参数&#xff0c; 以及如何进行自定义。 WebAPI 默认使用下面的规则进行参数绑定&#xff1a; 简单类型&#xff0c; WebAPI 尝试从 URL 中…

<table/>设置列宽度无效的问题

一、场景重现 <html> <head><title>测试</title><style type"text/css">.table {table-layout: fixed;}</style> </head> <body> <div style"width: 100%"><table class"table" styl…

公众号一年能有多少收入?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。前言由于坚持日更公众号也有一年左右了&#xff0c;好多人问我你这公众号一年到底能收入多少啊&#xff1f;值得你花那么多的时间去摆弄吗&#xff1f;今天我就来说说我这公众号&#xff0c;一年到…

SpringBootAdmin客户端接入

只有网关微服务有方框中的内容&#xff0c;其他微服务没有

ssl初一组周六模拟赛【2018.5.12】(期中)

前言 这周竟然没有奶死自己&#xff0c;成为模拟赛第一个AK的&#xff08;然而第一题数据错了所以这次放加上第一题的分&#xff09; 先说一下成绩&#xff1a; 姓名成绩wyc400xjq290xxy255lrz225hzb205zyc190hjq180lw140 期中总结 正题 题目1&#xff1a;ssl2413 排名【…

Java自动化邮件中发送图表(一)

一、邮件需求 邮件中需要展示柱状图、折线图和饼图等图表数据。如图&#xff1a; 二、解决方案 将图表转成图片&#xff0c;采用html邮件文本&#xff0c;使用base64编码图片发送邮件。 将图表导出成图片有三种方式&#xff1a; &#xff08;1&#xff09;JFreeChart 优点…

springboot+mybatis-plus实例demo

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。前言故事还得从一次微信通话说起……一个夜深人静的晚上&#xff0c;正在电脑前看书&#xff0c;突然&#xff0c;放在旁边的手机响了起来&#xff0c;原来是一个朋友打的微信电话。“你在干嘛呢&a…

分布式事务,EventBus 解决方案:CAP【中文文档】

前言 很多同学想对CAP的机制以及用法等想有一个详细的了解&#xff0c;所以花了将近两周时间写了这份中文的CAP文档&#xff0c;对 CAP 还不知道的同学可以先看一下 .NET Core 事件总线,分布式事务解决方案&#xff1a;CAP。 本文档为 CAP 文献&#xff08;Wiki&#xff09;&…

POJ1330-Nearest Common Ancestors【tarjan,LCA】

正题 题目链接&#xff1a; http://poj.org/problem?id1330 题目大意 就是给出一棵树&#xff0c;求LCA&#xff08;最近公共祖先&#xff09; 解题思路 用tarjan求LCA&#xff0c;这里给出tarjan算法 代码 #include<cstdio> #include<iostream> using nam…

Java自动化邮件中发送图表(二)之JFreeChart

一、JFreeChart库 JFreeChart是JAVA平台上的一个开放的图表绘制类库。 JFreeChart可生成饼图&#xff08;pie charts&#xff09;、柱状图&#xff08;bar charts&#xff09;、散点图&#xff08;scatter plots&#xff09;、时序图&#xff08;time series&#xff09;、甘…

springboot点击运行没反应,什么都不显示的解决方式

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。最近这段时间一直在看开源框架&#xff0c;自己慢慢的琢磨&#xff0c;终于将jeecgboot环境搭建起来&#xff0c;并且成功的跑起来了demo&#xff0c;在此过程中&#xff0c;很明显的能感觉到自己进…