ServiceResolverClient client = ServiceResolverClient.create(vertx, new KubeResolverOptions());
// 解析指定服务名背后的物理终结点
Future<Endpoint> fut = client.resolveEndpoint(ServiceAddress.of("the-service"));
fut.onSuccess(endpoint -> {
// 遍历并打印所有活跃的物理服务器节点详情:
List<ServerEndpoint> servers = endpoint.servers();
for (ServerEndpoint server : servers) {
System.out.println("可用服务器节点: " + server.address());
}
});
Vert.x 服务解析器与客户端负载均衡 (vertx-service-resolver)
服务解析器(Service Resolver)是一个功能强大的 Vert.x 插件库,允许 Vert.x 客户端使用逻辑服务名(Logical Service Names)替代传统的物理 IP 和端口来发起远程调用。此外,服务解析器还内建了客户端负载均衡能力,支持主流的负载均衡路由策略。
你可以直接使用服务解析器客户端独立查询服务终结点,也可以将其深度集成至 Vert.x 原生客户端中透明使用。
独立服务解析器客户端
你可以通过独立客户端主动向注册中心查询服务终结点实例:
你也可以让负载均衡器全自动决策路由节点。
与 Vert.x 核心客户端深度集成
服务解析器能够与 Vert.x HTTP Client 及 Web Client 原生无缝集成。
1. 在 Vert.x HTTP Client 中集成
通过 HttpClientBuilder 为 HTTP 客户端注入地址解析器:
HttpClient client = vertx.httpClientBuilder()
.withAddressResolver(resolver)
.build();
集成后,直接使用 ServiceAddress 替代传统的物理 SocketAddress:
ServiceAddress serviceAddress = ServiceAddress.of("the-service");
Future<HttpClientRequest> requestFuture = client.request(new RequestOptions()
.setMethod(HttpMethod.GET)
.setURI("/")
.setServer(serviceAddress));
Future<Buffer> resultFuture = requestFuture.compose(request -> request
.send()
.compose(response -> {
if (response.statusCode() == 200) {
return response.body();
} else {
return Future.failedFuture("服务端返回非正常状态码: " + response.statusCode());
}
}));
2. 在 Vert.x Web Client 中集成
同样借助 HttpClientBuilder 构建底层网络通道,并将其包装为高层 Web Client:
HttpClient httpClient = vertx.httpClientBuilder()
.withAddressResolver(resolver)
.build();
WebClient webClient = WebClient.wrap(httpClient);
发起基于服务名的请求调用:
ServiceAddress serviceAddress = ServiceAddress.create("the-service");
Future<HttpResponse<Buffer>> future = webClient
.request(HttpMethod.GET, new RequestOptions().setServer(serviceAddress))
.send();
客户端负载均衡策略
默认的负载均衡路由策略为 轮询(Round-Robin),你可以根据实际需求自由定制算法:
HttpClient client = vertx.httpClientBuilder()
.withAddressResolver(resolver)
.withLoadBalancer(LoadBalancer.LEAST_REQUESTS) // 最少请求数负载均衡策略
.build();
常见服务解析器实现生态
服务解析器现已深度集成了 Kubernetes 与 DNS SRV 等多种服务注册发现基础设施。
Kubernetes 服务解析器
Kubernetes 解析器能够实时感知并定位 Kubernetes 集群内部的微服务 Endpoints。
|
Kubernetes 解析器要求 Pod 所绑定的 ServiceAccount 拥有对 Kubernetes 原生 针对
|
在代码中初始化 Kubernetes 解析器:
KubeResolverOptions options = new KubeResolverOptions();
KubeResolver resolver = KubeResolver.create(options);
HttpClient client = vertx.httpClientBuilder()
.withAddressResolver(resolver)
.build();
默认配置项会自动从 Pod 容器环境变量与标准挂载路径读取:
- KUBERNETES_SERVICE_HOST
- KUBERNETES_SERVICE_PORT
- /var/run/secrets/kubernetes.io/serviceaccount/token
- /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
- /var/run/secrets/kubernetes.io/serviceaccount/namespace
你可以自由覆盖上述任意参数。
针对服务账号短期凭据自动轮转(Ephemeral Tokens),可通过 tokenProvider 注册动态获取函数:
KubeResolverOptions options = new KubeResolverOptions();
KubeResolver resolver = KubeResolver.create(options)
.tokenProvider(() -> loadToken());
HttpClient client = vertx.httpClientBuilder()
.withAddressResolver(resolver)
.build();
解析器会在需要新鲜 Token 时主动调用该函数,并自动维护内部缓存,直到遇到服务端返回 401 Unauthorized 状态码时自动作废旧 Token 并重新拉取。
匹配特定服务端口
当 Kubernetes Service 暴露了多个端口时,解析器默认仅选留一个端口,这可能不符合业务预期。你可以显式指定端口号:
ServiceAddress serviceAddress = KubernetesServiceAddressBuilder
.of("the-service")
.withPortNumber(8080)
.build();
或者按端口名称(Port Name)精准匹配:
ServiceAddress serviceAddress = KubernetesServiceAddressBuilder
.of("the-service")
.withPortName(portName)
.build();
DNS SRV 服务解析器
SRV 解析器利用标准 DNS SRV 资源记录来动态解析并定位后端服务实例:
SrvResolverOptions options = new SrvResolverOptions()
.setServer(SocketAddress.inetSocketAddress(dnsPort, dnsServer));
AddressResolver resolver = SrvResolver.create(options);
HttpClient client = vertx.httpClientBuilder()
.withAddressResolver(resolver)
.build();