第28章 RPC 框架异常:Dubbo / gRPC

第28章 RPC 框架异常:Dubbo / gRPC

28.1 Dubbo 常见异常

异常 触发场景
RpcException Dubbo RPC 调用过程中的通用异常,code 字段区分具体类型(超时、网络异常、序列化异常等)
TimeoutException(RpcException 的一种,isTimeout() 返回 true) 调用超过配置的 timeout 时间未返回
RemotingException 网络层通信异常(连接失败、连接断开等)
RpcException(No provider available) 服务发现失败,注册中心中找不到对应的 Provider 实例(服务未启动、或者服务分组/版本号配置不匹配导致过滤后无可用实例)

超时问题的典型排查路径:

java 复制代码
@Reference(timeout = 3000, retries = 2) // 单次调用超时3秒,失败后重试2次
private UserService userService;

关键提醒:retries 配置的重试机制只对幂等的读操作安全 ,对于写操作(如扣款、下单),超时后自动重试可能导致同一个操作被执行多次(第一次调用可能实际已经在 Provider 端成功执行,只是响应因为网络原因没有及时返回给 Consumer,被误判为超时后自动重试,就会造成重复执行)。因此写类接口通常应该显式设置 retries = 0,把重试的决策权交给业务层结合幂等设计来处理,而不是依赖框架的无脑重试。

"No provider available"排查清单:

  1. Provider 服务是否已经成功启动并注册到注册中心(查看注册中心控制台,如 Nacos/ZooKeeper 的服务列表)。
  2. Consumer 和 Provider 配置的 group/version 是否一致(Dubbo 支持按分组和版本号做服务隔离,配置不一致会导致 Consumer 找不到匹配的 Provider)。
  3. 网络策略(安全组/防火墙)是否放通了 Consumer 到 Provider 之间的端口。

28.2 gRPC 常见异常与状态码

gRPC 使用 StatusRuntimeException(非受检)统一表达调用失败,核心是 Status.Code 枚举,常见状态码及含义:

Status Code 含义 常见触发场景
DEADLINE_EXCEEDED 调用超过设置的截止时间 类似 HTTP 超时,网络延迟或服务端处理慢
UNAVAILABLE 服务不可达 目标地址连接失败、服务端过载主动拒绝连接
UNIMPLEMENTED 调用的方法在服务端没有实现 客户端/服务端 proto 定义版本不一致,客户端调用了服务端尚未实现的新接口
INVALID_ARGUMENT 请求参数不合法 服务端对入参做了校验并主动拒绝
INTERNAL 服务端内部错误 服务端代码抛出了未被妥善处理的异常
RESOURCE_EXHAUSTED 资源耗尽 触发了服务端的限流/配额限制
java 复制代码
try {
    response = stub.withDeadlineAfter(3, TimeUnit.SECONDS).someRpcCall(request);
} catch (StatusRuntimeException e) {
    Status.Code code = e.getStatus().getCode();
    if (code == Status.Code.DEADLINE_EXCEEDED) {
        log.warn("调用超时: {}", e.getMessage());
    } else if (code == Status.Code.UNAVAILABLE) {
        log.error("服务不可达: {}", e.getMessage());
    }
    // 根据不同状态码做差异化处理,而不是笼统 catch Exception 一把梭
}

gRPC 相比传统 HTTP+JSON 接口的一个显著差异 :所有错误信息都被规范化到统一的 Status/Code 体系里(而不是像 HTTP 那样用一堆不同的状态码 + 五花八门的 body 格式表达错误),配合 Status.withDescription()/withCause(),可以在保持跨语言兼容的同时携带更结构化的错误上下文,这是 gRPC 在微服务错误处理规范化方面相对传统 REST 接口的一个设计优势。

28.3 序列化/协议不兼容问题

Dubbo 和 gRPC 都对"跨版本兼容"有明确设计考量,但错误发生的层面不同:

  • Dubbo (默认使用 Hessian2 序列化):接口方法签名变化(比如增加了一个参数)通常需要 Provider 和 Consumer 同时更新,否则会在调用时抛出序列化/反序列化相关的 RpcException。
  • gRPC/Protobuf:Protobuf 的设计从一开始就重点考虑了向前向后兼容(新增字段使用新的字段编号,旧客户端会忽略不认识的字段而不是报错),这是 gRPC 在大规模微服务场景下比很多其他 RPC 框架更受青睐的原因之一------协议演进对旧版本客户端通常是"优雅降级"而不是直接报错。

相关推荐
不一样的少年_15 分钟前
别用前端思维写后端:一张 5MB 图片,为什么能撑爆内存?
前端·后端·图片资源
夜之眷属21 分钟前
记一次战斗服务器 CPU 打满 100% 且“无法恢复“的排查
java·linux·运维·服务器·后端·性能优化
郝学胜-神的一滴32 分钟前
C++ Templates 07:编译报错和调试手段与实战技巧
开发语言·c++·后端·软件工程·visual studio
谢亮_vipxieliang1 小时前
PHP 8 新特性:构造器属性提升与实战
开发语言·后端·php
imDwAaY1 小时前
Spring Boot的核心配置文件一览及其加载顺序
java·spring boot·后端
高频因子挖掘机1 小时前
量化选股到底要不要每天拉全市场股票?从全市场扫描到候选池的行情数据设计
后端·github·api
专业程序开发源1 小时前
springboot校园志愿者管理系统28562-计算机课程设计、毕业设计
java·spring boot·后端·python·django·php·课程设计
谢亮_vipxieliang1 小时前
Go select 多路复用:从语法到实战的完整指南
开发语言·后端·golang
高频因子挖掘机2 小时前
复权价格怎么算?从除权因子、时间方向到量化回测避坑
后端·github·api
mldong2 小时前
一条审批流的数据库账:5 张核心表、3 张扩展表、0 张表单表
后端·架构