RPC 原理详解
文章目录
- 什么是 RPC
- RPC 基本原理
- RPC核心功能
- 服务寻址
- 数据编解码
- 网络传输
- 一次RPC的调用过程
- 实践
- 基于HTTP协议的RPC
- 基于TCP协议的RPC
什么是 RPC
RPC(Remote Procedure Call),即远程过程调用,它允许像调用本地服务一样调用远程服务。是一种服务器-客户端(Client/Server)模式。
- 远程:指的是需要经过网络的,而不是应用内部、机器内部进行的。
- 过程:也就是方法。
那“远程过程调用”,就是:可以跨过一段网络,调用另外一个网络节点上的方法。以上就是对远程过程调用的简单理解。
RPC 调用分以下两种:
- 同步调用:客户方等待调用执行完成并返回结果。
- 异步调用:客户方调用后不用等待执行结果返回,但依然可以通过回调通知等方式获取返回结果。 若客户方不关心调用返回结果,则变成单向异步调用,单向调用不用返回结果。
异步和同步的区分在于是否等待服务端执行完成并返回结果。
RPC 基本原理
RPC核心功能
知道什么是RPC以后就会发现,RPC需要解决一些问题:
- 既然是远程调用,那么客户端如何知道服务端的地址?
- 如果客户端和服务端使用的是不同语言写的程序,那么参数该如何表达和解析?
- 如何进行网络传输?
这三个问题的解决方案也是RPC的核心功能:服务寻址、数据编解码和网络传输。
服务寻址
如果是本地调用,被调用的方法在同一个进程内,操作系统或者是虚拟机可以去地址空间去找;但是在远程调用中,这是行不通的,因为两个进程的地址空间是完全不一样的,肯定也无法知道远端的进程在那。
如果要想实现远程调用,我们需要对服务消费者和服务提供者两者进行约束:在远程过程调用中所有的函数都必须有一个 ID
,这个 ID 在整套系统中是唯一存在确定的。服务消费者在做远程过程调用时,发送的消息体中必须要携带这个 ID。服务消费者和服务提供者分别维护一个函数和 ID 的对应表。当服务消费者需要进行远程调用时,它就查一下这个表,找出对应的 ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码就行。
服务寻址的实现方式有很多种,常见的是:服务注册中心。要调用服务,首先你需要一个服务注册中心去查询对方服务都有哪些实例,然后根据负载均衡策略择优选一。

- 从服务提供者的角度看:当提供者服务启动时,需要自动向注册中心注册服务;当提供者服务停止时,需要向注册中心注销服务;提供者需要定时向注册中心发送心跳。如果一段时间未收到来自提供者的心跳后,注册中心会判定提供者已经停止服务,并从注册中心下架对应的服务。
- 从调用者的角度看:调用者启动时订阅注册中心的消息并从注册中心获取提供者的地址;当有提供者上线或者下线时,注册中心会告知到调用者;调用者下线时,取消订阅。
数据编解码
对计算机网络稍微有一点熟悉的同学都知道,数据在网络中传输都是二进制的:01010101010101010,类似这种,只有二进制数据才能在网络间传。选择好的序列化协议特别重要,一个好的序列化协议能减少序列化数据带来的性能损耗。常见的RPC序列化协议如下:
-
XML(Extensible Markup Language)是一种常用的序列化和反序列化协议,具有跨机器,跨语言等优点。狭义web service就是基于SOAP消息传递协议(一个基于XML的可扩展消息信封格式)来进行数据交换的。
-
JSON(Javascript Object Notation)起源于弱类型语言Javascript, 是采用"Attribute-value"的方式来描述对象协议。与XML相比,其协议比较简单,解析速度比较快。
-
Protocol Buffers 是google提供的一个开源序列化框架,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。同 XML 相比, Protobuf 的主要优点在于性能高。它以高效的二进制方式存储,比 XML 小 3 到 10 倍,快 20 到 100 倍。
以上每种协议都有其优点和适用场景,需要根据具体的需求和环境来选择合适的协议。
网络传输
提起网络传输大家脑海里肯定马上就能想到 TCP/IP四层模型、OSI 七层模型,那通常 RPC 会选择那一层作为传输协议呢?
在回答这个问题前,先来看下 RPC 需要网络传输实现什么样的功能。客户端的数据经过序列化后,就需要通过网络传输到服务端。网络传输层需要把前面说的函数 ID 和序列化后的参数字节流传给服务端,服务端处理完然后再把序列化后的调用结果传回客户端。
原则上只要能实现上面这个功能的都可以作为传输层来使用,具体协议没有限制。我们先来看下 TCP 协议,TCP 连接可以是按需连接,需要调用的时候就先建立连接,调用结束后就立马断掉,也可以是长连接,客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效。
由此可见 TCP 的性能确实很好,因此市面上大部分 RPC 框架都使用 TCP 协议,但也有少部分框架使用其他协议,比如 gRPC 用的是 HTTP2 来实现。
一次RPC的调用过程
忽略服务端向注册中心注册服务的流程,下面是客户端和服务端之间进行一次RPC调用的完整过程。

- 客户端(Client)通过本地调用的方式调用服务(以接口方式调用);
- 客户端存根(Client Stub)接收到调用请求后负责将方法、入参等信息进行组装序列化成能够进行网络传输的消息体(将消息体对象序列化为二进制流);
- 客户端存根(Client Stub)找到远程的服务地址,并且将消息通过网络发送给服务端(通过sockets发送消息);
- 服务端存根(Server Stub)收到消息后进行反序列化操作,即解码(将二进制流反序列化为消息对象);
- 服务端存根(Server Stub)通过解码结果调用本地的服务进行相关处理;
- 服务端(Server)将处理结果返回给服务端存根;
- 服务端存根(Server Stub)序列化处理结果(将结果消息对象序列化为二进制流);
- 服务端存根(Server Stub)将序列化结果通过网络发送至客户端(通过sockets发送消息);
- 客户端存根(Server Stub)接收到消息,进行反序列化解码(将结果二进制流反序列化为消息对象);
- 客户端得到最终的结果。
这里面有一个词语:
存根(Stub)
。这里存根的作用我认为和Linux内核里面的库打桩机制有点类似。在Linux中,一个"桩"(stub)就是一个程序或函数的临时替代品,"桩"可以模拟出类似于真实的程序或函数的行为。所以,在RPC中,客户端存根和服务器存根的作用是隐藏RPC底层机制的复杂性,让开发者可以像调用本地函数一样调用远程函数。
实践
基于HTTP协议的RPC
服务端代码:
type Args struct {A, B int
}type Compute intfunc (c *Compute) Add(args *Args, reply *int) error {*reply = args.A + args.Breturn nil
}func main() {compute := new(Compute)rpc.HandleHTTP() // 注册 HTTP 路由// 注册 RPC 服务if err := rpc.Register(compute); err != nil {log.Fatal("Register error:", err)}listen, err := net.Listen("tcp", ":8080")if err != nil {log.Fatal("Listen error:", err)}if err = http.Serve(listen, nil); err != nil {log.Fatal("Serve error:", err)}
}
rpc库对注册的方法有一定的限制,方法必须满足签名func (t *T) MethodName(argType T1, replyType *T2) error{}
:
- 方法名必需是可导出的。
- 方法接收两个参数,这两个参数都是可导出的,且第二个参数必需为指针类型。
- 方法必需返回一个error类型的参数。
客户端代码:
type Args struct {A, B int
}func main() {client, err := rpc.DialHTTP("tcp", "localhost:8080")if err != nil {log.Fatal("dialing:", err)}args := &Args{3, 5}// 同步调用var reply1 intif err = client.Call("Compute.Add", args, &reply1); err != nil {log.Fatal("Compute error:", err)}fmt.Printf("同步调用的sum: %d\n", reply1)// 异步调用var reply2 intdivCall := client.Go("Compute.Add", args, &reply2, nil)_ = <-divCall.Done // 接收调用结果fmt.Printf("异步调用的sum: %d\n", reply2)
}
运行结果如下:
PS D:\GolandProjects\RPC\client> go run .\client.go
同步调用的sum: 8
异步调用的sum: 8
基于TCP协议的RPC
服务端代码:
type Args struct {A, B int
}type Compute intfunc (c *Compute) Add(args *Args, reply *int) error {*reply = args.A + args.Breturn nil
}func main() {compute := new(Compute)if err := rpc.Register(compute); err != nil {log.Fatal("Register error:", err)}listen, err := net.Listen("tcp", ":8080")if err != nil {log.Fatal("Listen error:", err)}rpc.Accept(listen)
}
客户端代码:
type Args struct {A, B int
}func main() {client, err := rpc.Dial("tcp", "localhost:8080")if err != nil {log.Fatal("dialing:", err)}args := &Args{6, 8}// 同步调用var reply1 intif err = client.Call("Compute.Add", args, &reply1); err != nil {log.Fatal("Compute error:", err)}fmt.Printf("同步调用的sum: %d\n", reply1)// 异步调用var reply2 intdivCall := client.Go("Compute.Add", args, &reply2, nil)_ = <-divCall.Done // 接收调用结果fmt.Printf("异步调用的sum: %d\n", reply2)
}
运行结果:
PS D:\GolandProjects\RPC\client> go run .\client.go
同步调用的sum: 14
异步调用的sum: 14
相关文章:

RPC 原理详解
文章目录 什么是 RPCRPC 基本原理RPC核心功能服务寻址数据编解码网络传输一次RPC的调用过程 实践基于HTTP协议的RPC基于TCP协议的RPC 什么是 RPC RPC(Remote Procedure Call),即远程过程调用,它允许像调用本地服务一样调用远程服…...

新版Helix QAC 100%覆盖MISRA C++:2023
Helix QAC 2023.3预期将100%覆盖在2023年第四季度发布的新的MISRA C:2023规则。 此外,该版本支持更多的C20语言特性,并改进了Perforce Validate平台和Helix QAC与Validate的集成,以及其他质量改进。 编码标准覆盖率(MISRA C:202…...
maven 项目添加 git-hook 脚本,约束提交内容格式
git 提交代码,推送代码,可以通过在 .git/hooks 目录中的 bash 脚本来做一定的验证工作。 本例使用插件 maven-antrun-plugin 自动输出脚本至 .git/hooks 目录中,在 pom.xml 中的使用示例如下: <plugin><groupId>org.…...
18、Flink的SQL 支持的操作和语法
Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...

泛微OA_lang2sql 任意文件上传漏洞复现
简介 泛微OA E-mobile系统 lang2sql接口存在任意文件上传漏洞,由于后端源码中没有对文件没有校验,导致任意文件上传。攻击者可利用该参数构造恶意数据包进行上传漏洞攻击。 漏洞复现 FOFA语法: title"移动管理平台-企业管理" 页…...

Rust编程基础核心之所有权(上)
1.什么是所有权? Rust 的核心功能(之一)是 所有权(ownership)。虽然该功能很容易解释,但它对语言的其他部分有着深刻的影响。 所有程序都必须管理其运行时使用计算机内存的方式。一些语言中具有垃圾回收机制&#x…...
优化改进YOLOv5算法之添加DCNv3模块,有效提升目标检测效果
目录 前言 1 DCNv3原理 1.1 DCNv2 1.2 DCNv3 1.3 模型架构 2 YOLOv5算法中加入DCNv3模块...

VSCode 连接不上 debian 的问题
之前一台笔记本上安装了 debian12,当时用 vscode 是可以连接上的,但今天连接突然就失败了,失败信息是这样的: 查看失败信息 因为 debian 是自动获取 ip 地址的,以前能连接上时,ip 地址是 104,然…...

【ElasticSearch系列-06】Es集群架构的搭建以及集群的核心概念
ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【三】ElasticSearch的高级查询Quer…...
软考高级系统架构设计师系列案例考点专题六:面向服务架构设计
软考高级系统架构设计师系列案例考点专题六:面向服务架构设计 一、面向服务架构设计内容大纲二、SOA概述和发展三、SOA和微服务的区别四、SOA的参考架构五、SOA主要协议和规范六、SOA设计标准和原则七、SOA设计模式八、SOA构建和实施一、面向服务架构设计内容大纲 SOA概述和发…...

【入门Flink】- 07Flink DataStream API【万字篇】
DataStream API 是 Flink 的核心层 API。一个 Flink 程序,其实就是对DataStream的各种转换。 代码基本上都由以下几部分构成: 执行环境(Execution Environment) 1)创建执行环境StreamExecutionEnvironment StreamExe…...

AI:55-基于深度学习的人流量检测
🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…...
node版本管理工具nvm
node版本管理工具nvm 要在本地拥有多个 Node.js 版本,并根据不同的环境切换不同的 Node.js 版本,你可以使用工具如 nvm(Node Version Manager)来管理和切换 Node.js 版本。 以下是关于如何使用这两个工具的简要说明:…...

stable-diffusion-webui安装Wav2Lip
常见错误 1.错误:Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check 修改代码: launch_utils.py 删除三个地方:...

Nacos-2.2.2源码修改集成高斯数据库GaussDB,postresql
一 ,下载代码 Release 2.2.2 (Apr 11, 2023) alibaba/nacos GitHub 二, 执行打包 mvn -Prelease-nacos -Dmaven.test.skiptrue -Drat.skiptrue clean install -U 或 mvn -Prelease-nacos ‘-Dmaven.test.skiptrue’ ‘-Drat.skiptrue’ clean instal…...

Linux 内核中根据文件inode号获取其对应的struct inode
文章目录 前言一、简介二、iget_locked2.1 简介2.2 内核中使用2.3 LKM demo 三、ext4_iget3.1 简介3.2 LKM demo 前言 文件inode号和struct inode结构体请参考: Linux文件路径,目录项,inode号关联 Linux文件系统 struct inode 结构体解析 一…...

Pycharm-community-2021版安装和配置
一、下载Pycharm-community-2021 1.从官网下载pycharm-community Pycharm 版本官网 二、安装PyCharm 1.打开下载完成的安装包,点击Next 2.安装PyCharm到其他位置,点击Next 3.一定把更新PATH变量勾上,可以创建桌面快捷方式,创建关联,最后…...

飞书开发学习笔记(一)-应用创建和测试
飞书开发学习笔记(一)-应用创建和测试 一.前言 现在大企业用的办公IM软件中,飞书是口碑最好的,不得不说,字节在开发产品方面,确实有自己独到的竞争力,比如说抖音、头条、飞书。在办公会议和云文档的体验上,其它的办公…...

【Mybatis小白从0到90%精讲】12:Mybatis删除 delete, 推荐使用主键删除!
文章目录 前言XML映射文件方式推荐使用主键删除注解方式工具类前言 在实际开发中,我们经常需要删除数据库中的数据,MyBatis可以使用XML映射文件或注解来编写删除(delete)语句,下面是两种方法的示例。 XML映射文件方式 Mapper: int delete(int id);Mapper.xml:...
RocketMQ批量发送消息❓
优点: 批量发送消息可以提高rocketmq的生产者性能和吞吐量。 使用场景: 发送大量小型消息时;需要降低消息发送延迟时;需要提高生产者性能时; 注意事项: 消息列表的大小不能超过broker设置的最大消息大小;消息列表…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...