.net core高吞吐远程方法如何调用组件XRPC详解

前言

XRPC的目标非常明确,就是给.net core平台实现一个百万级别的远程方法调用RPC通讯组件。它的设计理念和GRPC一样,基于连接复用的机制实现高吞的性能;XRPC采用了HTTP2复用的思想,在协议设计上也类似文本和二进制相结合;在应用层面并没使用消息而是基于接口代理的方式让使用更简便。

协议序列化

XRPC采用了基于文本+二进制相结合的通讯协议,头以文本的方式表现主要是描述请求的位置和附加信息,这样设计的好处就是在实现网关的时候只需要解释头部就能做很好的负载策略。二进制处理并没有像GPRC一样使 Protobuf,而是使用了在.net core平台下相对更高效的组件MessagePack。

通讯机制

在早期很多RPC是基于独享连和连接池的方式进行构建,这样的好处就是实现起来方便简单,但这种设计就无法把不同请求的请求混合到一个IO上。导致网络IO随并发消息的增长而增长,从而局限了性能的发挥。XRPC的设计是尽量在最少连接情况发挥更高效的网络处理能力,这样就可以把N个请求的数据复用在一个IO上,而从让网络利用率大大提升。

但这种设计的缺点就是使用起来非常复杂,不过在.NET提供async/await支持下整体设计和应用就变得相对简单和清晰很多了。现在模块已经完成基础功能版本,以下介绍一下如何使用。

组件使用

组件现在只完成最基础的功能,后面会引用Actor的一些基础元素,让在并发业务处理数据上更高效。可以通过Nuget引用组件

Install-Package BeetleX.XRPC -Version x

定义接口服务

XRPC是通过接口的方式来描述服务,通过接口制定相关服务的逻辑,具体实现如下:

[Controller(typeof(IUserService))]
public class UserService : IUserService
{
 public Task<User> Add(string name, string email, string city, string remark)
 {
  User user = new User();
  user.Name = name;
  user.EMail = email;
  user.City = city;
  user.Remark = remark;
  return Task.FromResult(user);
 }

 public Task<List<User>> List(int count)
 {
  List<User> result = new List<User>();
  for (int i = 0; i < count; i++)
  {
   User user = new User();
   user.ID = Guid.NewGuid().ToString("N");
   user.City = "GuangZhou";
   user.EMail = "Henryfan@msn.com";
   user.Name = "henryfan";
   user.Remark = "http://ikende.com";
   result.Add(user);
  }
  return Task.FromResult(result);
 }

 public bool Login(string name, string pwd)
 {
  return (name == "admin" && pwd == "123456");
 }

 public User Modify(User user)
 {
  return user;
 }

 public void Save()
 {
  Console.WriteLine("user saved");
 }
}

启动服务

class Program
{
 private static XRPCServer mXRPCServer;
 static void Main(string[] args)
 {
  mXRPCServer = new XRPCServer();
  //mXRPCServer.ServerOptions.DefaultListen.Port = 80;
  mXRPCServer.Register(typeof(Program).Assembly);
  mXRPCServer.Open();
  Console.Read();
 }
}

通过Register注册相关程序集,组件会把程序集中所有控制器加载到内存中,可以通过日志加载情况:

Client定义

client = new XRPCClient("localhost", 9090);
client.Connect();
client.NetError = (c, e) =>
{
  Console.WriteLine(e.Error.Message);
};
client.TimeOut = 10000;

定义一个XRPCClient对象来进行远程访问,对象默认最大连接数是2,也可以根据自己实情况进行调整,不建增加这样会导致网络IO也会增加影响整体性能。

var api = client.Create<IUserService>();
var lresult = await api.Login("admin", "123456");
Console.WriteLine(lresult);
var result = await api.Add("henry", "henryfan@msn.com", "gz", "http://github.com");
Console.WriteLine($"{result.Name}\t{result.EMail}\t{result.City}\t{result.Remark}");
await api.Save();
Console.WriteLine("save completed");
User user = new User();
user.ID = Guid.NewGuid().ToString("N");
user.Name = "henry";
user.EMail = "henryfan@msn.com";
user.City = "GuangZhou";
user.Remark = "http://github.com/ikende";
result = await api.Modify(user);
Console.WriteLine($"{result.Name}\t{result.EMail}\t{result.City}\t{result.Remark}");
var items = await api.List(5);
foreach(var item in items)
{
 Console.WriteLine($"{item.Name}\t{item.EMail}\t{item.City}\t{item.Remark}");
}

通过Create方法可以创建接口代理,这个代理是线程安全的,正常情况只需要创建一个静态成员即可;创建接口后只需要调用相关方法即可完成远程方法的调用。

基础性能

组件设计的性能目标是百万级别RPS的远程方法调用,不过在一台4核物机作为服务测试并没有达到这个目标,不过测试结果还算比较理想,在以上示例代码Login方法,采用500个并发模拟的情况RPS达到将近70万。以下是不同方法在不同并发数下的测试结果。

详细测试代码:https://github.com/IKende/XRPC/tree/master/Samples/Performance

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • .net core高吞吐远程方法如何调用组件XRPC详解

    前言 XRPC的目标非常明确,就是给.net core平台实现一个百万级别的远程方法调用RPC通讯组件.它的设计理念和GRPC一样,基于连接复用的机制实现高吞的性能:XRPC采用了HTTP2复用的思想,在协议设计上也类似文本和二进制相结合:在应用层面并没使用消息而是基于接口代理的方式让使用更简便. 协议序列化 XRPC采用了基于文本+二进制相结合的通讯协议,头以文本的方式表现主要是描述请求的位置和附加信息,这样设计的好处就是在实现网关的时候只需要解释头部就能做很好的负载策略.二进制处理并没有像G

  • 高吞吐、线程安全的LRU缓存详解

    本文研究的主要是高吞吐.线程安全的LRU缓存的相关内容,具体介绍如下. 几年以前,我实现了一个LRU缓存用来为关键字来查找它的id.数据结构非常有意思,因为要求的吞吐很大足以消除大量使用locks和synchronized关键字带来的性能问题,应用是用java实现的. 我想到一连串的原子引用分配会在ConcurrentHashMap中保持LRU保持LRU顺序,开始的时候我把value包装到entry中去,entry在双链表的LRU链中有一个节点,链的尾部保持的是最近使用的entry,头节点中存放

  • Java对象方法的调用执行过程详解

    目录 对象方法的调用执行过程 调用方法的几种方式 第一种 第二种 第三种 对象方法的调用执行过程 编译器查看对象的声明类型和方法名.假设调用x.f(param),隐式参数为x声明为C类对象,需要注意的是,有可能存在多个方法名为f,但是参数不同的方法,此时,编译器会一一列举C类中的所有方法名为f的方法和超类中访问属性为public的并且名字为f的方法. 接下来,编译器将查看调用方法时提供的参数类型.如果在所有名为f的方法中存在一个与提供的参数类型完全匹配,就选择这个方法,这个过程叫做“重载解析”.

  • vue远程加载sfc组件思路详解

    问题 在我们的 vue 项目中(特别是后台系统),总会出现一些需要多业务线共同开发同一个项目的场景,如果各业务团队向项目中提供一些公共业务组件,但是这些组件并不能和项目一起打包,因为项目中不能因为某个私有模块的频繁变更而重复构建发布. ^_^不建议在生产环境使用,代码包含eval 思路 在这种场景下我们需要将公共的业务组件部署到服务端,由客户端请求并渲染组件. 服务端解析.vue文件 使用vue-template-compiler 模板解析器,解析SFC(单文件组件) const compile

  • Vue组件之间的参数传递与方法调用的实例详解

    目录 父组件向子组件 子组件调用父组件方法 其它组件间调用 补充: 父组件向子组件 1.父组件向子组件传参:父组件中的子组件标签中增加 :param="param" 子组件中增加 props 接受参数(注意props需要与data同级) props: { param: { type: Object } }, data() { return { ... } }, 2.父组件调用子组件方法:父组件中子组件的标签增加 ref="abc" 例如: <child ref

  • JavaCV实战之调用摄像头基础详解

    目录 关于<JavaCV的摄像头实战>系列 本篇概览 环境和版本信息 源码下载 基本套路分析 基本框架编码 部署媒体服务器 关于<JavaCV的摄像头实战>系列 <JavaCV的摄像头实战>顾名思义,是使用JavaCV框架对摄像头进行各种处理的实战集合,这是欣宸作为一名Java程序员,在计算机视觉(computer vision)领域的一个原创系列,通过连续的编码实战,与您一同学习掌握视频.音频.图片等资源的各种操作 另外要说明的是,整个系列使用的摄像头是USB摄像图或

  • Python3的高阶函数map,reduce,filter的示例详解

    函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数. 注意其中:map和filter返回一个惰性序列,可迭代对象,需要转化为list >>> a = 3.1415 >>> round(a,2) 3.14 >>> a_round = round >>> a_round(a,2) 3.14 >>> def func_devide(x, y, f): return f(x) - f(y

  • Java多线程高并发中的Fork/Join框架机制详解

    1.Fork/Join框架简介 Fork/Join 它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出.Fork/Join 框架要完成两件事情: Fork:把一个复杂任务进行分拆,大事化小 :把一个复杂任务进行分拆,大事化小 Join:把分拆任务的结果进行合并 在 Java 的 Fork/Join 框架中,使用两个类完成上述操作: ForkJoinTask: 我们要使用 Fork/Join 框架,首先需要创建一个 ForkJoin 任务.该类提供了

  • Mybatis 创建方法、全局配置教程详解

    总体介绍:MyBatis实际上是Ibatis3.0版本以后的持久化层框架[也就是和数据库打交道的框架]! 和数据库打交道的技术有: 原生的JDBC技术--->Spring的JdbcTemplate技术 这些工具都是提供简单的SQL语句的执行,但是和我们这里学的MyBatis框架还有些不同, 框架是一整套的东西,例如事务控制,查询缓存,字段映射等等. 我们用原生JDBC操作数据库的时候都会经过: 编写sql---->预编译---->设置参数----->执行sql------->

  • COM组件中调用JavaScript函数详解及实例

    COM组件中调用JavaScript函数详解及实例 要求是很简单的,即有COM组件A在IE中运行,使用JavaScript(JS)调用A的方法longCalc(),该方法是一个耗时的操作,要求通知IE当前的进度.这就要求使用回调函数,设其名称为scriptCallbackFunc.实现这个技术很简单: 1 .组件方(C++) 组件A 的方法在IDL中定义: [id(2)] HRESULT longCalc([in] DOUBLE v1, [in] DOUBLE v2, [in, optional

随机推荐