本项目将从零开始搭建出一个基于协程的异步RPC框架。
学习本项目需要有一定的C++,网络,RPC知识
项目地址:zavier-wong/acid: A high performance fiber RPC network framework. 高性能协程RPC网络框架
RPC框架设计
本项目将从零开始搭建出一个基于协程的异步RPC框架。
通过本项目你将学习到:
相信大家对RPC的相关概念都已经很熟悉了,这里不做过多介绍,直接进入重点。
本文档将简单介绍框架的设计,在最后的 examples 会给出完整的使用范例。
更多的细节需要仔细阅读源码。
本RPC框架主要有网络模块, 序列化模块,通信协议模块,客户端模块,服务端模块,服务注册中心模块,负载均衡模块
主要有以下三个角色:
注册中心 Registry
主要是用来完成服务注册和服务发现的工作。同时需要维护服务下线机制,管理了服务器的存活状态。
服务提供方 Service Provider
其需要对外提供服务接口,它需要在应用启动时连接注册中心,将服务名发往注册中心。服务端还需要启动Socket服务监听客户端请求。
服务消费方 Service Consumer
客户端需要有从注册中心获取服务的基本能力,它需要在发起调用时,
从注册中心拉取开放服务的服务器地址列表存入本地缓存,
然后选择一种负载均衡策略从本地缓存中筛选出一个目标地址发起调用,
并将这个连接存入连接池等待下一次调用。
协程同步原语
我们都知道,一旦协程阻塞后整个协程所在的线程都将阻塞,这也就失去了协程的优势。编写协程程序时难免会对一些数据进行同步,而Linux下常见的同步原语互斥量、条件变量、信号量等基本都会堵塞整个线程,使用原生同步原语协程性能将大幅下降,甚至发生死锁的概率大大增加。
框架实现了一套协程同步原语来解决原生同步原语带来的阻塞问题,在协程同步原语之上实现更高层次同步的抽象——Channel用于协程之间的便捷通信。
具体设计思路见 通用协程同步原语设计
序列化协议
本模块支持了基本类型以及标准库容器的序列化,包括:
- 顺序容器:string, list, vector
- 关联容器:set, multiset, map, multimap
- 无序容器:unordered_set, unordered_multiset, unordered_map, unordered_multimap
- 异构容器:tuple
以及通过以上任意组合嵌套类型的序列化
序列化有以下规则:
- 默认情况下序列化,8,16位类型以及浮点数不压缩,32,64位有符号/无符号数采用 zigzag 和 varints 编码压缩
- 针对 std::string 会将长度信息压缩序列化作为元数据,然后将原数据直接写入。char数组会先转换成 std::string 后按此规则序列化
- 调用 writeFint 将不会压缩数字,调用 writeRowData 不会加入长度信息
对于任意用户自定义类型,只要实现了以下的重载,即可参与传输时的序列化。
template<typename T>
Serializer &operator >> (Serializer& in, T& i){
return *this;
}
template<typename T>
Serializer &operator << (Serializer& in, T i){
return *this;
}
rpc调用过程:
- 调用方发起过程调用时,自动将参数打包成tuple,然后序列化传输。
- 被调用方收到调用请求时,先将参数包反序列回tuple,再解包转发给函数。
通信协议
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| BYTE | | | | | | | | | | | ........ |
+--------+--------+--------+--------+--