在传统的单体架构中,应用程序已经通过静态主机名、IP 地址和端口知道后端服务的存在位置。IT 运维团队维护静态配置,以保证服务的可靠性和系统的稳定性。自从微服务开始在分布式网络系统中运行以来,这种 Day 2 运维发生了显著的变化。发生这种变化的原因是微服务需要与多个后端服务进行通信,以提高负载平衡和服务弹性。
随着服务应用程序被容器化并放置在 Kubernetes 上,微服务拓扑变得更加复杂。由于应用程序容器可以随时被 Kubernetes 终止和重新创建,因此应用程序无法提前知道静态信息。微服务不需要配置后端应用程序的静态信息,因为 Kubernetes 可以动态、自动地处理 服务发现、负载平衡和自我修复。
然而,Kubernetes 不支持通过集成的应用程序配置进行编程服务发现和基于客户端的负载平衡。Smallrye Stork是一个开源项目,旨在解决这个问题,提供以下优点和特性:
- 增强服务发现能力
- 支持 Consul 和 Kubernetes
- 自定义客户端负载平衡功能
- 可管理和编程的 API
尽管如此,Java 开发人员需要一些时间来适应 Stork 项目并将其与现有的 Java 框架集成。幸运的是,Quarkus 使开发人员能够将 Stork 的特性插入到 Java 应用程序中。本文演示了 Quarkus 如何允许开发人员将 Stork 的特性添加到 Java 应用程序中。
使用 Quarkus CLI 创建一个新的 Quarkus 项目
使用Quarkus 命令行工具(CLI),创建一个新的 Maven 项目。以下命令将构建一个新的响应式 RESTful API 应用程序
$ quarkus create app quarkus-stork-example -x rest-client-reactive,resteasy-reactive
输出应该如下所示
...
[SUCCESS] ✅ quarkus project has been successfully generated in:
--> /Users/danieloh/Downloads/demo/quarkus-stork-example
...
打开pom.xml
文件并添加以下 Stork 依赖项:stork-service-discovery-consul 和 smallrye-mutiny-vertx-consul-client。 可以在这里找到此示例的解决方案。
<dependency>
<groupId>io.smallrye.stork</groupId>
<artifactId>stork-service-discovery-consul</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-consul-client</artifactId>
</dependency>
为发现创建新服务
创建两个服务(hero
和 villain
),Stork 负载均衡器将发现它们。在 src/main/java/org/acme
中创建一个新的 services 目录。然后在 src/main/java/org/acme/services
中创建一个新的 HeroService.java
文件。
将以下代码添加到 HeroService.java
文件中,该文件基于 Vert.x 反应式引擎创建一个新的 HTTP 服务器
@ApplicationScoped
public class HeroService {
@ConfigProperty(name = "hero-service-port", defaultValue = "9000") int port;
public void init(@Observes StartupEvent ev, Vertx vertx) {
vertx.createHttpServer()
.requestHandler(req -> req.response().endAndForget("Super Hero!"))
.listenAndAwait(port);
}
}
接下来,通过创建 VillainService.java
文件来创建另一个服务。 唯一的区别是您需要在 init() 方法中设置不同的名称、端口和返回消息,如下所示
@ConfigProperty(name = "villain-service-port", defaultValue = "9001") int port;
public void init(@Observes StartupEvent ev, Vertx vertx) {
vertx.createHttpServer()
.requestHandler(req -> req.response().endAndForget("Super Villain!"))
.listenAndAwait(port);
}
将服务注册到 Consul
正如我之前提到的,Stork 允许您使用基于 Vert.x Consul Client 的 Consul 进行服务注册。创建一个新的 ConsulRegistration.java
文件,以在 src/main/java/org/acme/services
中注册两个具有相同名称(my-rest-service)的服务。最后,添加以下 ConfigProperty 和 init() 方法
@ApplicationScoped
public class ConsulRegistration {
@ConfigProperty(name = "consul.host") String host;
@ConfigProperty(name = "consul.port") int port;
@ConfigProperty(name = "hero-service-port", defaultValue = "9000") int hero;
@ConfigProperty(name = "villain-service-port", defaultValue = "9001") int villain;
public void init(@Observes StartupEvent ev, Vertx vertx) {
ConsulClient client = ConsulClient.create(vertx, new ConsulClientOptions().setHost(host).setPort(port));
client.registerServiceAndAwait(
new ServiceOptions().setPort(hero).setAddress("localhost").setName("my-rest-service").setId("hero"));
client.registerServiceAndAwait(
new ServiceOptions().setPort(villain).setAddress("localhost").setName("my-rest-service").setId("villain"));
}
}
将反应式 REST 客户端委托给 Stork
hero
和 villain
服务是普通的反应式 RESTful 服务,可以通过可暴露的 API 直接访问。 您需要将这些服务委托给 Stork 进行服务发现、选择和调用。
在 src/main/java
目录中创建一个新的接口 MyRestClient.java
文件。 然后添加以下代码
@RegisterRestClient(baseUri = "stork://my-rest-service")
public interface MyRestClient {
@GET
@Produces(MediaType.TEXT_PLAIN)
String get();
}
以 stork://
开头的 baseUri 使 Stork 能够发现服务并根据负载平衡类型选择一个。 接下来,修改现有的资源文件或创建一个新的资源文件(MyRestClientResource
)以注入 RestClient
(MyRestClient) 以及端点 (/api),如下所示
@Path("/api")
public class MyRestClientResource {
@RestClient MyRestClient myRestClient;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String invoke() {
return myRestClient.get();
}
}
在运行应用程序之前,配置 Stork 以在 application.properties 中使用 Consul 服务器,如下所示
consul.host=localhost
consul.port=8500
stork.my-rest-service.service-discovery=consul
stork.my-rest-service.service-discovery.consul-host=localhost
stork.my-rest-service.service-discovery.consul-port=8500
stork.my-rest-service.load-balancer=round-robin
测试您的应用程序
您有几种方法可以运行本地 Consul 服务器。 对于此示例,请使用容器运行服务器。 这种方法可能比安装或引用外部服务器更简单。 在这里找到更多信息。
$ docker run --rm --name consul -p 8500:8500 -p 8501:8501 consul:1.7 agent -dev -ui -client=0.0.0.0 -bind=0.0.0.0 --https-port=8501
使用 Dev 模式运行您的 Quarkus 应用程序
$ cd quarkus-stork-example
$ quarkus dev
输出如下所示
...
INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, jaxrs-client-reactive, rest-client-reactive, resteasy-reactive, smallrye-context-propagation, vertx]
--
Tests paused
Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
Access the RESTful API (/api) to retrieve available services based on the round-robin load balancing mechanism. Execute the following curl command-line in your local terminal:
& while true; do curl localhost:8080/api ; echo ''; sleep 1; done
输出应该如下所示
Super Villain!
Super Hero!
Super Villain!
Super Hero!
Super Villain!
...
总结
您学习了 Quarkus 如何使开发人员能够使用 Stork 和 Consul 集成基于客户端的负载平衡编程,用于反应式 Java 应用程序。开发人员还可以通过实时编码获得更好的开发体验,同时他们在 Quarkus 中继续开发反应式编程。有关 Quarkus 的更多信息,请访问 Quarkus 指南和实践。
评论已关闭。