← 返回题目列表

远程代理和 RPC 框架有什么关系?

高频 中等 第 9 / 25 题 更新于 2026/07/28
代理模式远程代理RPC分布式

简化版

远程代理是代理模式的一种,它让调用方像调用本地对象一样调用远程服务。RPC 框架通常会为接口生成代理对象,代理对象负责序列化、网络通信、负载均衡、超时重试和结果反序列化。

详细版

远程代理的目标是屏蔽远程调用细节。

调用方看到的是:

UserService userService = rpcClient.getProxy(UserService.class);
User user = userService.getUser(1001L);

看起来像本地方法调用,但实际上代理对象背后做了很多事情:

  1. 拦截接口方法调用;
  2. 解析方法名、参数类型、参数值;
  3. 将请求序列化;
  4. 选择服务实例;
  5. 通过网络发送请求;
  6. 等待远程响应;
  7. 反序列化返回值;
  8. 处理超时、异常、重试、熔断等问题。

调用链可以理解为:

客户端 -> 本地代理对象 -> 网络请求 -> 服务端真实对象

所以 RPC 框架中的客户端 Stub、Feign Client、Dubbo 接口代理,本质上都能看到远程代理思想。

需要注意:远程代理虽然让调用形式像本地调用,但远程调用仍然有网络延迟、失败、超时、序列化成本,不能真的当成本地方法一样随意调用。

完整版教学

一、远程代理解决的核心问题

在分布式系统中,服务不一定在同一个进程里。

订单服务可能要调用用户服务:

订单服务进程 -> 用户服务进程

如果每次都手写 HTTP 请求、序列化、反序列化、错误处理,业务代码会非常重:

String json = httpClient.post(url, body);
User user = objectMapper.readValue(json, User.class);

远程代理希望把这些细节藏起来,让调用方只依赖接口:

User user = userService.getUser(userId);

调用方关心业务语义,代理对象关心通信细节。

二、RPC 代理对象通常做了什么

一个 RPC 客户端代理对象通常要处理:

  • 接口方法映射:知道调用的是哪个服务、哪个方法;
  • 参数封装:把参数名、类型、值放进请求;
  • 序列化:把对象转成字节流或 JSON;
  • 服务发现:找到可用服务实例;
  • 负载均衡:多个实例中选一个;
  • 网络传输:通过 TCP、HTTP、HTTP/2 等发送;
  • 超时控制:避免调用无限等待;
  • 重试策略:失败时是否重试;
  • 熔断降级:远程服务不稳定时保护调用方;
  • 反序列化:把响应转回 Java 对象。

这些都不是业务逻辑,却是远程调用必须面对的访问过程。代理模式非常适合承载这些逻辑。

三、为什么远程调用不能完全等同本地调用

远程代理会让代码写起来像本地调用,但语义上不能真的当成本地调用。

本地调用通常:

  • 延迟很低;
  • 成功率高;
  • 异常模型简单;
  • 参数传引用或值由语言决定;
  • 不涉及网络分区。

远程调用则可能:

  • 网络超时;
  • 服务不可用;
  • 请求重复发送;
  • 响应丢失;
  • 序列化失败;
  • 版本不兼容;
  • 部分成功。

因此,使用 RPC 代理时要特别注意超时、幂等、重试、限流和降级。

四、远程代理和本地代理的区别

本地代理通常增强的是权限、日志、事务、缓存等逻辑。

远程代理增强的是通信过程:

本地代理:控制访问本地对象
远程代理:把访问转发到远程对象

不过二者本质一样:客户端都不是直接访问真实对象,而是访问代理对象。

远程代理只是代理对象和真实对象之间隔了一层网络。

五、面试中怎么回答 RPC 与代理模式

一个比较完整的回答可以这样组织:

RPC 框架通常会给服务接口生成客户端代理对象,调用接口方法时进入代理,代理负责把本地方法调用转换成远程请求,包括序列化、服务发现、负载均衡、网络传输、超时重试和反序列化。它体现了远程代理模式,让调用方以接口方式使用远程服务,但工程上不能忽略网络失败和分布式语义。

这个回答既讲了模式,也讲了工程边界。

六、本地接口背后的远程失败语义

本地方法可能 1 ms 返回,RPC 经序列化 1 ms、网络往返 20 ms、服务处理 5 ms,总耗时约 26 ms,且任一阶段都可能超时。

stub -> encode -> network -> server dispatch -> target -> encode -> network -> stub

这个推演把模式带来的收益和成本放在同一条调用链上。设计评审时既要确认结果正确,也要确认额外层次没有改变原有契约。

七、边界、代价与验证

检查维度应确认的内容
正确性位置透明不等于语义透明:看到普通方法签名,也要按分布式调用设计超时和幂等。
适用边界远程代理只能隐藏通信细节,不能抹平超时、部分失败、重试重复执行和版本兼容。
测试证据覆盖正常路径、异常路径、空值或未知类型,并断言调用次数与顺序
运行成本记录额外对象、调用层数、延迟、线程或内存开销,不用模式名称代替测量

模式落地后要用单元测试验证独立职责,用集成测试验证对象装配和真实调用入口。涉及并发、远程或异步时,还要补充竞态、超时、重复执行与资源释放测试。

易错点:位置透明不等于语义透明:看到普通方法签名,也要按分布式调用设计超时和幂等。

八、常见误区与追问

  • 误区:RPC 代理让远程调用和本地调用完全等价。 网络带来延迟、不确定失败和序列化边界,调用方必须显式治理。
  • 误区:代理类存在,就代表所有调用都会经过代理。 只有客户端持有并调用代理引用时增强才生效;绕过代理直接调用目标对象,调用链自然不会出现增强。
  • 误区:示例代码能运行,就代表模式边界设计正确。 能运行只证明一条路径,仍要检查异常、并发、顺序、生命周期以及新增实现时是否修改稳定代码。
  • 追问:为什么重试可能造成一次调用执行两次? 客户端超时不代表服务端未完成;若再次发送且服务端没有幂等键,就可能重复执行。
  • 追问:代理模式和装饰器模式能只靠类图区分吗? 不能;两者都可能包装同一接口,必须结合“控制访问”还是“叠加职责”的设计意图区分。
  • 追问:怎样验证这套设计没有改变原有语义? 先做基线行为测试,再对新增层验证返回值、异常类型、调用次数和顺序;性能敏感处还要比较改造前后的量化指标。

九、加强记忆

远程代理就是“本地门面,远程执行”。RPC 让你写起来像本地方法,但代理背后跑的是网络通信;调用形式被简化了,分布式风险没有消失。