无尘阁日记

无尘阁日记

详细解释下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、消息队列,这三者到底有什么区别,我可以用你现在做接口对接的真实场景给你画成一张特别好记的图。