Vert.x 服务解析器

预览

服务解析器库是一个插件,它允许 Vert.x 客户端使用逻辑服务名称而不是网络地址来调用服务。服务解析器还能够使用常用策略执行客户端负载均衡。

您可以使用服务解析器作为客户端来查询解析器,或将其与 Vert.x 客户端原生集成。

服务解析器客户端

您可以使用服务解析器客户端查询服务解析器。

ServiceResolverClient client = ServiceResolverClient.create(vertx, new KubeResolverOptions());

// Resolve a service endpoint
Future<Endpoint> fut = client.resolveEndpoint(ServiceAddress.of("the-service"));

fut.onSuccess(endpoint -> {

  // Print physical servers details
  List<ServerEndpoint> servers = endpoint.servers();
  for (ServerEndpoint server : servers) {
    System.out.println("Available server: " + server.address());
  }
});

您还可以让负载均衡器选择节点

ServiceResolverClient client = ServiceResolverClient.create(vertx, new KubeResolverOptions());

// Resolve a service endpoint
Future<Endpoint> fut = client.resolveEndpoint(ServiceAddress.of("the-service"));

fut.onSuccess(endpoint -> {

  // Print physical servers details
  List<ServerEndpoint> servers = endpoint.servers();
  for (ServerEndpoint server : servers) {
    System.out.println("Available server: " + server.address());
  }
});

客户端集成

服务解析器与 Vert.x HTTP 和 Web 客户端集成。

Vert.x HTTP 客户端入门

给定一个解析器,您可以通过 HttpClientBuilder 配置 Vert.x 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("Invalid status response:" + response.statusCode());
    }
  }));

Vert.x Web 客户端入门

给定一个解析器,您可以通过 HttpClientBuilder 配置 Vert.x Web 客户端使用它。

HttpClient httpClient = vertx.httpClientBuilder()
  .withAddressResolver(resolver)
  .build();
WebClient webClient = WebClient.wrap(httpClient);

服务通过 ServiceAddress 地址来寻址。

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 集群内的服务。

Kubernetes 解析器要求使用为 Pod 配置的服务帐户访问 endpoints 资源。

以下是 default 服务帐户的角色和角色绑定配置示例

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: observe-endpoints
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: observe-endpoints
  namespace: default
roleRef:
  kind: Role
  name: observe-endpoints
  apiGroup: rbac.authorization.k8s.io
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default
KubeResolverOptions options = new KubeResolverOptions();

AddressResolver 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

您可以覆盖这些设置。

KubeResolverOptions options = new KubeResolverOptions()
  .setServer(SocketAddress.inetSocketAddress(port, host))
  .setNamespace(namespace)
  .setBearerToken(bearerToken)
  .setHttpClientOptions(httpClientOptions)
  .setWebSocketClientOptions(wsClientOptions);

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();