SRPC 框架服务端源码解析

0. RPC Context

保存某些必要的上下文信息;

某端独有功能:Client 获取请求成功或失败

1. RPCBuffer

constconstexpr 变量的主要区别是:const 变量的初始化可以被推迟到运行期,constexpr 必须在编译期初始化;所有 constexpr 都是 const

buffer_t 指向实际的数组,代表一个缓存块;再通过链表将各缓存块连接起来;

(1)BUFFER_MODE_NOCOPY 类型的缓存块如何释放?

在代码中,删除或合并时没用对 is_nocopy 进行删除,是否会引发内存泄漏?

规定标记:旧 RPCBuffer 为 B1,新 RPCBuffer 为 B2

在 B1 调用 cut 生成 B2 时,如果当前位置位于某个缓存块的中间位置,那么该缓存块就会由这两个 RPCBuffer 共同管理,注意到在 B2 中管理该缓存块的后半部分,类型为 BUFFER_MODE_NOCOPY ,但在 B1 中管理该缓存块的前半部分,其类型没用改变,仍然为 BUFFER_MODE_GIFT_MALLOC;

显然这种情况要求,B2 先释放后,B1 才能释放,如何保证该要求的实现?

(2)acquire 中申请缓存块时,有极值限制,过大过小都会调整,避免频繁申请内存;

(3)read_back 函数中,offset 绝对值过大时 cur_.firstbegin, secondbegin->buflen, 如果此时调用 internal_fetch 会获取第二块缓存,但应该获取第一块,就会造成问题;

因此需要保证 offset 不会大于当前的 size_ ,如何保证?

2. zero_copy_stream

内部都包装了一个 RPCBuffer 指针;

根据作者的知乎文章,下述两个类是用于序列化和反序列化过程;

2.1 RPCOutputStream

构造时可以指定需要的缓存大小,如果未指定,会按最小的来申请;

(1)Next 结合循环,即内部不断申请缓存块,以填充数据;

// Copy the contents of "infile" to "outfile", using plain read() for
// "infile" but a ZeroCopyOutputStream for "outfile".
int infd = open("infile", O_RDONLY);
int outfd = open("outfile", O_WRONLY);
ZeroCopyOutputStream* output = new FileOutputStream(outfd);

void* buffer;
int size;
while (output->Next(&buffer, &size)) {
  int bytes = read(infd, buffer, size);
  if (bytes < size) {
    // Reached EOF.
    output->BackUp(size - bytes);
    break;
  }
}

delete output;
close(infd);
close(outfd);

由 Protocol Buffers 官网示例可以看出,最后一块内存一般来说会给得多一些,因此只需回退最后一个缓存块,与 RPCBuffer 中 backup 设计吻合;

2.2 RPCInputStream

(1)Next

其中调用了 RPCBuffer 的 fetch方法,结合 while 循环,即不断获取 RPCBuffer 中待读取的缓存块,直到所有缓存块都读取完毕;

// Read in a file and print its contents to stdout.
int fd = open("myfile", O_RDONLY);
ZeroCopyInputStream* input = new FileInputStream(fd);

const void* buffer;
int size;
while (input->Next(&buffer, &size)) {
  cout.write(buffer, size);
}

delete input;
close(fd);

(2)BackUp

理论上,如果内存里有超过一个 message,那么当前 message 解析完整之后,需要回退 count 字节。

这里需要注意一下 RPCBuffer 中的(3)的问题;(即保证不用过度回退)

3. RPCMessage

3.1 SRPCMessage

代表一条消息,message 数据可能是分成数份传递过来的

(1)append 函数,从形参 buf 中接收数据,workflow 收到网络包后会调用该函数;

header 由固定大小的数组接收
meta_bufnew 分配空间,存放 meta 数据
message 数据则放入 RPCBuffer 中

在这里插入图片描述
(2)deserialize

使用接收 message 数据部分的 buf 初始化 RPCInputStream

直接调用 Protobuf 的 ParseFromZeroCopyStream 解析消息

(3)encode(要求 iovec 数组的大小最少为 3);workflow 会在进行网络发送时会被调用

  1. 设置 header
  2. 将 header 数组和 meta_buf 分别填入 iovec 数据结构中(使用两个)
  3. 调用 bufencode 方法,将 message 部分填入 iovec 数据结构中(最少使用一个)

可以合理猜测底层 workflow 会使用 writev 来发送数据

4. rpc_module

4.1 SnowFlake

(1)get_id生成不同的分布式 ID,总位数为 64 位,由以下四部分组成:

timestampgroup_idmachine_idsequence

timestamp 由 std::chrono::steady_clock 产生,单位为 ms,如果在同一 ms 内的申请,由 sequence 进行区分

std::chrono::steady_clock 为单调时钟,两个 tick 之间的时间固定,与钟表上的时间不同(可以是从某个时间点开始的),适合测量间隔;)

sequence 和 last_timestamp 由原子变量维护;

5. 服务器端

5.1 RPCWorker

封装了 请求和相应 Message,及 RPCContext,这些基类指针指向派生类(是 proto 生成类型,基类为 google::protobuf::Message

5.2 RPCService

服务名 name_
内部维护一个哈希表 methods_,key 为方法名,val 为回调函数

(1)add_method 就是将回调函数加入到这个 methods_ 中;

(2)ServiceRPCCallImpl

申请 req 的空间
从 RPCWorker 中接收到的 Message 反序列化出 req( SRPCMessage 中 buf 转化为 EchoRequest 类型)
如果成功解析,调用用户 rpc 函数;

5.2.1 Service

位于服务端;

service Example {
     rpc Echo(EchoRequest) returns (EchoResponse);
};

是由 srpc_generator protobuf 生成的 xxx.srpc.h 文件中,继承自 RPCService;

RPC 服务为 Service 中的纯虚函数,用户需要继承自该类,实现该函数;

(1)Service 的构造函数会设置 name_ 为 Example,调用 RPCService::add_method ,从而注册回调函数(方法名为 Echo,绑定 this 指针结合虚函数动态绑定机制的调用用户实现的函数);

5.2.2 RPCServer

继承自 WFServer

内部维护一个哈希表 service_map,key 为服务名,val 为 RPCService 指针;

(1)add_service 就是在 service_map 中添加 RPCService ;

(2)start 为 WFServer 中的方法,为开启 TCP 服务器;

推测有数据到来,会调用 server_process 函数

(3)server_process

  1. ParseFromArray 解析 RPCMeta;(反序列化,从 meta_buf 转换为 RPCMeta 类型)

  2. 从 RPCMeta 中的解析出 RPCMetaKeyValue 存放到 RPCModuleData 中( map 类型)

  3. module 部分处理(此步看不太懂)

  4. message 数据部分解压缩;

  5. 调用 rpc;

  6. 设置响应状态码

5.2.3 RPCServerTask

(1)message_out ,用来告诉 Workflow 网络层面这次发出的请求内容时啥

  1. 将 EchoResponse 序列化为到 SRPCMessage类型的 buf

  2. 将 SRPCMessage类型的 buf 中的数据进行压缩

  3. 处理 module

  4. 序列化 meta(将 RPCMeta 类型转换为 SRPCMessage 中的字符数组 meta_buf
    RPCMeta 类型也是由 proto 定义生成的类型

  5. 设置状态码,即设置 meta 中的 status_code 属性

6. RPCCompressor

使用了单例模式,局部静态变量初始化

私有构造函数会添加其支持的各种压缩算法;

持有 CompressHandler 的固定大小的数组,每种代表一个压缩算法;

(1)parse_from_compressed,根据给定的类型,调用相关压缩算法的函数

6.1 CompressHandler

封装了一些函数句柄;

7. 客户端部分

由于要放寒假了,之后有时间再看吧;

7.1 RPCClientTask

user_done_ 就是用户设置的 rpc 完成回调函数;

如果使用 rpc 的异步接口,create_rpc_client_task

即调用 RPCClient::create_rpc_client_task,在该函数中会创建 RPCClientTask。

重要参考

作者本人的知乎,对整个流程介绍还是非常清晰的,尤其是对像我这种不懂 workflow 的人

https://zhuanlan.zhihu.com/p/619721187

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/348240.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony开发——GN快速上手

背景 最近在研究鸿蒙操作系统的开源项目OpenHarmony&#xff0c;该项目使用了GNNinja工具链进行配置&#xff0c;编译&#xff0c;于是开始研究GN如何使用。 本文的所有信息均来自GN官网和本人个人体会。 GN快速入门 使用GN GN的主要功能是根据配置文件&#xff08;.gn, BU…

Android开发--状态栏布局隐藏的方法

1.问题如下&#xff0c;安卓布局很不协调 2.先将ActionBar设置为NoActionBar 先打开styles.xml 3.使用工具类 package com.afison.newfault.utils;import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.graph…

字符串匹配(BF KMP)详解 + 刷题

目录 &#x1f33c;前言 BF 算法 KMP 算法 &#xff08;1&#xff09;前缀函数 -- O(n^3) &#xff08;2&#xff09;前缀函数 -- O(n^2) &#xff08;3&#xff09;前缀函数 -- O(n) &#xff08;4&#xff09;辅助理解 &#x1f40b;P1308 -- 统计单词数 …

【深度学习】线性回归模型与梯度下降法

线性回归模型与梯度下降法 线性回归模型与枚举法 线性回归模型定义: w:权重b:偏置#mermaid-svg-ZAxF27Mw5dXNQgw2 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZAxF27Mw5dXNQgw2 .error-icon{fill:#552222;}…

pyecharts模块的下载方法以及介绍,折线图的创立

目录 1.pyecharts是什么 2.pyecharts下载方法 1.在屏幕左下角搜索这里输入cmd&#xff0c;找到命令提示符并且打开 2.输入pip install pyecharts 然后回车进行下载 3.检查是否下载完成 4.另一个方法 3.pyecharts入门 4.pyecharts的配置选项 set_global_opts全局配置选…

[docker] Docker资源管理

一、docker资源控制 Docker通过Cgroup 来控制容器使用的资源配额&#xff0c;包括CPU、内存、磁盘三大方面&#xff0c;基本覆盖了常见的资源配额和使用量控制。Caroup 是ControlGroups的缩写&#xff0c;是Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如…

OpenKruise :Kubernetes背后的托底

一、 诞生背景 Kubernetes 自身提供的应用部署管理功能&#xff0c;无法满足大规模应用场景的需求&#xff0c;例如应用发布时的原地升级策略&#xff0c;流式扩容&#xff0c;缩容顺序控制等等。所以OpenKruise的出现弥补了 Kubernetes 在应用部署、升级、防护、运维等领域的不…

剪映声音克隆;多位滴滴前中高层加入小红书提速商业化;中国和新加坡互免签证

今日精选 • 剪映推出 AI 音色克隆功能&#xff0c;录制 5 秒声音即可完成克隆• 商业化全面提速&#xff0c;多位滴滴前中高层加入小红书• 2 月 9 日起&#xff0c;中国和新加坡互免签证 科技动态 • 夸克上线大模型新产品“AI PPT”&#xff0c;可一键生成提纲、创作 PPT…

Unity - gamma space下还原linear space效果

文章目录 环境目的环境问题实践结果处理要点处理细节【OnPostProcessTexture 实现 sRGB 2 Linear 编码】 - 预处理【封装个简单的 *.cginc】 - shader runtime【shader需要gamma space下还原记得 #define _RECOVERY_LINEAR_IN_GAMMA】【颜色参数应用前 和 颜色贴图采样后】【灯…

接口自动化测试实践

众所周知&#xff0c;接口自动化测试有着如下特点&#xff1a; 低投入&#xff0c;高产出。 比较容易实现自动化。 和UI自动化测试相比更加稳定。 如何做好一个接口自动化测试项目呢&#xff1f; 我认为&#xff0c;一个“好的”自动化测试项目&#xff0c;需要从“时间”…

【算法练习Day51】柱状图中最大的矩形

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 柱状图中最大的矩形思路动态…

HTML+CSS:飞翔按钮

效果演示 实现了一个按钮的动画效果&#xff0c;当鼠标悬停在按钮上时&#xff0c;按钮的背景颜色和图标会发生变化&#xff0c;并且图标会旋转45度并向右移动1.2em&#xff0c;同时按钮中的文字也会向右移动5em。当鼠标点击按钮时&#xff0c;按钮会变小并向下移动0.1em。整个…

软考复习之软件工程篇

软件生命周期 问题定义&#xff1a;要示系统分析员与用户进行交流&#xff0c;弄清”用户需要计算机解决什么问题”然后提出关于“系统目标与范围的说明”&#xff0c;提交用户审查和确认 可行性研究&#xff1a;一方面在于把待开发的系统的目标以明确的语言描述出来&#xf…

LINUX服务之YUM仓库

1. YUM概述 YUM基于RPM包构建的软件更新机制 可以自动解决依赖关系 所有软件包由集中的YUM软件仓库提供 YUM支持软件源 搭建yum支持的的软件源主要有以下三种&#xff1a; 本地yum&#xff1a;file&#xff1a;//… 网络yum&#xff0c;又分为HTTP服务器&#xff1a;http…

Vue3 watch与watchEffect区别

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

从全流程的角度来了解python包的使用,也许你会有不一样的认识

在python中&#xff0c;只要我们一谈到包或模块&#xff0c;基本默认说的就是包的导入和使用。也就是说只要我们知道包的名字&#xff0c;导入后知道怎么使用基本就可以了&#xff0c;但本人认为&#xff0c;我们仅仅了解的是包的一部分&#xff0c;若想对包有个整体的认识&…

376. 摆动序列 - 力扣(LeetCode)

题目描述 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为摆动序列。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。少于两个元素的序列也是摆动序列。 例如&#xff0c; [1,7,4,9,2,5] 是一个摆动序列&#xff0c;因为差值 (6,…

【机器学习300问】15、什么是逻辑回归模型?

一、逻辑回归模型是为了解决什么问题&#xff1f; 逻辑回归&#xff08;Logistic Regression&#xff09;是一种广义线性回归分析模型&#xff0c;尤其适用于解决二分类问题&#xff08;输出为两个类别&#xff09;。 &#xff08;1&#xff09;二分类举例 邮件过滤&#xff…

详解BLDC和PMSM的特点

文章目录 前言BLDC和PMSM的优点基础架构前言 在电机领域中,有刷电机和无刷电机代表着两种不同的技术路径。有刷电机的绕组通常位于转子,即电机的旋转部分。 而无刷电机则采用一种更为先进的设计,其绕组安置在定子,即电机的静止部分。 这样的设计理念在于将绕组固定在电机的…

深入理解stress/stress-ng

文章目录 一、概述二、安装2.1、源码编译安装2.2、命令行安装2.3、安装确认 三、重要参数详解3.1、查询支持的参数3.2、重要参数说明 四、实例4.1、压测CPU4.2、压测内存4.3、压测IO4.4、压测磁盘及IO4.5、压测磁盘及CPU 团队博客: 汽车电子社区 一、概述 stress是一种工作负载…