📡 RPC 原理
RPC 调用链路 · Dubbo 架构 · 序列化 · gRPC
1. 一次 RPC 调用的完整过程?(手撕链路)
RPC = 像调用本地方法一样调用远程方法。核心链路:
- 客户端代理:调用方持有一个"接口的动态代理"(看似本地实现)
- 参数序列化:代理把方法名 + 参数对象序列化成字节流
- 网络传输:按协议(长度头 + 数据)发送到服务端(TCP/Netty)
- 服务端反序列化 + 找到实现类(路由分发)
- 执行方法 → 结果序列化返回
- 客户端反序列化 → 返回给调用方(同步等待或异步回调)
RPC 与 HTTP 调用的对比
HTTP(REST):
- 面向资源,语义化 URL,可读可调试(浏览器/curl)
- 基于 HTTP 协议(请求头重、JSON 文本序列化大)
- 适合:对外接口、跨语言、低延迟要求不极端
RPC:
- 面向方法,接口即契约,传输高效(二进制序列化+长连接)
- 自带注册发现/负载均衡/超时重试等治理能力
- 适合:微服务内部高频调用(Dubbo/gRPC)
🎯 面试要点
- 动态代理是 RPC 的入口(客户端),反射/映射是服务端分发的关键——与 Java 基础模块呼应
- RPC 三要素:序列化、网络传输、动态代理
2. Dubbo 的核心架构?
Dubbo(阿里开源,国内微服务主流)分层架构:
- Provider / Consumer:服务提供方 / 消费方
- Registry:注册中心(ZooKeeper/Nacos)——服务注册发现
- Monitor:监控中心(调用统计)
- Container:服务运行容器(Spring)
调用流程:Provider 启动注册 → Consumer 订阅列表并缓存 → 本地负载均衡选节点(默认加权随机)→ 集群容错(failover 失败重试 / failfast 快速失败)→ 过滤链(上下文/限流/监控)→ 序列化(Hessian2)→ Netty 传输。
🎯 面试要点
- 集群容错:Failover(重试其他节点,默认)、Failfast(快速失败)、Failsafe(失败忽略)、Failback(失败异步重试)、Forking(并行调多个取第一个成功)
- 服务降级:mock 参数返回兜底
- Dubbo3 支持 Triple 协议(HTTP/2 + gRPC 兼容),云原生方向
3. 序列化方式对比与选择?
| 方式 | 特点 | 适用 |
|---|---|---|
| JSON(Jackson/Gson) | 可读、跨语言、体积大 | HTTP 接口、日志 |
| Hessian2 | 二进制、跨语言、Dubbo 默认 | Java RPC |
| Protobuf | 最快最小、强类型、需 .proto 定义 | gRPC、高性能链路 |
| Java 原生 | 仅 Java、有安全问题、性能差 | 不推荐 |
| Kryo/FST | Java 生态快、需注册类 | Java 内部高性能 |
🎯 面试要点
- 选型维度:性能、体积、跨语言、兼容性(字段增删)、安全性
- 兼容性实践:序列化版本号 serialVersionUID、新增字段默认值
4. gRPC 的特点?
- Google 开源,基于 HTTP/2(多路复用、双向流、头部压缩)
- Protobuf 序列化(.proto 文件定义接口和消息,自动生成代码)
- 支持四种调用:一元、服务端流、客户端流、双向流
- 跨语言:Java/Go/C++/Python 等生成客户端服务端
🎯 面试要点
- 对比 Dubbo:gRPC 强在跨语言 + HTTP/2 生态(云原生标配);Dubbo 强在治理功能丰富(Java 生态)
- gRPC 用 HTTP/2 而非自定义 TCP 协议——学习成本低、可观测性好