之前展示了Vert.x HTTP客户端如何方便调用消费一个REST服务,客户端需要事先知道REST服务在哪个主机和端口,不幸的是,这个信息是不能在编码阶段事先知道,在部署运行应用程序的生命周期甚至可能会改变。Vert.x提供了服务发现机制,如下图,服务发现让服务提供者发布服务,让消费者找到其正确的服务,也提供桥接到其他服务发现机制如Consul Zookeeper或Kubernetes。
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-service-discovery</artifactId>
</dependency>
发布一条记录到Vert.x服务发现中:
ServiceDiscovery discovery = ServiceDiscovery.create(vertx);
discovery.publish(HttpEndpoint.createRecord(
"my-rest-api",
"localhost", 8080,
"/names"),
ar -> {
if (ar.succeeded()) {
System.out.println("REST API published");
} else {
System.out.println("Unable to publish the REST API: " +
ar.cause().getMessage());
}
});
Vert.x存储这些记录在分布式map共享给Vert.x集群所有成员,可以以配置替代map,使用Redis Zookeeper等。
另外一边,消费者需要获得这些记录信息,只要输入名称即可:
public MyRestAPIClient(ServiceDiscovery discovery,
Handler<asyncresult> completionHandler) {
HttpEndpoint.getClient(discovery,
new JsonObject().put("name", "my-rest-api"),
ar -> {
if (ar.failed()) {
// No service
completionHandler.handle(Future.failedFuture(
"No matching services"));
} else {
client = ar.result();
completionHandler.handle(Future.succeededFuture());
}
});
Vert.x让你很容易获得的定位服务的透明性,能够无论什么环境部署微服务。如果服务更改位置,或如果服务变得不可用,您的应用程序会自动作出反应,并顺利管理这些情况。
容错弹性
Vert。X配有一套弹性模式使你的应用程序准备好面对失败。首先,正如你在文章的不同代码段看到,失败是一流的公民,必须使用你的代码来对付他们。因此,故障失败不会被传播,使得每一个服务都有舱壁。此外,你可以设置一个超时timeout管理所有分布式交互。
下面是设置超时代码:
client.get("/names",
response ->
// Handler called when the response is received
// We register a second handler to retrieve the body
response.bodyHandler(body -> {
// When the body is read, invoke the result handler
handler.handle(Future.succeededFuture(body.toJsonArray()));
}))
// Set the timeout (time given in ms)
.setTimeout(5000)
.exceptionHandler(t -> {
// If something bad happen, report the failure to the passed handler
// Also called when the timeout is reached
handler.handle(Future.failedFuture(t));
})
// Call end to send the request
.end();
不要忘记一个超时并不意味着实际操作没有完成,只是它没有按时完成,或者其他的事情出错了。
断路器
还有另一种弹性模式应用很著名:断路器。这种模式的优点是包括一个“恢复”功能。基本上,一个断路器是一个状态自动机如下所示:
断路器监视一个操作,并跟踪执行此操作时遇到的故障数。当达到一个阈值时,断路器开关到打开状态。在这种状态下操作不再被调用了,但一个后备函数会立即执行。它会定期地,发送一个请求调用实际操作。根据执行的结果,如成功断路器可切换到关闭状态后,如果操作再次失败或回到打开状态。断路器模式的一个重要方面是给你的服务以时间来恢复,而不是积累越来越多的调用操作。
下面是Vert.x断路器实现:
// Step 1 - create a circuit breaker
// Create an instance of circuit breaker.
circuitBreaker = CircuitBreaker.create("my-circuit-breaker", vertx,
// Configure it
new CircuitBreakerOptions()
.setTimeout(5000) // Operation timeout
.setFallbackOnFailure(true) // Call the fallback on failure
.setResetTimeout(10000)); // Switch to the half-open state every 10s
//…
public void getNames(Handler<asyncresult> handler) {
// Step 2 - Protect operation with it
circuitBreaker.executeWithFallback(
operation -> {
client.get("/names",
response ->
response.bodyHandler(body -> {
operation.complete(body.toJsonArray());
}))
.exceptionHandler(operation::fail)
.end();
},
failure ->
// Return an empty json array on failures
new JsonArray()
).setHandler(handler); // Just call the handler.