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>

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

时间: 2024-10-11 22:11:21

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

ocelot集成consul服务发现

首先下载consul 点击这里下载 转到解压文件夹目录输入cmd命令  consul agent -dev (有时候会卡住按一下方向键上) 在浏览器中输入http://localhost:8500/ui 查看是否安装成功成功如下图所示 在网站启动的时候注册服务,网站停止的时候卸载服务. 服务的注册 先引用consul nuget包 添加配置文件 { ... "ServiceDiscovery": { "ServiceName": "DataService&

一篇文章了解Consul服务发现实现原理

从 2016 年起就开始接触 Consul,使用的主要目的就是做服务发现,后来逐步应用于生产环境,并总结了少许使用经验. 最开始使用 Consul 的人不多,这两年微服务越来越火,使用 Consul 的人也越来越多. 经常有人会问一些问题,比如: 服务注册到节点后,其他节点为什么没有同步? Client 是干什么的?(Client 有什么作用?) 能不能直接注册到 Server?(是否只有 Server 节点就够了?) 服务信息是保存在哪里的? 如果节点挂了,健康检查能不能转移到别的节点? 有些

Spring Cloud Consul—服务发现与Consul

服务发现是基于微服务架构的关键原则之一.尝试配置每个客户端或某种形式的约定可能非常困难,可以非常脆弱.Consul通过HTTP API和DNS提供服务发现服务.Spring Cloud Consul利用HTTP API进行服务注册和发现.这不会阻止非Spring Cloud应用程序利用DNS界面.Consul代理服务器在通过八卦协议进行通信的集群中运行,并使用Raft协议协议. 如何激活 要激活Consul服务发现,请使用组org.springframework.cloud和artifact i

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

原文:.NET Core微服务实施之Consul服务发现与治理 Consul官网:https://www.consul.io Consul下载地址:https://www.consul.io/downloads.html Consul nuget 命令:Install-Package Consul 我的理解是,Consul是一个服务管理者,系统中所有使用到的服务他都帮你管理好,促销高峰需要新增服务的时候,服务开启来就自动注册到Consul中,服务下线关闭,也自动从Consul注销,无缝衔接,对于

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

原文:基于Docker的Consul服务发现集群搭建 在去年的.NET Core微服务系列文章中,初步学习了一下Consul服务发现,总结了两篇文章.本次基于Docker部署的方式,以一个Demo示例来搭建一个Consul的示例集群,最后给出一个HA的架构示范,也会更加贴近于实际应用环境. 一.示例整体架构 此示例会由一个API Gateway, 一个Consul Client以及三个Consul Server组成,有关Consul的Client和Server这两种模式的Agent的背景知识,请

Ocelot 网关 和 consul 服务发现

服务发现 Consul 一.安装和启动 下载 [Consul](https://www.consul.io/downloads.html) 下载完成后,解压,只有一个consul.exe,把目录添加到环境变量的PATH,注意添加到系统变量,仅仅加入用户变量不起作用.打开cmd,输入 consul agen -dev // 启动Consul服务 二.在aspnetcore中注册Consul 1. 定义配置项 /// <summary> /// Consul配置 /// </summary&

安装-consul服务发现集群

centos 7.4.x consul  1.2.2 list: 172.16.16.103 172.16.16.112 172.16.16.115 下载: #cd /usr/local/ #wget  https://releases.hashicorp.com/consul/1.2.2/consul_1.2.2_linux_amd64.zip #tar zxvf xxxxxx.zip #第一台启动 #nohup ./consul agent -bind=172.16.16.112 -serv

.NET CORE2.2 下 Ocelot+Consul服务发现踩坑记录

历史原因,笔者所在公司的项目目前还在使用 .NET CORE 2.2版本,在所有业务应用升级完成服务注册发现之后,最后剩下 Ocelot 网关服务升级.在升级过程中,遇到一些问题,记录此文,以便有相同情况的同学参考. 1. Ocelot 升级服务发现 根据官方文档 ,通过简单的添加配置,既可以将原有配置方式改为服务发现: 安装插件 Install-Package Ocelot.Provider.Consul 13.5.2,.Net Core 2.x 最后一个版本 配置服务 s.AddOcelot

(4).NET CORE微服务 Micro-Service ---- Consul服务发现和消费

上一章说了  Consul服务注册  现在我要连接上Consul里面的服务 请求它们的API接口 应该怎么做呢? 1.找Consul要一台你需要的服务器 1.1 获取Consul下的所有注册的服务 using (var consulClient = new ConsulClient(c => c.Address = new Uri("http://127.0.0.1:8500"))) { var services = consulClient.Agent.Services().R