RPC 远程过程调用专题:原理、调用流程、序列化、服务发现、Dubbo 与 gRPC
RPC(Remote Procedure Call,远程过程调用)的目标只有一个:让调用远程服务像调用本地方法一样自然,业务代码只面对接口,序列化、网络传输、寻址、容错全部交给框架。本文拆解一次调用的完整链路,并横向对比 Dubbo、gRPC、OpenFeign 三种主流方案。
RPC 的本质
本地调用是同一进程内的方法跳转:参数在栈上传递,失败就是抛异常。远程调用要跨过进程边界:参数得变成字节流、字节流得走网络、对端的方法得先被找到,连失败的语义都变得模糊。RPC 框架做的事,是用动态代理在调用方生成一个”长得像本地接口”的 Stub,把这些差异全部挡在代理背后。
它解决的不是”能不能通信”——裸 HTTP 客户端也能通——而是把通信细节标准化、可治理化,让业务代码不需要感知网络的存在。
一次调用的完整链路
调用方 服务方 |
链路上四个环节缺一不可:
- 动态代理(JDK 动态代理、ByteBuddy、Javassist)把方法签名和参数打包成调用描述对象,业务无感知,同时给框架留出插入治理逻辑的切面;
- 序列化决定跨语言能力与包体大小:Java 原生序列化只限 JVM 且体积大,Hessian2、Kryo 快但偏 Java 体系,Protobuf 跨语言且紧凑,代价是要维护 IDL;
- 网络传输普遍基于 Netty 做异步 NIO,长连接复用避免反复建连的开销;
- 服务发现让地址不再写死:Provider 注册、Consumer 订阅,实例上下线由注册中心实时推送,负载均衡在列表中挑选实例。
超时、重试、熔断这类治理策略统一挂在调用链路上,而不是散落在每个业务方法里——这正是框架相对裸 HTTP 的核心价值。
主流框架对比
| 维度 | Dubbo | gRPC | Spring Cloud OpenFeign |
|---|---|---|---|
| 传输协议 | 私有 TCP(Dubbo2)/Triple(HTTP/2) | HTTP/2 | HTTP/1.1 |
| 契约形式 | Java 接口 | Protobuf IDL | Java 接口注解 |
| 跨语言能力 | 弱,Triple 在改善 | 强,官方多语言 | 弱,绑定 JVM 体系 |
| 治理能力 | 内置注册发现、路由、限流熔断、监控 | 核心精简,治理依赖 xDS/服务网格 | 依赖 Spring Cloud 组件拼装 |
| 典型场景 | 国内 Java 微服务内部调用 | 多语言、移动端、需穿透网关 | Spring Cloud 体系内声明式 HTTP 调用 |
选型逻辑很直接:纯 Java 且要求治理开箱即用选 Dubbo;多语言栈或流量要走网关选 gRPC;已经在 Spring Cloud 生态里、性能要求不极端,OpenFeign 最省心。
工程实践与常见误区
- 必须显式设置超时,框架默认值通常和你的下游 P99 对不上;
- 重试只给幂等接口,非幂等接口重试会在故障时放大事故;
- 接口演进保持向后兼容:只加字段、不改语义、不删方法,否则序列化层会替你把事故变成 ClassNotFound;
- 别迷信”RPC 一定比 HTTP 快”:gRPC 就跑在 HTTP/2 上,差距主要在序列化效率、连接管理和治理成本,不在协议名字。
面试视角
为什么 RPC 框架普遍用动态代理? 因为入参打包、网络收发、结果解析都是模板代码,代理把它们收进 Stub,业务才能像调本地方法一样调远程服务,治理逻辑也有了统一的插入点。
RPC 和 HTTP 是什么关系? 两者不在同一层:RPC 是调用模型,HTTP 是传输协议。RPC 可以跑在私有 TCP 上,也可以跑在 HTTP/2 上(gRPC 就是例子);反过来,手写 HTTP 客户端调接口只是在用 HTTP 协议裸做远程调用,缺契约也缺治理。
小结
- RPC 的本质是用代理屏蔽远程细节,链路核心四件套:动态代理、序列化、网络传输、服务发现。
- 框架选型看语言栈与治理诉求:Dubbo 重治理、gRPC 重跨语言、OpenFeign 重 Spring 生态整合。
- 超时显式化、重试幂等化、接口向后兼容,是 RPC 生产化的三条及格线。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Dai Wei!
评论

