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 = ;
required int32 Y = ;
} message AddResponse
{
required int32 Result = ;
} 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: -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>

版权声明:本篇文章《Redola 集成 Consul 服务发现》由作者 Dennis Gao 发表自博客园个人技术博客,未经作者本人同意禁止以任何的形式转载,任何自动的或人为的爬虫转载行为均为耍流氓。

Redola.Rpc 集成 Consul 服务发现的更多相关文章

  1. ocelot集成consul服务发现

    首先下载consul 点击这里下载 转到解压文件夹目录输入cmd命令  consul agent -dev (有时候会卡住按一下方向键上) 在浏览器中输入http://localhost:8500/u ...

  2. 扩展gRPC支持consul服务发现和Polly策略

    gRPC由于需要用工具生成代码实现,可开发性不是很高,在扩展这方面不是很友好 最近研究了下,进行了扩展,不需要额外的工具生成,直接使用默认Grpc.Tools生成的代理类即可 相关源码在文章底部 客户 ...

  3. 学习搭建 Consul 服务发现与服务网格-有丰富的示例和图片

    目录 第一部分:Consul 基础 1,Consul 介绍 2,安装 Consul Ubuntu/Debian 系统 Centos/RHEL 系统 检查安装 3,运行 Consul Agent 启动 ...

  4. 微服务(入门三):netcore ocelot api网关结合consul服务发现

    简介 api网关是提供给外部调用的统一入口,类似于dns,所有的请求统一先到api网关,由api网关进行指定内网链接. ocelot是基于netcore开发的开源API网关项目,功能强大,使用方便,它 ...

  5. .NET Core微服务实施之Consul服务发现与治理

    .NET Core微服务实施之Consul服务发现与治理   Consul官网:https://www.consul.io Consul下载地址:https://www.consul.io/downl ...

  6. .NetCore Cap 注册 Consul 服务发现

    注册服务发现 需要使用Cap中的UseDiscovery方法 具体用法如下 var capConsulConfig = Configuration.GetSection("CapConsul ...

  7. 基于Docker的Consul服务发现集群搭建

    在去年的.NET Core微服务系列文章中,初步学习了一下Consul服务发现,总结了两篇文章.本次基于Docker部署的方式,以一个Demo示例来搭建一个Consul的示例集群,最后给出一个HA的架 ...

  8. consul服务发现和配置共享的软件,

    Consul 是什么 consul是一个支持多数据中心分布式高可用服务发现和配置共享的服务软件,由HashiCorp 公司用 Go 语言开发, 基于 Mozilla Public License 2. ...

  9. Ocelot 网关 和 consul 服务发现

    服务发现 Consul 一.安装和启动 下载 [Consul](https://www.consul.io/downloads.html) 下载完成后,解压,只有一个consul.exe,把目录添加到 ...

随机推荐

  1. ssh无密码登录远程主机

    方法:在客户端生成公/私钥对,将私钥文件保存在客户端,再将公钥文件上传到服务器端(远程主机) 1.在客户端生成公/私钥对 cb@cb251#ssh-keygen...cb@cb251#ls .ssh/ ...

  2. Ubuntu下Tomcat初始配置

    1.下载tomcat安装包 从tomcat官方网站http://tomcat.apache.org下载安装包,然后解压到某个目录,比如: ~/opt/apache-tomcat-7.0.63官方文档中 ...

  3. 学习maven的各种问题

    1. The container 'Maven Dependencies' references non existing library 解决方法,将eclipse中maven插件中“resolve ...

  4. Java IO学习笔记总结

    Java IO学习笔记总结 前言 前面的八篇文章详细的讲述了Java IO的操作方法,文章列表如下 基本的文件操作 字符流和字节流的操作 InputStreamReader和OutputStreamW ...

  5. arcgis api for js入门开发系列十二地图打印(GP服务)

    上一篇实现了demo的地图统计图,本篇新增地图打印,截图如下: (1)地图打印实现的思路如下:首先在创建好地图打印GP模型,设置好模型的参数:其次是验证模型运行模型:然后是发布地图打印的GP服务:最后 ...

  6. a链接返回上一页

    <a href="javascript:void(0);" onclick="javascript:history.go(-1);" style='mar ...

  7. 一张图搞定Java设计模式——工厂模式! 就问你要不要学!

    小编今天分享的内容是Java设计模式之工厂模式. 收藏之前,务必点个赞,这对小编能否在头条继续给大家分享Java的知识很重要,谢谢!文末有投票,你想了解Java的哪一部分内容,请反馈给我. 获取学习资 ...

  8. [leetcode-438-Find All Anagrams in a String]

    Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.Strings c ...

  9. winform利用委托delegate进行窗体间通信,相同标题已经存在??

    前段时间学习委托,感觉很模糊的样子,也做过许多实例,但是项目中一直没有用到,今天在项目中遇到一个很简单的例子,现在拿出来,做一个简单的记录. 要求:将弹出框里勾选的内容返回到主面板上. 工具:委托. ...

  10. win7-x64安装mysql5.7.11(官方zip版)

    1.下载官方安装包(http://www.mysql.com/downloads/),此zip包是没有安装器的(*.msi),也没有辅助配置的自动程序. 2.解压zip包,将文件放入指定目录,如:D: ...