详细解释下RPC 模式
2026-03-20
当然可以。我用尽量小白、接地气的方式给你讲清楚。
什么是 RPC 模式
RPC,英文全称叫 Remote Procedure Call,中文一般叫:
远程过程调用
光看这个名字很吓人,其实你可以把它理解成一句特别简单的话:
像调用自己电脑里的一个函数一样,去调用另一台机器上的函数。
也就是说:
你本来写代码时,可能会这样调用本地方法:
$result = UserService::getUserInfo(1001);
这是本地调用。
而 RPC 的目标是:
明明这个 getUserInfo 不在你这台机器上,而是在另外一台服务器上,但你调用起来,感觉还是像在调用一个普通方法。
这就是 RPC 的核心思想。
先别急着看“远程”,先理解“本地调用”是什么
你平时写代码,经常会这么干:
1. 调用一个函数
sum(1, 2)
2. 调用一个类的方法
$userService->getUserById(1)
3. 调用一个工具类
$this->psassService->verifyUser($params)
这些都有一个共同点:
你不关心它内部怎么做,你只管传参数,然后拿结果。
比如:
你调 getUserById(1),你根本不需要每次都去想:
SQL 怎么写
数据库怎么连
表名是什么
中间经历了哪些逻辑
你只知道:
我给它一个用户 id,它给我一个用户信息。
RPC 就是把这个体验,扩展到了“跨机器调用”。
用一个最生活化的例子理解 RPC
你可以把 RPC 想成:
你在办公室,想让隔壁办公室的人帮你查资料
你自己桌上没有这份资料。
资料在隔壁办公室老王那。
你现在有两种做法。
第一种:你自己过去查
你走过去,敲门,进去翻柜子,找文件,抄下来,再回来。
这就像:
你直接去访问对方系统、自己处理一大堆细节。
第二种:你给老王打电话
你说:
“老王,帮我查一下 1001 这个员工的信息。”
老王那边去查,查完后告诉你:
“这个员工叫江天,手机号是 xxx。”
你根本不用过去,也不用知道资料柜在哪。
你只要“发请求”,然后“拿结果”。
这就像 RPC。
所以 RPC 本质上就是:
把“找远方的人办事”这件事,包装得像“我本地调了一个方法”。
RPC 模式到底解决什么问题
它主要解决的是:
系统拆开之后,模块之间如何互相调用。
比如一个公司系统越来越大,通常不会所有功能都塞在一个项目里。
可能会拆成:
1. 用户服务
专门管用户信息
2. 权限服务
专门管角色和权限
3. 订单服务
专门管订单
4. 支付服务
专门管支付
5. 消息服务
专门管短信、邮件、站内信
这时候,订单服务想知道某个用户信息,就不能每次都复制一套用户逻辑。
它要去调用“用户服务”。
调用方式有很多种,RPC 就是其中一种。
小白最容易懂的一句话定义
RPC 模式你就记住一句话:
把调用远程服务器上的功能,包装得像调用本地函数。
RPC 模式的完整流程,到底发生了什么
表面上你写的是:
$user = $userService->getUserInfo(1001);
你感觉只是调了个方法。
但实际上背后发生了很多事。
第一步:你本地先把请求整理好
比如你要调用:
getUserInfo(1001)
系统会先把这个信息打包成一个“请求包”,里面大概有:
你要调哪个服务
你要调哪个方法
参数是什么
请求编号是多少
比如可能变成这样一种数据:
{
"service": "UserService",
"method": "getUserInfo",
"params": [1001]
}第二步:通过网络发给远程服务器
这个请求不会凭空过去,而是通过网络传过去。
可能底层走的是:
TCP
HTTP
gRPC
WebSocket
或其他通信协议
你作为业务开发,很多时候不一定直接看到这些细节。
第三步:远程服务器接到请求
远程机器收到后,会看:
你要找哪个服务
你要执行哪个方法
参数是什么
然后它真的去执行:
getUserInfo(1001)
第四步:远程服务器返回结果
执行完之后,把结果再打包回来。
比如:
{
"code": 0,
"data": {
"id": 1001,
"name": "江天"
}
}第五步:你本地收到结果并还原
本地程序拿到返回值后,再把它还原成你代码里需要的对象、数组或者结果值。
最后你感觉就像:
$user = $userService->getUserInfo(1001);
特别自然。
所以 RPC 的关键点不在“调用”,而在“伪装”
这是理解 RPC 最重要的一点。
RPC 最厉害的地方不是它能联网,而是它做了一层“伪装”:
让远程调用看起来像本地调用。
这会给开发者一种很顺滑的体验。
但也正因为这种“像本地”,很多新手反而容易掉坑。
因为:
它看起来像本地,实际上不是本地。
而只要不是本地,就一定会有很多额外问题。
RPC 和普通 HTTP 接口有什么区别
这是很多人最容易混淆的地方。
先说相同点
两者本质上都在做一件事:
一台机器请求另一台机器,让另一台机器执行逻辑后返回结果。
所以从本质上说,RPC 和 HTTP API 都属于“远程调用”。
主要区别
1. HTTP 更像“访问网址”
比如:
/api/user/detail?id=1001/api/order/create
你会比较明确地感觉到:
我是在请求一个接口。
2. RPC 更像“调方法”
比如:
$userService->getUserInfo(1001) $orderService->createOrder($data)
你会更像是在调用程序里的函数。
所以直白讲:
HTTP API 更像访问网页地址,RPC 更像调用远程方法。
再举个特别通俗的区别
HTTP 接口像点外卖
你打开 app,找到店铺,点进菜单,选择商品,下单。
你会明显感觉自己在“访问一个外部服务”。
RPC 像叫家里人帮你递个东西
你喊一句:
“把桌上的水杯递给我。”
你不关心对方怎么走过去、怎么拿,只要结果。
RPC 强调的是这种“像本地协作”的感觉。
为什么很多大系统喜欢 RPC
因为当系统拆成很多服务后,服务和服务之间会频繁调用。
比如:
订单服务调库存服务
库存服务调商品服务
商品服务调价格服务
价格服务调营销服务
如果全部都按非常原始的 HTTP 接口方式去手写,开发会很繁琐:
自己拼 URL
自己拼参数
自己处理返回结构
自己处理序列化
自己处理异常
自己处理超时
自己处理重试
RPC 框架会把这些公共动作封装掉。
于是开发者只需要像这样写:
$stockService->deduct($skuId, 2);
体验会很统一。
所以很多大型微服务架构里,会比较喜欢 RPC。
RPC 模式里常见的几个角色
这里你可以简单记四个角色。
1. 调用方
也叫客户端
就是“谁发起调用”。
比如订单服务要查用户信息,订单服务就是调用方。
2. 提供方
也叫服务端
就是“谁提供能力”。
比如用户服务提供 getUserInfo 方法,那用户服务就是提供方。
3. 注册中心
有些 RPC 框架里会有这个东西
它像一个“通讯录”或者“黄页”。
作用是:
告诉调用方,某个服务现在在哪台机器、哪个端口。
不然你都不知道去哪里找。
4. 网络通信层
就是负责真正把请求发过去、把结果拿回来。
这个小白不用钻太深,知道它存在就行。
为什么说 RPC 看似简单,其实比本地调用复杂很多
因为本地调用几乎不会有网络问题,但 RPC 一定会遇到下面这些问题。
第一类问题:网络不通
你调用本地函数,函数就在内存里。
RPC 不一样,隔着网络。
所以会遇到:
对方服务挂了
网络断了
DNS 解析失败
端口不通
防火墙拦截
这时候,方法就不是“正常返回”,而是直接报错或者超时。
第二类问题:超时
本地函数可能 1 毫秒就执行完。
远程函数可能:
网络传输 50ms
对方处理 200ms
对方数据库慢 2 秒
对方系统卡住 10 秒
所以 RPC 必须考虑超时。
不然你这个请求可能一直卡死。
第三类问题:序列化和反序列化
本地方法传对象很方便。
远程调用不行。
因为数据要过网络,所以必须先变成一种可传输格式,比如:
JSON
Protobuf
MsgPack
二进制协议
这叫序列化。
对方收到后再还原成对象,这叫反序列化。
这里如果格式不一致,就会出问题。
第四类问题:版本不兼容
你本地函数改了参数,自己项目里一起改就行。
RPC 不一样。
比如你今天把接口改成:
getUserInfo($id, $mobile)
但对方系统还按老版本只传一个 $id。
那就炸了。
所以 RPC 特别怕服务升级不一致。
第五类问题:重试和幂等
有时候请求发过去了,但你没收到响应。
那到底是:
对方没执行?
还是已经执行了,只是结果回来的路上丢了?
这时候如果你重试,就可能导致重复执行。
比如扣款、下单、发短信,这都很危险。
所以 RPC 系统很强调:
幂等性
请求唯一号
去重机制
重试策略
为什么有人说“RPC 不是真正的透明”
因为它虽然想让你“感觉像本地调用”,但它永远不可能真的和本地一样。
原因很简单:
远程调用永远存在网络不确定性。
本地调用几乎默认是确定的。
远程调用天然不确定。
所以一个成熟工程师看到 RPC 调用时,脑子里其实会自动多一层意识:
这不是普通函数,这是一次跨网络调用。
这点非常重要。
那 RPC 模式有哪些优点
一、调用体验好
你写起来像本地方法调用,比较顺手。
二、服务拆分清晰
哪个服务提供什么能力,边界更明确。
三、便于大型系统协作
很多团队可以各自维护服务,再通过 RPC 协作。
四、可以统一治理
成熟 RPC 框架通常会带很多能力:
服务发现
负载均衡
超时控制
熔断降级
链路追踪
权限控制
监控报警
这些很适合企业级系统。
RPC 模式有哪些缺点
一、排错更复杂
本地函数出错,直接看代码。
RPC 出错,可能是:
调用方问题
网络问题
注册中心问题
服务端问题
序列化问题
版本问题
超时问题
排查链路长得多。
二、耦合可能变隐蔽
表面看像方法调用,很舒服。
但一舒服,大家就容易无脑互调,最后服务之间缠成一团。
三、对基础设施要求高
真正把 RPC 用好,通常需要:
注册中心
服务治理
监控系统
日志系统
链路追踪
统一异常规范
不是随便写个调用就完事。
四、对新人容易造成误导
新人看:
$userService->getUserInfo(1)
会下意识觉得这跟本地调用一样轻。
实际上背后可能很重。
一个特别形象的比喻:本地函数 vs RPC
你可以这样记忆。
本地函数调用
像你伸手去拿桌上的笔。
很快,很确定,几乎不会失败。
RPC 调用
像你打电话让另一个城市的朋友帮你买笔再寄给你。
你看起来只是“说一句”,但背后多了很多不确定因素:
电话能不能打通
对方在不在
对方有没有听清
有没有买错
快递会不会丢
多久能送到
所以:
RPC 在代码层面像函数,在现实层面像一次跨城市协作。
在实际开发里,什么时候会用 RPC
一般是这些场景。
一、微服务之间互调
最典型。
比如:
用户中心
订单中心
支付中心
风控中心
这些之间互相调用。
二、内部高频服务调用
公司内部自己家的多个服务之间,需要高频通信。
三、追求更统一的服务治理
想把超时、重试、监控、路由这些统一起来。
四、不希望每次都手写接口请求细节
想让开发体验更像“调方法”。
常见 RPC 框架有哪些
你不用死记,我简单让你有个概念。
Java 体系常见
Dubbo
gRPC
Spring Cloud OpenFeign(严格说更偏 HTTP 调用封装,但很多人会放一起理解)
Go / 多语言常见
gRPC
PHP 里也有类似远程服务调用方案
虽然 PHP 传统上更多直接写 HTTP 接口,但也能做 RPC 风格封装。
gRPC 和 RPC 是什么关系
这个也很多人会混。
RPC 是一种思想。
gRPC 是一种具体实现。
就像:
“交通工具”是一个大类
“汽车”是其中一种具体实现
所以别把 RPC 和 gRPC 画等号。
你可以把 RPC 模式理解成这张脑图
RPC 模式 ├── 目的:像调本地函数一样调远程服务 ├── 本质:跨网络请求 + 方法调用封装 ├── 优点:开发顺手、系统解耦、便于治理 ├── 风险:网络不稳定、超时、版本不兼容、排错复杂 └── 核心提醒:看起来像本地,实际上是远程
如果用你的工作场景来理解
结合你平时做企业系统、接口对接、服务封装,我给你套一个更贴近业务的例子。
比如你有一个“评估系统”,里面有个方法:
$oaService->verifyUser($tenantId, $mobile);
如果这个 verifyUser 实际上不是你本系统本地查库,而是去调用另外一台 OA 系统服务,那么这就已经带有 RPC 思维了。
也就是说:
你业务层只管写:
$result = $oaService->verifyUser($params);
至于背后:
请求地址是什么
怎么签名
怎么编码
怎么传输
怎么解析
怎么处理异常
都被封装到 oaService 里面去了。
这就是一种很典型的“让远程调用看起来像本地方法”的做法。
最后帮你用一句最白的话收尾
RPC 模式,你就把它理解成:
我电脑上的程序,去“遥控”另一台电脑帮我干活,但代码写起来像是在调自己家方法。
这个理解,基本就不会偏。
再帮你做一个超短记忆版
一句话
RPC = 远程调用像本地调用
两个关键词
远程、像本地
一个警告
看着像本地,其实不是本地
如果你愿意,我下一条可以继续给你讲:
HTTP 接口、RPC、消息队列,这三者到底有什么区别,我可以用你现在做接口对接的真实场景给你画成一张特别好记的图。
发表评论: