Giter VIP home page Giter VIP logo

gayrpc's Introduction

gayrpc

跨平台全双工双向(异步)RPC系统,也即通信两端都可以同时作为RPC服务方和客户端.

Platform

Build Status

hosted-ninja-vcpkg-autocache

动机

目前的RPC系统大多用于互联网行业后端系统,但他们之间更像一个单向图(不存在两个服务彼此依赖/互相调用),但游戏等行业中则两节点之间可能相互调用。 因此我们需要一个全双工RPC,在一个"链接"的两端均可开启服务和客户端,当然这里的"链接"是一个虚拟概念,它不一定基于TCP,也即"链接"的两端可以只存在逻辑链接而并没有网络直连。

设计准则

  1. RPC支持拦截器,能够对Request或Response做一些处理(比如监控、认证、加解密、分布式跟踪)
  2. RPC核心不依赖网络和网络传输协议,即:我们可以开发任何网络应用和逻辑来开启RPC两端,将"收到"的消息丢给RPC核心,并通过某个出站拦截器来实现/决定把Request或Response以何种方式传递给谁。
  3. 此RPC是基于异步回调的,我认为这是目前C++里比较安全和靠谱的方式,虽然没有同步那么舒服……但gayrpc通过使用folly的Promise模式已经足够简便了
  4. RPC系统核心(以及接口)是线程安全的,可以在任意线程调用RPC;且可以在任意线程使用XXXReply::PTR对象返回Response。
  5. RPC是并行的,也即:客户端可以随意发送Request而不必等待之前的完成。 且允许先收到后发出的Request的Response。
  6. RPC系统会为每一个"链接"生成一个XXXService对象,这样可以让不同的"链接"绑定/持有各自的业务对象(有状态)(而不是像grpc等系统那样,一个服务只存在一个service对象,这类RPC调用类似短链接:收到请求返回数据即可)
  7. 支持HTTP API(同理2,此功能通过具体通信协议和拦截器进行支持,RPC核心本身与此无关).

依赖

gayrpc依赖以下库:

注意,请务必根据你的构建系统中的protoc版本对gayrpc_meta.proto和gayrpc_option.proto预先生成代码,这需要你在 src目录里执行:

 protoc --cpp_out=. ./gayrpc/core/gayrpc_meta.proto ./gayrpc/core/gayrpc_option.proto

测试体验

Windows下可以安装vcpkg,然后直接使用Visual Studio 2019/2022打开本代码仓库目录,并在VS 的CMake设置里勾选“从不使用CMake预设”(位置在"选项"-"CMake"-"CMake配置文件"),即不使用仓库目录中的CMakePresets文件!然后再进行生成CMake工程。

Linux下则请按照vcpkg文档进行构建。

代码生成工具

gayrpc使用protobuf定义服务,并需要使用代码生成工具根据protobuf服务文件生成对应的代码。生成工具的地址是:https://github.com/IronsDu/protoc-gen-gayrpc,它由liuhan编写完成。
首先将插件程序放到系统 PATH路径下(比如Linux下的/usr/bin),然后执行代码生成,比如(在具体的服务目录里,比如gayrpc/examples/echo/pb):

 protoc  -I. -I../../../src --cpp_out=. echo_service.proto
 protoc  -I. -I../../../src --gayrpc_out=. echo_service.proto

Example

https://github.com/IronsDu/gayrpc/tree/master/examples

Benchmark

Latency(single threaded):

connection num:1000
cost 16491 ms for 3000000 requests
throughput(TPS):187500
mean:5 ms, 5274983 ns
median:5 ms, 5132642 ns
max:57 ms, 57525470 ns
min:0 ms, 17231 ns
p99:19 ms, 19198630 ns

Throughput(two threaded):

Ubuntu 18.04 (i5 CPU)下,echo 300k QPS,当并发echo时 1000K QPS.

协议

目前实现的RPC通信协议底层采用两层协议.(注意!RPC核心库并不依赖具体通信协议!) 第一层采用二进制协议,且字节序统一为大端. 通信格式如下:

[data_len | op | data]
字段解释:
data_len : uint64_t;
op       : uint32_t;
data     : char[data_len];

op值为1时表示RPC消息,此为第二层协议!这时第一层协议中的data的内存布局则为:

[meta_size | data_size | meta | data]
字段解释:
meta_size  : uint32_t;
data_size  : uint64_t;
meta       : char[meta_size];
data       : char[data_size];

其中metaRpcMata的binary.data为某业务上的Protobuf Request或Response类型对象的binary或JSON.

RpcMata的proto定义如下:

syntax = "proto3";

package gayrpc.core;

message RpcMeta {
    enum Type {
        REQUEST = 0;
        RESPONSE = 1;
    };

    enum DataEncodingType {
        BINARY = 0;
        JSON = 1;
    };

    message Request {
        // 请求的服务函数
        uint64  method = 1;
        // 请求方是否期待服务方返回response
        bool    expect_response = 2;
        // 请求方的序号ID
        uint64  sequence_id = 3;
    };

    message Response {
        // 请求方的序号ID
        uint64  sequence_id = 1;
        // 执行是否成功
        bool    failed = 2;
        // (当failed为true)错误码
        int32   error_code = 3;
        // (当failed为true)错误原因
        string  reason = 4;
    };
    
    // Rpc类型(请求、回应)
    Type    type = 1;
    // RpcData的编码方式
    DataEncodingType encoding = 2;
    // 请求元信息
    Request request_info = 3;
    // 回应元信息
    Response response_info = 4;
}

服务描述文件范例

以下面的服务定义为例:

syntax = "proto3";

package dodo.test;

message EchoRequest {
    string message = 1;
}

message EchoResponse {
    string message = 1;
}

service EchoServer {
    rpc Echo(EchoRequest) returns(EchoResponse){
        option (gayrpc.core.message_id)= 1 ;//设定消息ID,也就是rpc协议中request_info的method
    };
}

处理请求或Response的实现原理

  1. 编写第一层通信协议的编解码
  2. 将第一层中的data作为第二层协议数据,反序列化其中的meta作为RpcMeta对象
  3. 判断RpcMata中的type
    1. 如果为REQUEST则根据request_info中的元信息调用method所对应的服务函数. 此时第二层协议中的data则为服务函数的请求请求对象(比如EchoRequest).
    2. 如果为RESPONSE则根据response_info中的元信息调用sequence_id对应的回调函数. 此时第二层协议中的data则为服务方返回的Response(比如EchoResponse)

发送请求的实现原理

client->echo(echoRequest, responseCallback)为例 参考代码:GayRpcClient.h

  1. 客户端分配 sequence_id,以它为key将 responseCallback保存起来.
  2. 将echoRequest序列化为binary作为第二层协议中的data
  3. 构造RpcMeta对象,将echo函数对应的id号作为request_info的method,并设置sequence_id.
  4. 将RpcMeta对象的binary作为第二层协议中的meta
  5. 用第二层协议的数据写入第一层协议进行发送给服务端.

发送Response的实现原理

replyObj->reply(echoResponse)为例 参考代码:GayRpcReply.h

  1. 首先replyObj里(拷贝)储存了来自于请求中的RpcMata对象.
  2. 将echoResponse序列化为binary作为第二层协议中的data
  3. 构造RpcMeta对象,将备份的RpcMeta对象中的sequence_id设置到前者中response_info的sequence_id.
  4. 将RpcMeta对象的binary作为第二层协议中的meta
  5. 用第二层协议的数据写入第一层协议进行发送给服务端.

编解码参考

https://github.com/IronsDu/gayrpc/tree/master/src/gayrpc/protocol

注意点

  • RPC核心并不依赖通信采用的协议,而且网络传输可以是TCP、UDP、WebSocket等等,亦或消息队列等等。
  • RPC服务方的reply顺序与客户端的调用顺序无关,也就是可能后发起的请求先得到返回.

gayrpc's People

Contributors

ironsdu avatar overtalk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gayrpc's Issues

服务与双向调用问题

请问一条连接上可以安装多个服务吗,服务器如何调用已经连接的特定客户端上服务中的方法?

echo示例运行问题

请教一下,我在用vs2017运行echo示例,在客户端发送消息的request.set_message处报错,看起来是string释放时内存访问冲突。从网上查资料看我猜可能是开启了arena分配器,还没有进一步确认,请问这个问题作者有遇到么,是这个原因么?c++新手望指点,谢谢~

关于client的析构

client有shared_ptr的 RpcTypeHandleManager
RpcTypeHandleManager 又存有shared_ptr的client 和shared_ptr的service
这样client,service,RpcTypeHandleManager 不会析构不了吗
还是说就这样设计的,不需要析构

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.