
本文介绍如何在 gRPC Java 客户端中无需重建 Channel 或 Stub,即可实现服务端故障时自动切换至备用服务器,核心是利用内置的 pick_first 负载均衡策略与自定义 NameResolver 协同工作。
本文介绍如何在 grpc java 客户端中无需重建 channel 或 stub,即可实现服务端故障时自动切换至备用服务器,核心是利用内置的 `pick_first` 负载均衡策略与自定义 nameresolver 协同工作。
在 gRPC Java 中,客户端连接管理高度依赖 ManagedChannel 和其背后的 NameResolver 与 LoadBalancer 机制。默认情况下,gRPC 使用 pick_first 负载均衡策略——它会按顺序尝试解析出的所有地址,仅建立与首个成功连接的地址的长连接,并持续复用该连接;一旦该连接因服务端宕机、网络中断等原因进入 TRANSIENT_FAILURE 状态,gRPC 会自动触发重连流程,并重新遍历地址列表,选择下一个可用地址建立连接。这意味着:只要我们将 Server A 和 Server B 的地址同时提供给 NameResolver(且 A 在前),就能天然实现“优先连 A,A 不可用则自动切 B”的行为,完全无需手动重建 Channel、Stub,也无需在业务层编写重试或异常捕获逻辑。
要实现这一点,关键在于让 ManagedChannelBuilder 使用能动态返回多个地址的 NameResolver。你可以选择以下任一方式:
✅ 推荐方式:使用 dns:/// + 自定义 DNS 解析(生产就绪)
若服务端地址可通过 DNS 统一标识(如 grpc-service.example.com),可在 DNS 中配置多条 A/AAAA 记录(A 的 IP 在前,B 的 IP 在后)。然后构建 Channel 时指定:
ManagedChannel channel = ManagedChannelBuilder.forTarget("dns:///grpc-service.example.com")
.usePlaintext() // 开发环境;生产请用 TLS
.build();gRPC 内置的 DNS NameResolver 将按记录顺序返回地址,pick_first 会自动完成故障转移。
✅ 开发/测试快速验证:自定义 StaticNameResolver
若需硬编码地址(如示例中的 localhost:8080 和 localhost:8081),可实现轻量级 NameResolver:
public class FailoverNameResolver extends NameResolver {
private final List<EquivalentAddressGroup> servers = Arrays.asList(
new EquivalentAddressGroup(Arrays.asList(new Address("localhost", 8080))),
new EquivalentAddressGroup(Arrays.asList(new Address("localhost", 8081)))
);
@Override
public String getServiceAuthority() { return "failover"; }
@Override
public void start(Listener2 listener) {
listener.onResult(ResolutionResult.newBuilder()
.setAddresses(servers)
.setAttributes(Attributes.EMPTY)
.build());
}
// 其他方法可空实现(stop, refresh等)
}再注册并使用:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
NameResolverRegistry.getDefaultRegistry()
.register(new FailoverNameResolverProvider());
ManagedChannel channel = ManagedChannelBuilder.forTarget("failover:///")
.usePlaintext()
.build();⚠️ 重要注意事项:
-
pick_first是默认策略,无需显式设置;若误设为round_robin或其他策略,将失去故障自动切换能力; - 连接状态检测依赖 gRPC 的健康检查与连接空闲超时机制,建议保持默认
keepAlive配置(或根据网络环境微调); - 切换过程对上层 RPC 调用完全透明:正在执行的请求可能失败(抛出
StatusRuntimeExceptionwithUNAVAILABLE),但后续请求将自动流向新地址; - 若需更精细控制(如主动探测、权重、熔断),应升级至
xds或集成 Resilience4j 等外部容错框架,而非绕过 gRPC 原生机制。
综上,gRPC Java 已为服务端故障转移提供了简洁、可靠、零侵入的原生支持——只需让 NameResolver 提供有序地址列表,剩下的交由 pick_first 负载均衡器自动完成。

















