Giter VIP home page Giter VIP logo

phxrpc's Introduction

PhxRPC是微信后台团队推出的一个非常简洁小巧的RPC框架,编译生成的库只有450K。

作者: Sifan Liu, Haochuan Cui 和 Duokai Huang

联系我们:[email protected]

想了解更多, 以及更详细的编译手册,请进入中文WIKI,和扫描右侧二维码关注我们的公众号

PhxRPCBuild Status

总览

  • 使用Protobuf作为IDL用于描述RPC接口以及通信数据结构。
  • 基于Protobuf文件自动生成Client以及Server接口,用于Client的构建,以及Server的实现。
  • 半同步半异步模式,采用独立多IO线程,通过Epoll管理请求的接入以及读写,工作线程采用固定线程池。IO线程与工作线程通过内存队列进行交互。
  • 支持协程Worker,可配置多个线程,每个线程多个协程。
  • 提供完善的过载保护,无需配置阈值,支持动态自适应拒绝请求。
  • 提供简易的Client/Server配置读入方式。
  • 基于lambda函数实现并发访问Server,可以非常方便地实现Google提出的 Backup Requests 模式。

局限

  • 不支持多进程模式。

性能

使用Sample目录下的Search RPC C/S进行Echo RPC调用的压测,相当于Worker空转情况。

运行环境

CPU:24 x Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz 内存:32 GB 网卡:千兆网卡 Client/Server机器之间PING值: 0.05ms 请求写入并发:1000个线程 业务数据大小:除去HTTP协议部分20b Worker线程数:20

性能测试结果(qps)

短连接

ucontext类型/IO线程 1 3 8 20
system 41k 85k 90k 92k
boost 45k 95k 95k 95k

长连接

ucontext类型/IO线程 1 3 8 20
system 55k 160k 360k 500k
boost 62k 175k 410k 500k

如何编译

Protobuf准备

PhxRPC必须依赖的第三方库只有Protobuf。在编译前,在third_party目录放置好protobuf目录,或者通过软链的形式。

boost优化

PhxRPC在ServerIO以及Client并发连接管理上使用了ucontext,而boost的ucontext实现要比system默认的更为高效,推荐使用boost。如果需要使用boost的话需要在third_party目录放置好boost目录,或者通过软链的形式。

编译环境

  • Linux
  • GCC-4.8及以上版本
  • boost 1.56及以上版本(可选)

编译安装方法

进入PhxRPC根目录。

make (默认是-O2编译,如需编译debug版,执行 make debug=y)
make boost (可选,编译PhxRPC的boost优化插件,编译之前先准备好boost库)

如何使用

编写proto文件

下面是sample目录下的proto文件样例。

syntax = "proto3";
package search;
import "google/protobuf/wrappers.proto";
import "google/protobuf/empty.proto";
import "phxrpc/phxrpc.proto";

enum SiteType {
    BLOG = 0;
    NEWS = 1;
    VIDEO = 2;
    UNKNOWN = 3;
}

message Site {
    string url = 1;
    string title = 2;
    SiteType type = 3;
    tring summary = 4;
}

message SearchRequest {
    string query = 1;
}

message SearchResult {
    repeated Site sites = 1;
}

service Search {
    rpc Search(SearchRequest) returns (SearchResult) {
        option(phxrpc.CmdID) = 1;
        option(phxrpc.OptString) = "q:";
        option(phxrpc.Usage) = "-q <query>";
    }
    rpc Notify(google.protobuf.StringValue) returns (google.protobuf.Empty) {
        option(phxrpc.CmdID) = 2;
        option(phxrpc.OptString) = "m:";
        option(phxrpc.Usage) = "-m <msg>";
    }
}

生成代码

(PhxRPC根目录)/codegen/phxrpc_pb2server -I (PhxRPC根目录) -I (Protobuf include目录) -f (proto文件路径) -d (生成代码放置路径)

# sample
../codegen/phxrpc_pb2server -I ../ -I ../third_party/protobuf/include -f search.proto -d .
../codegen/phxrpc_pb2server -I ../ -I ../third_party/protobuf/include -f search.proto -d . -u

两种生成模式,区别在于-u参数。

第一种生成默认的线程池worker模型。

第二种-u参数指定生成uthread worker模型,也就是工作线程池里面每个线程里面运行着多个协程。

调用完工具后,在生成代码放置目录下执行make,即可生成全部的RPC相关代码。

选择是否启用Boost优化

打开生成代码放置目录下的Makefile文件。

# choose to use boost for network
#LDFLAGS := $(PLUGIN_BOOST_LDFLAGS) $(LDFLAGS)

可以看到以上两行,取消注释掉第二行,重新make clean && make即可开启Boost对PhxRPC的优化。开启前记得编译好PhxRPC的Boost插件。

补充自己的代码

Server(xxx_service_impl.cpp)

int SearchServiceImpl::PHXEcho(const google::protobuf::StringValue &req,
        google::protobuf::StringValue *resp) {
    resp->set_value(req.value());
    return 0;
}

int SearchServiceImpl::Search(const search::SearchRequest &req,
        search::SearchResult *resp) {
    // 这里补充这个RPC调用的Server端代码
    return -1;
}

int SearchServiceImpl::Notify(const google::protobuf::StringValue &req,
        google::protobuf::Empty *resp) {
    // 这里补充这个RPC调用的Server端代码
    return -1;
}

Client (xxx_client.cpp)

// 这个是默认生成的代码,可自行修改,或利用我们提供的stub API自定义封装Client

int SearchClient::PHXEcho(const google::protobuf::StringValue &req,
        google::protobuf::StringValue *resp) {
    const phxrpc::Endpoint_t *ep = global_searchclient_config_.GetRandom();

    if (ep != nullptr) {
        phxrpc::BlockTcpStream socket;
        bool open_ret = phxrpc::PhxrpcTcpUtils::Open(&socket, ep->ip, ep->port,
                    global_searchclient_config_.GetConnectTimeoutMS(), nullptr, 0,
                    *(global_searchclient_monitor_.get()));
        if (open_ret) {
            socket.SetTimeout(global_searchclient_config_.GetSocketTimeoutMS());

            SearchStub stub(socket, *(global_searchclient_monitor_.get()));
            return stub.PHXEcho(req, resp);
        }
    }

    return -1;
}

UThread Client (xxx_client_uthread.cpp)

// 这个是默认生成的代码,可自行修改,或利用我们提供的stub API自定义封装Client
// UThread Client只能在采用PhxRPC uthread worker模型的server中调用。
// UThread Client构造函数需要传入UThreadEpollScheduler*类型参数,
// 这个参数来源可以在xxx_service_impl.h的私有变量中获得。

int SearchClientUThread::PHXEcho(const google::protobuf::StringValue &req,
        google::protobuf::StringValue *resp) {
    const phxrpc::Endpoint_t *ep = global_searchclientuthread_config_.GetRandom();

    if (uthread_scheduler_ != nullptr && ep != nullptr) {
        phxrpc::UThreadTcpStream socket;
        bool open_ret = phxrpc::PhxrpcTcpUtils::Open(uthread_scheduler_, &socket, ep->ip, ep->port,
                    global_searchclientuthread_config_.GetConnectTimeoutMS(),
                    *(global_searchclientuthread_monitor_.get()));
        if (open_ret) {
            socket.SetTimeout(global_searchclientuthread_config_.GetSocketTimeoutMS());

            SearchStub stub(socket, *(global_searchclientuthread_monitor_.get()));
            return stub.PHXEcho(req, resp);
        }
    }

    return -1;
}

Client并发调用样例

int SearchClient::PHXBatchEcho(const google::protobuf::StringValue &req,
        google::protobuf::StringValue *resp) {
    int ret = -1;
    size_t echo_server_count = 2;
    uthread_begin;
    for (size_t i = 0; i < echo_server_count; i++) {
        uthread_t [=, &uthread_s, &ret](void *) {
            const phxrpc::Endpoint_t *ep = global_searchclient_config_.GetByIndex(i);
            if (ep != nullptr) {
                phxrpc::UThreadTcpStream socket;
                if(phxrpc::PhxrpcTcpUtils::Open(&uthread_s, &socket, ep->ip, ep->port,
                            global_searchclient_config_.GetConnectTimeoutMS(),
                            *(global_searchclient_monitor_.get()))) {
                    socket.SetTimeout(global_searchclient_config_.GetSocketTimeoutMS());
                    SearchStub stub(socket, *(global_searchclient_monitor_.get()));
                    int this_ret = stub.PHXEcho(req, resp);
                    if (this_ret == 0) {
                        ret = this_ret;
                        uthread_s.Close();
                    }
                }
            }
        };
    }
    uthread_end;
    return ret;
}

uthread_begin, uthread_end, uthread_s, uthread_t这几个关键字是PhxRPC自定义的宏,分别表示协程的准备、结束,协程调度器以及协程的创建。

上面的代码实现了Google提出的 Backup Requests 模式。实现的功能是分别对两个Server同时发起Echo调用,当有一个Server响应的时候,则整个函数结束。在这段代码里面,我们提供了一种异步IO的同步写法,并给予了一些方便使用的宏定义。首先使用uthread_begin进行准备,然后使用uthread_t以lambda的形式创建一个协程,而在任意一个协程里面都可使用我们PhxRPC生成的Client API进行RPC调用,并可使用uthread_s随时结束所有RPC调用。最后的uthread_end真正通过协程调度发起这些lambda内的RPC调用,并等待结束。

当然你可以借用这4个宏定义,以同步代码的写法,进行更自定义的并发访问。

Server配置说明 (xxx_server.conf)

[Server]
BindIP = 127.0.0.1              // Server IP
Port = 16161                    // Server Port
MaxThreads = 16                 // Worker 线程数
WorkerUThreadCount = 50         // 每个线程开启的协程数,采用-u生成的Server必须配置这一项
WorkerUThreadStackSize = 65536  // UThread worker的栈大小
IOThreadCount = 3               // IO线程数,针对业务请自行调节
PackageName = search            // Server 名字,用于自行实现的监控统计上报
MaxConnections = 800000         // 最大并发连接数
MaxQueueLength = 20480          // IO队列最大长度
FastRejectThresholdMS = 20      // 快速拒绝自适应调节阀值,建议保持默认20ms,不做修改

[ServerTimeout]
SocketTimeoutMS = 5000          // Server读写超时,Worker处理超时

phxrpc's People

Contributors

liusifan avatar lynncui00 avatar mariohuang avatar taohexxx avatar taozhijiang avatar tencent-wechat avatar unixliang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

phxrpc's Issues

按照WIKI中文详细编译手册安装失败

按照中文详细编译手册安装,发现文档已经过时了,protobuf在googlecode的地址已经失效了,而且github上的protobuf现在不带gtest了,需要自己安装了,自动安装脚本需要同步更新下

protoc各种参数生成的命名规则为什么那么奇怪?

下面尝试三种生成方式(全部都在 WORKDIR=~/dev-workspace/wx/phxrpc 下执行):

  1. third_party/protobuf/bin/protoc -Ithird_party/protobuf/include -I./phxrpc/rpc --cpp_out=. ./phxrpc/rpc/phxrpc.proto

最后生成的结果在 $WORKDIR 里面,与cpp_out参数指定的目标一致,然后phxrpc.pb.h的namespace为protobuf_phxrpc_2eproto

  1. third_party/protobuf/bin/protoc -Ithird_party/protobuf/include -I./phxrpc/rpc --cpp_out=./phxrpc/rpc ./phxrpc/rpc/phxrpc.proto

最后生成的结果在 $WORKDIR/phxrpc/rpc 里面,与cpp_out参数指定的目标一致,然后phxrpc.pb.h的namespace为protobuf_phxrpc_2eproto

  1. third_party/protobuf/bin/protoc -Ithird_party/protobuf/include -I. --cpp_out=. ./phxrpc/rpc/phxrpc.proto

最后生成的结果在 $WORKDIR/phxrpc/rpc 里面,与cpp_out参数指定的目标不一致 ,然后 phxrpc.pb.h的namespace为 protobuf_phxrpc_2frpc_2fphxrpc_2eproto

第三种就是官方提供的生成pb.cc的方式,这种方式生成的代码,在另外一个proto文件引用才是正常的,可视为什么呢?

HsHaServerIO::AddAcceptFd中的NotifyEpoll应该没有作用

bool HshaServerIO :: AddAcceptedFd(int accepted_fd) {
std::lock_guardstd::mutex lock(queue_mutex_);
if (accepted_fd_list_.size() > MAX_ACCEPT_QUEUE_LENGTH) {
return false;
}
accepted_fd_list_.push(accepted_fd);

if (static_cast<int>(hsha_server_stat_->io_read_request_qps_) < 5000
        && static_cast<int>(hsha_server_stat_->accept_qps_) < 5000) {

    scheduler_->NotifyEpoll();  /*即便qps超过阀值,不进行NotifyEpoll在UThreadEpollScheduler中依然会进行HandlerAcceptedFd回调检测AcceptList*/
}

return true;

}

因为在**UThreadEpollScheduler::Run()中超时Pipe还是会进行一次handler_accepted_fd_func_调用,即便没有NotifyEpoll操作,不知道我的立即是否正确,请解释下,谢谢。

每次rpc调用都要新开一个进程吗?

每次rpc调用都要新开一个进程吗?如何想要自行调用函数的话,每个函数有个OptMap类型的参数,这个类的定义找不到。难道每次调用都要把参数传进main函数,然后再转化成某个函数调用?

Why we split the pointer to two `uint32_t`s in `UThreadContextSystem :: UThreadFuncWrapper`?·

in file uthread_context_system.cpp, we have a function called UThreadFuncWrapper. I'm confused why we pass high bits and low bits of this pointer rather than passing the whole this pointer into the wrapper. Is there any concern about that?

Thanks for your reply.

void UThreadContextSystem :: Make(UThreadFunc_t func, void * args) {
    func_ = func;
    args_ = args;
    getcontext(&context_);
    context_.uc_stack.ss_sp = stack_.top();
    context_.uc_stack.ss_size = stack_.size();
    context_.uc_stack.ss_flags = 0;
    context_.uc_link = GetMainContext();
    uintptr_t ptr = (uintptr_t)this;
    makecontext(&context_, (void (*)(void))UThreadContextSystem::UThreadFuncWrapper, 
            2, (uint32_t)ptr, (uint32_t)(ptr >> 32)); // we split `this` pointer into two parts
}

void UThreadContextSystem :: UThreadFuncWrapper(uint32_t low32, uint32_t high32) {
    uintptr_t ptr = (uintptr_t)low32 | ((uintptr_t) high32 << 32); // then we put it together again
    UThreadContextSystem * uc = (UThreadContextSystem *)ptr;
    uc->func_(uc->args_);
    if (uc->callback_ != nullptr) {
        uc->callback_();
    }
}

UThreadRuntime 改进建议

  1. UThreadRuntime类中的 void UThreadRuntime :: UThreadDoneCallback() 是否考虑对执行完成
    的 ContextSlot 剔除出 context_list_ 数组,这样可以加快没有完成的 UThreadContext 被选中的几率,
    比如通过例子 test_uthread(test_uthread.cpp)来执行,在
    for(; ! runtime.IsAllDone(); ) {
    int seq = random() % count;
    runtime.Resume( args[ seq ].id );
    }
    这段代码中,最后一个没有执行完成的UThreadContext 可能要随机被选中,需要空转很多次才能选中。
  2. UThreadRuntime::IsAllDone(),这个函数建议直接返回 unfinished_item_count_即可,这样就能立即
    获取到队列中没有执行完成总数。
  3. 执行完成的任务立即剔除出执行数组,那创建函数
    int UThreadRuntime :: Create(UThreadFunc_t func, void * args) 也可以简化很多,不用去抢占执行完成的坑了

关于phxrpc中服务端c++调用tensorflow脚本,Tensorflow Protobuf版本和phxrpc Protobuf版本

您好,phx团队,有个问题想请教一下,phxrpc框架需要下载protobuf编译,我的服务端程序是用c++调用python,执行一个包含tensorflow的脚本,可是在执行过程中,出现
[libprotobuf ERROR google/protobuf/descriptor_database.cc:58] File already exists in database: google/protobuf/timestamp.proto [libprotobuf FATAL google/protobuf/descriptor.cc:1401] CHECK failed: generated_database_->Add(encoded_file_descriptor, size): terminate called after throwing an instance of 'google::protobuf::FatalException' what(): CHECK failed: generated_database_->Add(encoded_file_descriptor, size):
这是什么问题,有什么解决办法吗?
在补嵌入phxrpc框架,c++调用python,执行tensorflow脚本是ok的,tensorflow1.4.0(protobuf3.4.0) python3.5.3 phxrpc编译时,protobuf版本是3.4.0

与svrkit的区别

我看之前的分享是用svrkit 做rpc的,如:

微信后台主要使用C++。后台服务使用Svrkit框架搭建,服务之间通过同步RPC进行通讯。

Svrkit是另一个广硏后台就已经存在的高性能RPC框架,当时尚未广泛使用,但在微信后台却大放异彩。作为微信后台基础设施中最重要的一部分,Svrkit这几年一直不断在进化。我们使用Svrkit构建了数以千计的服务模块,提供数万个服务接口,每天RPC调用次数达几十万亿次。

于是我们开始尝试使用一种新的CGI架构——Logicsvr。
Logicsvr基于Svrkit框架。将Svrkit框架和CGI逻辑通过静态编译生成可直接使用HTTP访问的Logicsvr。

每个Logicsvr都是一个独立的二进制程序,可以分开部署、独立上线。时至今日,微信后台有数十个Logicsvr,提供了数百个CGI服务,部署在数千台服务器上,每日客户端访问量几千亿次。

Svrkit——Client/Server自动代码生成框架:10分钟搭建内部服务器

epoll_wait的最后参数为什么是4MS ?

如题,不应该通过计算定期或者超时事件最小触发时间而动态进行设置吗?
无就绪事件而有定时器来时,4ms会有延迟处理;
无就绪事件也无定时器来时,4MS触发的往下执行没有必要。

Woker 无法使用UThread所带来的好处

个人认为这个RPC几个做的漂亮的地方:

  1. IO流的处理
  2. IO处理创新性的使用UThread,但仅限于socket -> data_flow(worker)之间

想问下, 有考虑Worker本身就是UThreadScheduler驱动吗? 实际业务开发往往是Worker线程调用其他服务接口RT不可控导致 服务本身处理能力低下。这种异步IO,同步Worker解决不了这种问题。

worker能否改成是 UThread epoll 驱动的,而不是data_flow的队列消费驱动, 这样每个Worker线程都是一个UthreadScheduler,类似libco的思路, 便于Worker 在调用其他服务的时候使用 Uthread

Thks.

关于用protobuf定义接口以及通信数据结构的疑问

这里我有个疑问,如果rpc接口返回的数据结构十分复杂,比如以前是http接口返回的是一个json字符串,这个json字符串很长,并且其中的某些字段内容经常变化。这时候改造成rpc接口,用pb来描述接口返回值的话,pb的定义会很复杂繁琐,并且pb的字段最好只增加不减少,针对这种场景,你们在实际使用过程中,有没有遇到,以及是如何处理的呢。

MakeFile怎么转Makefile.define

phxrpc 中Makefile 怎么转 phxsql中Makefile.define
phxbinlogsvr/framework/proto/phxbinlogsvr.proto phxbinlogsvr/framework/proto/Makefile.define phxbinlogsvr/framework/rpccomm/Makefile.define phxbinlogsvr/framework/phxrpc/client/Makefile.define phxbinlogsvr/framework/phxrpc/svr/Makefile.define phxbinlogsvr/framework/phxrpc/tools/Makefile.define

这里是不是有bug

bool UThreadEpollScheduler::Run() 中
业务线程开启协程时,epoll_wait可能会被业务fd唤醒,但handler_new_request_func_被注册,
就会被调用处理新请求,Worker::HandlerNewRequestFunc()函数中貌似是阻塞取io线程的消息的,这样的话业务中的其他协程就会暂时挂起,影响性能。
PS:从性能测试看,短连接、长连接的性能差距蛮大的,有没有考虑cache 协程的方案?
即:进程启动后就开启N个IO协程,当accept到连接时使用缓存的协程等待读,读取完数据不销毁协程;业务协程同理。

编译pb失败?

用的是protobuf-3.4.1,编译的时候发现

search.pb.cc:126:13: error: ‘phxrpc::protobuf_phxrpc_2frpc_2fphxrpc_2eproto’ has not been declared
::phxrpc::protobuf_phxrpc_2frpc_2fphxrpc_2eproto::InitDefaults();
^
search.pb.cc: In function ‘void search::protobuf_search_2eproto::{anonymous}::AddDescriptorsImpl()’:
search.pb.cc:163:13: error: ‘phxrpc::protobuf_phxrpc_2frpc_2fphxrpc_2eproto’ has not been declared
::phxrpc::protobuf_phxrpc_2frpc_2fphxrpc_2eproto::AddDescriptors();

编译plugin_boost出错

OS: Ubuntu18.04 64bit
GCC: 8.0
Boost: 1.66

由于使用到的boost::context下的类和函数已经转移到boost::context::detail下,并且有的函数参数发生变化,需要进行更改plugin_boost/network下的uthread_context_boost.h和uthread_context_boost.cpp,之后可以成功编译,但是未进行测试.
代码中中文注释部分为修改的地方.
其中uthread_context_boost.h改为:

#pragma once

#include <unistd.h>
#include <functional>
#include <assert.h>
#include <boost/context/all.hpp>
#include "phxrpc/network.h"
// 添加
using boost::context::detail::fcontext_t;
using boost::context::detail::transfer_t;

namespace phxrpc {

class UThreadContextBoostInit {
public:
    UThreadContextBoostInit();
};

class UThreadContextBoost : public UThreadContext {
public:
    UThreadContextBoost(size_t stack_size, UThreadFunc_t func, void * args, 
            UThreadDoneCallback_t callback, const bool need_stack_protect);
    ~UThreadContextBoost();

    static UThreadContext * DoCreate(size_t stack_size, 
            UThreadFunc_t func, void * args, UThreadDoneCallback_t callback,
            const bool need_stack_protect);

    void Make(UThreadFunc_t func, void * args) override;
    bool Resume() override;
    bool Yield() override;

    fcontext_t & GetMainContext();

private:
    // 参数从intptr_t变为transfer_t
    static void UThreadFuncWrapper(transfer_t ptr);

    fcontext_t context_;
    UThreadFunc_t func_;
    void * args_;
    UThreadStackMemory stack_;
    UThreadDoneCallback_t callback_;
};

} //namespace phxrpc

uthread_context_boost.cpp改为:

#include <unistd.h>
#include <functional>
#include <assert.h>
#include <boost/context/all.hpp>

#include "uthread_context_boost.h"
#include "phxrpc/network.h"
using boost::context::detail::transfer_t;
using boost::context::detail::fcontext_t;
using boost::context::detail::jump_fcontext;
using boost::context::detail::make_fcontext;
namespace phxrpc {

UThreadContextBoostInit g_uthread_context_boost_init_;

UThreadContextBoostInit :: UThreadContextBoostInit() {
    UThreadContext::SetContextCreateFunc(UThreadContextBoost::DoCreate);
}

UThreadContextBoost :: UThreadContextBoost(size_t stack_size, UThreadFunc_t func, 
        void * args, UThreadDoneCallback_t callback, const bool need_stack_protect)
    : func_(func), args_(args), stack_(stack_size, need_stack_protect), callback_(callback) {
    Make(func, args);
}

UThreadContextBoost :: ~UThreadContextBoost() {
}

UThreadContext * UThreadContextBoost:: DoCreate(size_t stack_size, 
        UThreadFunc_t func, void * args, UThreadDoneCallback_t callback,
        const bool need_stack_protect) {
    return new UThreadContextBoost(stack_size, func, args, callback, need_stack_protect);
}

// 参数从intptr_t变为transfer_t
void UThreadContextBoost :: UThreadFuncWrapper(transfer_t ptr) {
    // 类型转换前将transfer_t取地址转为intptr_t
    UThreadContextBoost * uc = reinterpret_cast<UThreadContextBoost *>(intptr_t(&ptr));
    uc->func_(uc->args_);
    if (uc->callback_ != nullptr) {
        uc->callback_();
    }
    uc->Yield();
}
void UThreadContextBoost :: Make(UThreadFunc_t func, void * args) {
    func_ = func;
    args_ = args;
    void * stack_p = (void *)((char *)stack_.top() + stack_.size());
    context_ = make_fcontext(stack_p, stack_.size(), &UThreadFuncWrapper);
}

bool UThreadContextBoost :: Resume() {
    //boost::context::detail::jump_fcontext(&GetMainContext(), context_, reinterpret_cast<intptr_t>(this));
    //删除最后一个参数
    jump_fcontext(&GetMainContext(), context_);
    return true;
}

bool UThreadContextBoost :: Yield() {
    //boost::context::detail::jump_fcontext(&context_, GetMainContext(), 0);
   // 删除最后一个参数
    jump_fcontext(&context_, GetMainContext());

    return true;
}

fcontext_t & UThreadContextBoost :: GetMainContext() {
    static thread_local fcontext_t main_context;
    return main_context;
}

} //namespace phxrpc

配置Config类section的处理

char tmp_section[128] = { 0 };
snprintf(tmp_section, sizeof(tmp_section), "\n[%s]", section);

char tmp_key[128] = { 0 };
snprintf(tmp_key, sizeof(tmp_key), "\n%s", key);

如上配置类中关于,tmp_section的初始化格式,测试用于读取下面配置信息。

[Server]
BindIP = 127.0.0.1          //Server IP
Port = 16161                //Server Port
MaxThreads = 16             //Worker 线程数
IOThreadCount = 3           //IO线程数,针对业务请自行调节
PackageName = search        //Server 名字,用于自行实现的监控统计上报
MaxConnections = 800000     //最大并发连接数
MaxQueueLength = 20480      //IO队列最大长度
FastRejectThresholdMS = 20  //快速拒绝自适应调节阀值,建议保持默认20ms,不做修改

[ServerTimeout]
SocketTimeoutMS = 5000      //Server读写超时,Worker处理超时

因为tmp_section初始化为\n[%s]格式,如果[Server]section配置选没有\n在二行而是在首行则无法匹配,从而导致无法获取Server区块的配置信息。

去掉HttpHeader

http太浪费带宽了,还是用命令号+tcp比较合适。

优秀的phxrpc

几年前看看<<微信技术总监解读微信架构的秘密>>一片文章, 觉得Svrkit, LogicServer好厉害,能实现真正的微服务。
苦苦找寻基于服务端的优秀c++ rpc框架, 用过thrift可不支持protobuf, 觉得grpc使用http2协议用在外网还行。
昨晚还在想, 是不是自己用asio结合protobuf实现rpc。 今天早上在google上搜索 wechat server framework,终于找到phxrpc。
前一阵子, 心想微信的产品已经做到大爷大妈那里了, 微信的技术也不做点开源。 今天看到phxrpc,心情有点激动, 发了这个issues。

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.