RPC 到底是什么:微服务内部调用的首选,以及它藏起来的三个坑

简介: RPC 是什么?微服务内部为什么用 RPC 调用而不用 HTTP?本文从一次远程调用讲起,讲清 RPC 框架解决了什么问题、怎么用,以及它藏起来的三个坑。

大家好,我是晚安code。

这篇不打算重复那些「定义 + 通信流程 + 框架对比」的套路,我想聊的是:RPC 的甜头来自「像本地调用一样」,它所有的坑也全部来自「它毕竟不是本地调用」。看完你至少能判断,自己项目里那几十个 RPC 调用,哪些是安全的,哪些是埋在线上的一颗雷。

一、RPC 是什么:一次调用,怎么就跑到了另一台机器上

RPC(Remote Procedure Call,远程过程调用):让调用方像调用本地方法一样,去调用另一台机器上的方法,把寻址、序列化、网络收发这些事全部藏进框架里。类比:你在外卖软件上下单点一份牛肉面,只要说清楚要什么,骑手怎么找路、厨房在哪栋楼、配送箱保不保温,都不用你管。

这个类比得往下再走一步,因为这里正好是第一个分岔口——外卖送到你手上,和你在楼下自己煮一碗面,中间差着的东西,恰恰是 RPC 隐藏掉的全部复杂度。

序列化(Serialization):把内存里的对象转成能在网络上传输的字节流,接收端再还原成对象,后者叫反序列化。类比:把一台组装好的家具拆成平板打包寄走,收件人照着图纸拼回去——拆和拼都不难,难的是图纸不能有歧义。

一次 RPC 调用,代码上只有一行,实际跑起来是这么一条链:

1)你写的 userService 其实不是实现类,是一个动态代理生成的桩,它长得像接口,干的却是打包的活。

2)代理把「接口名 + 方法名 + 参数」序列化成一段二进制。网络只认字节,不认 Java 对象,这一步绕不开。

3)二进制顺着一条已经建好的长连接发出去。注意是长连接——每次调用都重新握手,那是 HTTP/1.1 时代的做法。

4)对端的解码器把字节还原成对象,查路由表找到真正的实现类,反射调用它。

5)返回值再反过来走一遍序列化和网络,最后你的 getUser(id) 拿到了一个 User 对象。

RPC 一次调用的完整链路时序图:动态代理、序列化、长连接传输、反序列化、反射调用

图里我特意把「动态代理」放在最前面。很多人以为 RPC 的魔法发生在网络上,其实第一步就发生了:那行代码从写下的一刻起,就不是本地调用。

饭还是那碗饭,差的是中间那段路——那段路就是 RPC 帮你藏起来的。

二、RPC 到底解决了什么问题(它最早真不是为了性能)

搜 RPC 的文章,十篇里有九篇会说「为了性能」。这个说法不算错,但顺序反了。

RPC 这个概念的源头是 1980 年代的 Bruce Jay Nelson,他在论文里给的目标是「简单、高效、通用」——注意,简单排在高效前面。而微服务时代我们真正被它救过的,也不是那点吞吐量,是下面这三件具体的事。

第一件:不用每个团队自己重写一遍连接池。

三个团队各自用 HttpClient 封装了一套调用层。半年后的结果是:A 团队的重试是无限次,B 团队的重试是三次但不做退避,C 团队压根没超时。同一个上游服务抖了一下,三家的表现完全不同。后来统一 RPC 框架进来,第一件砍掉的事就是这三套各写各的。

序列化、收发线程、连接池、超时、状态机——这些是「业务之外」的技术劳动。一个团队写一遍是本事,十个团队写十遍是浪费。

第二件:调用方不该关心对端在哪台机器上。

服务实例会扩容、会缩容、会上线、会挂掉。如果调用方靠配置文件写死 IP,那运维每加一台机器,就得推一次配置重启一批应用。RPC 框架配一个服务发现(Service Discovery)就解决了:实例启动时把自己注册到注册中心,调用方从本地缓存里拿地址列表,节点变化时自动同步。类比:你不用背下全城每一家面馆的地址,打开外卖软件它自己知道谁在营业。

第三件:把「这是远程」这件事从业务代码里抹掉。

如果不封装,你每调一个远端方法都要手写一段「拼 URL、发请求、判状态码、解析 JSON、异常处理」。业务逻辑被稀释得只剩三成,剩下七成在跟网络打交道。RPC 把这七成收进了框架。

水面上的那一行代码是免费的,水面下的六件事是要还的。

三、为什么用 RPC,而不是 HTTP、MQ 或者 WebSocket

先把一个常见的说法掰正:HTTP 是一种应用层协议,而 RPC 是一类调用模型。「HTTP 和 RPC 谁更强」这个问法本身就不成立,gRPC 的底座就是 HTTP/2。它们真正的分野在建模方式上——HTTP/REST 面向资源,RPC 面向方法。

GET /users/1001 描述的是「我要拿编号 1001 这个资源」;UserService.getUser(1001) 描述的是「我要执行 getUser 这个方法」。你的微服务边界是按业务能力切的,而业务能力天然是「一个个能调用的方法」,不是「一堆资源目录」。这是 RPC 在内部调用里更顺手的第一层原因。

第二层是工程上的具体差别,列成表更清楚:

对比维度 HTTP/REST RPC 框架(gRPC / Dubbo)
建模方式 面向资源:/users/1001 面向方法:UserService.getUser(id)
数据格式 文本 JSON,Header 偏大 二进制 Protobuf / Hessian,报文紧凑
连接方式 HTTP/1.1 多为短连接 + Keep-Alive 长连接 + 多路复用 + 连接池
服务发现 依赖 DNS 或网关转发 内置注册中心,实例上下线自动感知
对外兼容 浏览器、第三方直接可用 需要 SDK 或 IDL,浏览器不直接支持
调试成本 低,curl 就能打 中,得先有 .proto 和生成的桩

那什么时候该用 HTTP,什么时候该用 RPC?我的划分很土,但用了几年没出过问题:对外用 HTTP,内部用 RPC,异步用 MQ,推送用 WebSocket。

微服务通信边界图:客户端经 HTTP 接入网关,内部服务之间走 RPC 同步调用,跨域业务用消息队列异步解耦

边界画清楚之后有个附带好处:团队吵「用哪个」的次数明显变少了。给第三方开放的接口,你必须用 HTTP,因为这由对方的接入成本决定,不由你的偏好决定;反过来,订单服务调库存服务这种内部一跳,用 HTTP 就是给自己找麻烦。

有两个判断句我想单独拎出来说,因为它们和网上的主流说法相反:

「HTTP 更简单,所以内部调用也应该用 HTTP」——这句话只在接口数量少、团队规模小的时候成立。接口数一旦过百,没有契约约束的 JSON 就会变成一场灾难:字段名靠口口相传,类型靠运行时才发现,改一个字段没人知道影响了谁。

MQ 和 RPC 不是替代关系,是两种时间观。RPC 是你现在就要答案,MQ 是你先收下这件事、回头再处理。下单后扣积分这种「必须成功但可以晚一点」的操作,用 RPC 硬扛只会把两个服务绑在一条命上。

四、怎么应用:RPC 藏起来的三件事

这一节是全文我最想让你记住的部分。前面说了半天「像本地调用一样方便」,现在得说硬币的另一面。

第一件:它看起来是本地调用,但它会超时。

本地方法调用只有三种结局:返回、抛异常、死循环。RPC 有第四种:没有结局。请求发出去了,对方可能正在 GC、可能网络在丢包、可能对端进程已经挂了但 TCP 连接还没断。你的线程就那么挂着,一直挂着。

我见过最典型的一次事故:一个查询接口,上游给它的超时是 30 秒,它给下游的也是 30 秒。下游卡住的时候,上游连接池被占满,整个服务雪崩。正确的做法是给超时做预算,而不是给每一跳都配一个「默认值」——上游总共 800ms 的容忍度,那给下游最多 300ms,剩下 500ms 留给自己的处理和网络往返。超时不是越大越安全,越大越危险。

第二件:它看起来只会执行一次,但它可能重试。

「网络超时」这四个字是有歧义的。它可能是请求没发到,也可能是请求发到了、对方处理完了、但响应回来的路上丢了。你这边看到的结果一样,服务端那边的状态却完全不同。所以无脑重试一个「扣库存」的接口,就等着用户投诉吧。

幂等(Idempotent):同一个操作执行一次和执行多次,对系统状态的影响完全相同。类比:电梯的「关门」按钮你按几下都一样,门就是关上——它不因为你多按了三次就关三次。

工程上的落点很简单:调用方生成一个全局唯一的请求 ID 带上去,服务端拿它做去重,处理过的直接返回上次的结果。这件事必须在设计接口的时候就想,事后补的代价通常是改数据库。

第三件:它看起来像函数,但接口设计不该照着本地函数来。

这条最容易踩,因为它不报错。有些团队用 RPC 用得跟没用一样——一个接口叫 doSomething,参数是一个大的 JSON 字符串,返回值也是 JSON 字符串,业务字段全靠字符串里解析。这就麻烦了:你把 RPC 当成了 HTTP 用,那么 RPC 的好处你一样没拿到。

所以 RPC 的接口要切得细一点、语义明确一点:getOrderById 和 listOrdersByUser 就是两个接口,不该为了「少写两个方法」硬合并成一个 queryOrder。接口数量少不等于设计好,语义清楚才算好。

正确的用法长这样——先用 IDL 写契约,再生成调用桩,调用方拿到的是一份有类型的接口:

五、RPC 真正的好处:它把跨进程调用变回一份可检查的合同

知道了坑在哪,再回头看好处,你会发现它们其实是同一件事的两面。

好处一:契约是编译期的。

这是我认为 RPC 最被低估的价值。写完 .proto 或者接口定义,代码生成器会给你一份带类型的桩。字段类型改了、方法签名变了,调用方编译就过不去。这不是「节省时间」,这是把一整类线上事故提前到了本地。用裸 HTTP + JSON 的时候,字段对了错了,只有跑起来才知道。

好处二:跨语言是真的跨语言。

服务 A 用 Java,服务 B 用 Go,服务 C 用 Rust,只要它们认同一份 IDL,互相调用就不用为对方改写架构。这一点在收购、合并、多团队并行的时候价值特别明显——你不用劝另一个团队换语言。

好处三:服务治理是内建的,不是外挂的。

负载均衡、失败重试、熔断降级、灰度路由、链路追踪、实例上下线无感——这些东西如果自己基于 HTTP 搭,每一项都是一个独立项目。RPC 框架把它们做成了配置项。

好处四:长连接扛得住高并发。

对内部的短平快调用来说,每次请求都走一遍三次握手是纯浪费。长连接 + 多路复用把这块开销压掉了。这也是为什么秒杀、Feed 流这类场景,内部链路基本清一色是 RPC。

截至 2026 年 10 月,主流选择基本就三个:gRPC(HTTP/2 + Protobuf,多语言、支持流式,跨语言场景首选)、Dubbo(Java 生态里服务治理最完整的,triple 协议在语义上和 gRPC 对齐)、Thrift(老牌,多语言,但生态热度不如前两个)。选型的顺序我建议是:先看团队主语言,再看要不要跨语言,最后才比性能——因为对绝大多数业务来说,这三者的性能差距都不是瓶颈。

可能有人会问:gRPC 底层就是 HTTP/2,那「内部用 RPC 不用 HTTP」这句话是不是自相矛盾?

不矛盾。协议是运输工具,RPC 是说怎么建模、怎么治理。gRPC 用 HTTP/2 当底座,但它给你的是 IDL 契约、代码生成、流式语义和一套治理能力——这些东西 HTTP/2 本身并不提供。你完全可以手写 HTTP/2 请求,只是那样你就得自己把 RPC 框架又实现一遍。

可能有人会问:我们团队接口不到 20 个,是不是没必要上 RPC 框架?

大概率是的。接口少、团队小的时候,裸 HTTP + 一份约定好的 JSON schema 跑得又轻又快,引入 RPC 框架反而增加了构建和调试成本。我的经验阈值是「服务数过 10 个、或者有跨团队调用」——到这个时候,寻址和契约的一致性会开始收税。

六、写在最后:RPC 让你忘记网络,但你不能真的忘

回到开头那个 userService.getUser(id)。

RPC 做的事情,本质上是在工程上给「分布式」这件事做了一次精致的包装:它让你写代码的时候可以假装没有网络。这个假装是有价值的,它让业务逻辑重新变成业务逻辑。

但假装归假装,线上不会陪你演戏。每一次「像本地调用」的舒适,背后都该有一次「它不是本地调用」的清醒——超时写了没有,重试幂等了没有,这个接口的语义是不是切得够清楚。

把这三件事做到,RPC 才真的帮你省事;做不到,它就只是把一次故障从三天前挪到了上线当天。


我是晚安code,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你们项目里的 RPC 调用,超时和幂等这两件事,是设计的时候就定好的,还是出事之后补上的?

目录
相关文章
|
14天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
8044 15
|
12天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1788 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
12天前
|
人工智能 并行计算 PyTorch
秋叶 ComfyUI 2026 整合包 v3.2 完整部署教程:Python 3.13 + Torch 2.13 全栈升级
秋叶aaaki ComfyUI 2026年8月整合包v3.2正式发布!全面升级Python 3.13.11、PyTorch 2.13.0+cu130及ComfyUI v0.30.2,原生支持MiniMax H3、Wan 2.2、Qwen-Image-2.1等2026主流音视频/图像模型,解压即用,无需环境配置。
2018 12
|
10天前
|
人工智能 编解码 并行计算
MiniMax-H3 一键整合包技术文档:8G 显存运行 AI 漫剧制作 —— 角色替换 / 动作迁移 / 文图生视频部署与调参指南
MiniMax H3 是 MiniMax 开源的全模态视频生成模型,支持文/图/音/视多条件输入,输出最高2K、15秒带双声道音频视频。本文档详述其Int8量化版在8GB显存下的本地一键部署、三段式工作流(EDIT/REPLACE/CONTINUE)、参数调优及常见问题排查。(239字)
|
6天前
|
人工智能 Linux 开发者
【2026国内使用】Codex安装过程一篇讲透(Win/Mac/Linux全支持)
Codex是OpenAI推出的AI编程智能体,可读取本地项目、理解需求并自动修改代码。支持桌面GUI、命令行(CLI)及VS Code/Cursor插件三种形态,覆盖可视化操作、终端高效开发与编辑器无缝集成场景,助开发者用自然语言驱动编码全流程。(239字)
【2026国内使用】Codex安装过程一篇讲透(Win/Mac/Linux全支持)
|
26天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
3836 10
|
20天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
2157 1

热门文章

最新文章