“AI 技术+人才”如何成为企业增长新引擎?戳此了解>>> 了解详情
写点什么

如何借助 Quarkus 和 MicroProfile 实现微服务

  • 2021-10-20
  • 本文字数:10655 字

    阅读完需:约 35 分钟

如何借助Quarkus和MicroProfile实现微服务

为何需要微服务特性?

在微服务架构中,应用程序是由多个相互连接的服务组成的,这些服务协同工作以实现所需的业务功能。


所以,一个典型的企业级微服务架构如下所示:



最初,我们可能认为使用微服务架构实现一个应用程序是很容易的事情。但是,要恰当地完成这一点并不容易,因为我们会面临一些新的挑战,而这些挑战是单体架构所未曾遇到的。举例来讲,这样的挑战包括容错、服务发现、扩展性、日志和跟踪等。


为了应对这些挑战,每个微服务都需要实现在 Red Hat 被称为“微服务特性(microservicility)”的内容。这个术语指的是除了业务逻辑之外,服务必须要实现的一个横切性关注点的列表,总结起来如下图所示:



业务逻辑可以使用任何语言(Java、Go 或 JavaScript)或任何框架(Spring Boot、Quarkus)来实现,但是围绕着业务逻辑,我们应该实现如下的关注点:


API:服务可以通过一组预先定义的 API 操作进行访问。例如,在采用 RESTful Web API 的情况下,会使用 HTTP 作为协议。此外,API 还可以使用像Swagger这样的工具实现文档化。


发现(Discovery):服务需要能够发现其他的服务。


调用(Invocation):在服务发现之后,需要使用一组参数来调用它,并且可能会返回一个响应。


弹性(Elasticity):微服务架构很重要的特性之一就是每个服务都是有弹性的,这意味着它可以根据一些参数(比如系统的重要程度或当前的工作负载)独立地进行扩展和伸缩。


回弹性(Resiliency):在微服务架构中,我们在开发时应该要考虑到故障,特别是与其他服务进行通信的时候。在单体架构中,应用会作为一个整体进行启动和关闭。但是,当我们把应用拆分成微服务架构之后,应用就变成由多个服务组成的,所有的服务会通过网络互相连接,这意味着应用的某些部分可能在正常运行,而其他部分可能已经出现了故障。在这种情况下,很重要的一点就是遏制故障,避免错误通过其他的服务进行传播。回弹性(或称为应用回弹性)是指一个应用/服务能够对面临的问题作出反应的能力,在出现问题的时候,依然能够提供尽可能最好的结果。


管道(Pipeline):服务应该能够独立部署,不需要任何形式的部署编排。基于这一点,每个服务应该有自己的部署管道。


认证(Authentication):在微服务架构中,涉及到安全性时,很重要的一个方面就是如何认证/授权内部服务之间的调用。Web token(以及通用的 token)是在内部服务之间声明安全性的首选方式。


日志(Logging):在单体应用中,日志是很简单的事情,因为应用的所有组件都在同一个节点中运行。现在,组件以服务的形式分布在多个节点上,因此,为了全面了解日志跟踪的情况,我们需要一个统一的日志系统/数据收集器。


监控(Monitoring):要保证基于微服务的应用正确运行,很重要的一个方面就是衡量系统的运行情况、理解应用的整体健康状况并在出现问题的时候发出告警。监控是控制应用程序的重要方面。


跟踪(Tracing):跟踪用来可视化一个程序的流程和数据进展。当我们需要检查用户在整个应用中的操作时,它对开发人员或运维人员尤其有用。


Kubernetes 正在成为部署微服务的事实标准工具。它是一个开源的系统,用来自动化、编排、扩展和管理容器。


但是在我们提到的十个微服务特性中,通过使用 Kubernetes 只能覆盖其中的三个。



发现(Discovery) 是通过_Kubernetes Service_理念实现的。它提供了一种将_Kubernetes Pod_(作为一个整体)进行分组的方式,使其具有稳定的虚拟 IP 和 DNS 名。要发现一个服务只需要在发送请求的时候使用 Kubernetes 的服务名作为主机名即可。


使用 Kubernetes 调用(Invocation) 服务是非常容易的,因为平台本身提供了所需的网络来调用任意的服务。


弹性(Elasticity) (或者说扩展性)是 Kubernetes 从一开始就考虑到的问题,例如,如果运行kubectl scale deployment myservice --replicas=5命令的话,myservice deployment 就会扩展至五个副本或实例。Kubernetes 平台会负责寻找合适的节点、部署服务并维持所需数量的副本一直处于运行状态。


但是,剩余的微服务特性该怎么处理呢?Kubernetes 只涵盖了其中的三个,那么我们该如何实现剩余的哪些呢?


根据所使用的语言或框架,我们有很多可遵循的策略,但是在本文中,我们会看到如何使用Quarkus来实现其中某些微服务特性。

什么是 Quarkus?

Quarkus是一个全栈、Kubernetes 原生的 Java 框架,适用于 Java 虚拟机(JVM)和原生编译环境,针对容器环境对 Java 的进行了专门的优化,使其成为一个可用于无服务器、云和 Kubernetes 环境的高效平台。


Quarkus 没有重复发明轮子,而是使用了由标准/规范支撑的知名企业级框架,并使它们可以借助GraalVM编译成二进制文件。

什么是 MicroProfile?

Quarkus 集成了MicroProfile规范,将企业级 Java 生态系统转移到了微服务架构中。


在下图中,我们可以看到构成 MicroProfile 规范的所有 API。其中有些 API 是基于Jakarta EE(也就是以前的 Java EE)规范的,比如 CDI、JSON-P 和 JAX-RS,其他的则是由 Java 社区开发的。



接下来,我们就使用 Quarkus 来实现 API、调用、回弹性、认证、日志、监控和跟踪等微服务特性。


如何使用 Quarkus 实现微服务特性

起步

开始使用 Quarkus 的最快捷方式就是通过起始页面,在这里我们可以添加所需的依赖。就本例来讲,我们要注册如下的依赖以满足微服务特性的需求:


  • API:RESTEasy JAX-RS、RESTEasy JSON-B 和 OpenAPI

  • 调用:REST Client JSON-B

  • 回弹性:Fault Tolerance

  • 认证:JWT

  • 日志:GELF

  • 监控:Micrometer metrics

  • 跟踪:OpenTracing



我们可以手动选择这些依赖,也可以导航至如下的链接Microservicilities Quarkus Generator,在这里所有的依赖都已经选择好了。然后点击“Generate your application”按钮以下载包含脚手架应用的压缩文件。

服务

在本例中,我们会创建一个非常简单的应用,它只包含两个服务。其中一个服务名为_Rating service_,它会返回给定一本书的评分,另外一个服务名为_Book service_,它会返回某本书的信息及其评分。服务之间的所有调用必须要进行认证。


在下图中,我们可以看到完整系统的概览:



_Rating service_已经开发完成并且能够以 Linux 容器的形式供我们使用。我们可以使用如下的命令在 9090 端口启动该服务:


docker run --rm -ti -p 9090:8080 quay.io/lordofthejars/rating-service:1.0.0
复制代码


为了校验该服务,我们可以发送请求到http://localhost:9090/rate/1


curl localhost:8080/rate/1 -vv
> GET /rate/1 HTTP/1.1> Host: localhost:8080> User-Agent: curl/7.64.1> Accept: */*>< HTTP/1.1 401 Unauthorized< www-authenticate: Bearer {token}< Content-Length: 0
复制代码


这里的状态码是401 Unauthorized,这是因为我们没有在请求中以 bearer token(JWT)的形式提供认证信息。带有_group_ Echoer的合法 token 才能访问_rating service_。

API

Quarkus 使用大家熟知的 JAX-RS 规范来定义 RESTful web API。在底层,Quarkus 使用了 RESTEasy 实现,直接与 Vert.X 框架协作,而不是使用 Servlet 相关的技术。


现在我们为 book service 定义 API,实现最常见的操作:


import javax.ws.rs.Consumes;import javax.ws.rs.DELETE;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.PathParam;import javax.ws.rs.Produces;import javax.ws.rs.QueryParam;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response;import javax.ws.rs.core.UriBuilder;
@Path("/book")public class BookResource {
@GET @Path("/{bookId}") @Produces(MediaType.APPLICATION_JSON) public Book book(@PathParam("bookId") Long bookId) { // logic }
@POST @Consumes(MediaType.APPLICATION_JSON) public Response getBook(Book book) { // logic
return Response.created( UriBuilder.fromResource(BookResource.class) .path(Long.toString(book.bookId)) .build()) .build(); }
@DELETE @Path("/{bookId}") public Response delete(@PathParam("bookId") Long bookId) { // logic
return Response.noContent().build(); }
@GET @Produces(MediaType.APPLICATION_JSON) @Path("search") public Response searchBook(@QueryParam("description") String description) { // logic
return Response.ok(books).build(); }}
复制代码


我们要注意的第一件事情就是这里定义了四个不同的端点:


  • GET /book/{bookId}使用 GET HTTP 方法来返回图书的信息,其中包括它的评分。返回元素会自动反编组(unmarshal)为 JSON。

  • POST /book使用 POST HTTP 方法插入来自请求体内容的一本图书。请求体的内容会自动从 JSON 编组(marshal)为 Java 对象。

  • DELETE /book/{bookId}使用 DELETE HTTP 方法以根据 ID 删除某本图书。

  • GET /book/search?description={description}根据描述搜索图书。


要注意的第二件事就是返回的类型,有时候我们返回的是一个 Java 对象,有时候返回的是javax.ws.rs.core.Response的实例。当使用 Java 对象的时候,我们会将 Java 编组为@Produces注解所设置的媒体类型。具体到本服务中,输出是 JSON 文档。如果使用Response对象的话,对于返回什么内容给调用者,我们会有更细粒度的控制,例如,我们可以设置返回给调用者的 HTTP 状态码、头信息或内容。至于该优选选择哪种方式,这取决于具体的使用场景。

调用

定义完访问_book service_的 API 之后,我们就该开发调用_rating service_服务以获取图书评分信息的代码了。


Quarkus 使用MicroProfile Rest Client规范来访问外部的(HTTP)服务。它提供了一种类型安全的方式借助 HTTP 协议访问 RESTful 服务,在这个过程中,它会使用 JAX-RS 2.0 的一些 API 以实现一致性和更简单的重用。


我们要创建的第一个元素是代表远程服务的接口,它会用到 JAX-RS 的注解。


import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.PathParam;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@Path("/rate")@RegisterRestClientpublic interface RatingService {
@GET @Path("/{bookId}") @Produces(MediaType.APPLICATION_JSON) Rate getRate(@PathParam("bookId") Long bookId);
}
复制代码


getRate()方法被调用的时候,会触发一个对/rate/{bookId}的远程 HTTP 调用,在这个过程中bookId会被替换为方法参数中的值。很重要的一点就是,要为接口添加@RegisterRestClient注解。


然后,RatingService接口需要注入到BookResource中以执行远程调用。


import org.eclipse.microprofile.rest.client.inject.RestClient;
@RestClientRatingService ratingService;
@GET@Path("/{bookId}")@Produces(MediaType.APPLICATION_JSON)public Book book(@PathParam("bookId") Long bookId) { final Rate rate = ratingService.getRate(bookId);
Book book = findBook(bookId); return book;}
复制代码


@RestClient注解会注入对应接口的一个代理实例,从而提供了客户端的实现。


最后需要配置的就是服务的位置(_hostname_部分)。在 Quarkus 中,配置属性是在src/main/resources/application.properties文件中设置的。要配置服务的位置,我们需要使用 Rest Client 接口的全限定名并结合 URL 作为键,然后使用实际的位置作为值:


org.acme.RatingService/mp-rest/url=http://localhost:9090
复制代码


要想正确访问_rating_服务并摆脱401 Unauthorized的问题,我们还需要解决相互认证的问题。

认证

基于 token 的认证机制允许系统基于一个安全 token 进行认证、授权和身份验证。Quarkus 集成了MicroProfile JWT RBAC Security规范,以使用 JWT Bearer Token 来保护服务。


要使用 MicroProfile JWT RBAC Security 来保护一个端点,我们只需要为方法添加@RolesAllowed注解即可。


@GET@Path("/{bookId}")@RolesAllowed("Echoer")@Produces(MediaType.APPLICATION_JSON)public Book book(@PathParam("bookId") Long bookId)
复制代码


随后,我们还需要在application.properties文件中配置 token 的 issuer 以及公钥文件的位置,以便于校验 token 的签名:


mp.jwt.verify.publickey.location=https://raw.githubusercontent.com/redhat-developer-demos/quarkus-tutorial/master/jwt-token/quarkus.jwt.pubmp.jwt.verify.issuer=https://quarkus.io/using-jwt-rbac
复制代码


该扩展会执行如下的校验:token 是合法的;issuer 是正确的;token 没有被修改过;签名是合法的;它还没有过期。


现在,_book service_和_rating service_都使用相同的 JWT issuer 和秘钥进行保护,所以服务之间的通信需要用户进行认证,这是通过在Authentication头信息中提供一个合法的 bearer token 实现的。


rating service_运行起来之后,我们就可以使用如下的命令启动_book service


./mvnw compile quarkus:dev
复制代码


最后,我们可以发送请求来获取图书信息并提供一个合法的 JSON Web Token 作为 bearer token。


至于 token 如何生成超出了本文的范围,我们假设 token 已经能够生成:



curl -H "Authorization: Bearer eyJraWQiOiJcL3ByaXZhdGVLZXkucGVtIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJqZG9lLXVzaW5nLWp3dC1yYmFjIiwiYXVkIjoidXNpbmctand0LXJiYWMiLCJ1cG4iOiJqZG9lQHF1YXJrdXMuaW8iLCJiaXJ0aGRhdGUiOiIyMDAxLTA3LTEzIiwiYXV0aF90aW1lIjoxNTcwMDk0MTcxLCJpc3MiOiJodHRwczpcL1wvcXVhcmt1cy5pb1wvdXNpbmctand0LXJiYWMiLCJyb2xlTWFwcGluZ3MiOnsiZ3JvdXAyIjoiR3JvdXAyTWFwcGVkUm9sZSIsImdyb3VwMSI6Ikdyb3VwMU1hcHBlZFJvbGUifSwiZ3JvdXBzIjpbIkVjaG9lciIsIlRlc3RlciIsIlN1YnNjcmliZXIiLCJncm91cDIiXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamRvZSIsImV4cCI6MjIwMDgxNDE3MSwiaWF0IjoxNTcwMDk0MTcxLCJqdGkiOiJhLTEyMyJ9.Hzr41h3_uewy-g2B-sonOiBObtcpkgzqmF4bT3cO58v45AIOiegl7HIx7QgEZHRO4PdUtR34x9W23VJY7NJ545ucpCuKnEV1uRlspJyQevfI-mSRg1bHlMmdDt661-V3KmQES8WX2B2uqirykO5fCeCp3womboilzCq4VtxbmM2qgf6ag8rUNnTCLuCgEoulGwTn0F5lCrom-7dJOTryW1KI0qUWHMMwl4TX5cLmqJLgBzJapzc5_yEfgQZ9qXzvsT8zeOWSKKPLm7LFVt2YihkXa80lWcjewwt61rfQkpmqSzAHL0QIs7CsM9GfnoYc0j9po83-P3GJiBMMFmn-vg" localhost:8080/book/1 -v
复制代码


响应再次提示禁止访问的错误:


<  HTTP/1.1 401 Unauthorized<  Content-Length: 0
复制代码


你可能会想在提供了合法的 token 之后,为何还会遇到这个错误。如果我们探查一下 book service 的控制台,就会看到如下的异常:


org.jboss.resteasy.client.exception.ResteasyWebApplicationException: Unknown error, status code 401    at org.jboss.resteasy.client.exception.WebApplicationExceptionWrapper.wrap(WebApplicationExceptionWrapper.java:107)    at org.jboss.resteasy.microprofile.client.DefaultResponseExceptionMapper.toThrowable(DefaultResponseExceptionMapper.java:21)
复制代码


出现这个异常的原因在于我们已经认证并授权访问_book service_,但是这个 bearer token 并没有传递到_rating service_中。



为了让Authorization头信息能够从传入的请求自动传播至 rest-client 请求,我们需要进行两项修改。


第一项修改是更新 Rest Client 接口并为其添加org.eclipse.microprofile.rest.client.inject.RegisterClientHeaders注解。


@Path("/rate")@RegisterRestClient@RegisterClientHeaderspublic interface RatingService {}
复制代码


第二项修改是配置哪些头信息要在请求之间进行传递,这是在application.properties文件中进行配置:


org.eclipse.microprofile.rest.client.propagateHeaders=Authorization
复制代码


我们再次使用相同的 curl,就会得到正确的输出了:


< HTTP/1.1 200 OK< Content-Length: 39< Content-Type: application/json<* Connection #0 to host localhost left intact{"bookId":2,"name":"Book 2","rating":1}* Closing connection 0
复制代码

回弹性

在微服务架构中,服务具备容错性是非常重要的,这样可以避免一个故障从某个服务传播至它的所有直接和间接的调用者。Quarkus 将MicroProfile Fault Tolerance规范与如下的注解集成到了一起,以便于处理故障相关的问题:


●    @Timeout:定义在抛出异常之前,某个服务最长的持续时间。


●    @Retry:如果调用失败的话,会再次进行尝试执行。


●    @Bulkhead:并发执行的限制,这样的话,该区域出现的故障不会导致整个系统超载。


●    @CircuitBreaker:当执行反复失败时,该服务会自动地快速失败。


●    @Fallback:当执行失败的时候,提供一个替代方案/默认值。


在访问_rating service_的时候,如果出现错误,我们会进行三次重试并在每次重试之间添加一秒钟的睡眠计时器。


@Retry(maxRetries = 3, delay = 1000)Rate getRate(@PathParam("bookId") Long bookId);
复制代码


现在,我们关掉_rating service_并执行请求,将会抛出如下的异常:


org.jboss.resteasy.spi.UnhandledException: javax.ws.rs.ProcessingException: RESTEASY004655: Unable to invoke request: org.apache.http.conn.HttpHostConnectException: Connect to localhost:9090 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused
复制代码


显然,这里会有错误,但是需要注意在抛出异常之前,我们经历了三秒钟的时间,这是因为执行了三次重试,并且每次重试间有一秒钟的延迟。


在这种情况下,_rating service_已经被我们停掉了,所以不可能恢复,但是在现实世界的例子中,_rating service_可能只会停机很短的时间,或者服务部署了多个副本,这样的话,简单的重试操作可能就足以恢复并提供一个合法的响应。


但是,当重试不足以解决问题并且抛出异常的时候,我们可以将错误传播至调用者,也可以为调用提供一个替代值。这个替代值可以来自对其他系统的调用(如分布式缓存),也可以是一个静态值。


就本例来讲,当连接_rating service_失败的时候,我们会返回一个值为 0 的评分值。


为了实现这个回退(fallback)逻辑,我们首先要做的就是实现org.eclipse.microprofile.faulttolerance.FallbackHandler接口,并将返回值设置为相同的类型,因为回退策略方法的作用是返回一个替代值。在本例中,会返回一个默认的Rate对象。


import org.eclipse.microprofile.faulttolerance.ExecutionContext;import org.eclipse.microprofile.faulttolerance.FallbackHandler;
public class RatingServiceFallback implements FallbackHandler&lt;Rate&gt; {
@Override public Rate handle(ExecutionContext context) { Rate rate = new Rate(); rate.rate = 0; return rate; }
}
复制代码


最后要做的就是为getRating()方法添加@org.eclipse.microprofile.faulttolerance.Fallback注解,配置在无法进行恢复的时候要执行的回退类。


@Retry(maxRetries = 3, delay = 1000)@Fallback(RatingServiceFallback.class)Rate getRate(@PathParam("bookId") Long bookId);
复制代码


如果我们重复前面的请求,此时不会抛出异常,而是会返回一个合法的输出,其中评分字段的值被设置成了 0。


* Connection #0 to host localhost left intact{"bookId":2,"name":"Book 2","rating":0}* Closing connection 0
复制代码


相同的方式也可以用于该规范提供的其他模式。比如,如果使用断路器模式的话::


@CircuitBreaker(requestVolumeThreshold = 4,               failureRatio=0.75,               delay = 1000)
复制代码


如果在滚动时间窗口中,四个连续的请求中有_三个(即 4 x 0.75)_出现了故障,那么断路器就会打开 1000 毫秒的时间,然后会回到半开状态。当断路器处于半开状态时,如果调用成功了,那么会再次关闭。否则的话,它会继续保持打开的状态。

日志

在微服务架构中,推荐将所有服务的日志收集到一起,以便于高效使用和理解。


其中有个解决方案就是使用Fluentd,这是一个开源的数据收集器,能够用来实现 Kubernetes 中统一的日志层。Quarkus 使用 Graylog 扩展日志格式(Graylog Extended Log Format,GELF)与 Fluentd 进行了集成。


具体的集成是非常简单的。首先,像其他的 Quarkus 应用那样使用日志逻辑:


import org.jboss.logging.Logger;
private static final Logger LOG = Logger.getLogger(BookResource.class);
@GET@Path("/{bookId}")@RolesAllowed("Echoer")@Produces(MediaType.APPLICATION_JSON)public Book book(@PathParam("bookId") Long bookId) { LOG.info("Get Book");
复制代码


接下来,启用 GELF 格式并设置 Fluentd 服务器的地址:


quarkus.log.handler.gelf.enabled=truequarkus.log.handler.gelf.host=localhostquarkus.log.handler.gelf.port=12201
复制代码


最后,我们可以发送请求给实现日志功能的端点:


curl -H "Authorization: Bearer ..." localhost:8080/book/1
{"bookId":1,"name":"Book 1","rating":3}
复制代码


在输出方面并没有任何变化,但是日志已经被传输到了 Fluentd 上。如果我们使用Kibana来可视化数据的话,就会看到如下所示的日志行:


监控

监控是另外一个我们需要在微服务架构中实现的微服务特性。Quarkus 集成了Micrometer实现应用监控。Micrometer 为几乎所有流行的监控系统提供了一个简单的入口,从而能够让我们在避免供应商锁定的前提下 instrument 基于 JVM 的应用。


对于本例来讲,我们使用Prometheus格式作为监控输出,但是 Micrometer(和 Quarkus)也支持其他的格式,比如 Azure Monitor、Stackdriver、SignalFx、StatsD 和 DataDog。


我们可以注册如下的 Maven 依赖以提供 Prometheus 输出:


<dependency>  <groupId>io.quarkus</groupId>;  <artifactId>quarkus-micrometer-registry-prometheus</artifactId></dependency>
复制代码


Micrometer 扩展默认会注册一些与系统、JVM 或 HTTP 相关的指标。所收集到的指标的一个子集可以通过/q/metrics端点进行访问,如下所示:


curl localhost:8080/q/metrics
jvm_threads_states_threads{state="runnable",} 22.0jvm_threads_states_threads{state="blocked",} 0.0jvm_threads_states_threads{state="waiting",} 10.0http_server_bytes_read_count 1.0http_server_bytes_read_sum 0.0
复制代码


但是,我们还可以使用 Micrometer API 实现应用特定的指标。


在这里,我们实现一个自定义的指标来衡量评分最高的图书。


要注册一个指标,也就是本例中的一个 gauge,是通过使用io.micrometer.core.instrument.MeterRegistry类来完成的。


private final MeterRegistry registry;private final LongAccumulator highestRating = new LongAccumulator(Long::max, 0);
public BookResource(MeterRegistry registry) { this.registry = registry; registry.gauge("book.rating.max", this, BookResource::highestRatingBook);}
复制代码


我们发送一些请求并校验 gauge 是否被正确地更新了。


curl -H "Authorization: Bearer ..." localhost:8080/book/1
{"bookId":1,"name":"Book 1","rating":3}
curl localhost:8080/q/metrics
# HELP book_rating_max# TYPE book_rating_max gaugebook_rating_max 3.0
复制代码


我们还可以设置一个计时器,记录从 rating service 获取评分信息所耗费的时间。


Supplier<Rate> rateSupplier = () -> {      return ratingService.getRate(bookId);};
final Rate rate = registry.timer("book.rating.test").wrap(rateSupplier).get();
复制代码


我们发送一些请求并校验是否收集了评分服务的耗时。


# HELP book_rating_test_seconds# TYPE book_rating_test_seconds summarybook_rating_test_seconds_count 4.0book_rating_test_seconds_sum 1.05489108# HELP book_rating_test_seconds_max# TYPE book_rating_test_seconds_max gaugebook_rating_test_seconds_max 1.018622001
复制代码


Micrometer 使用MeterFilter实例来自定义由MeterRegistry实例所发出的指标。Micrometer 扩展将会探测到MeterFilter CDI bean 并使用它们来初始化MeterRegistry实例。


例如,我们可以定义一个通用的标签来设置应用运行的环境(prod、testing、staging 等)。


@Singletonpublic class MicrometerCustomConfiguration {
@Produces @Singleton public MeterFilter configureAllRegistries() { return MeterFilter.commonTags(Arrays.asList( Tag.of("env", "prod"))); }
}
复制代码


发送一个新的请求并校验指标是否添加了标签。


http_client_requests_seconds_max{clientName="localhost",env="prod",method="GET",outcome="SUCCESS",status="200",uri="/rate/2",} 0.0
复制代码


请注意,标签env包含的值为prod

跟踪

Quarkus 应用使用OpenTracing规范来为互相交互的 Web 应用提供分布式跟踪能力。


接下来,我们配置 OpenTracing 连接一个 Jaeger 服务器,并将服务的名字设置为 book-service 以标识跟踪信息:


quarkus.jaeger.enabled=truequarkus.jaeger.endpoint=http://localhost:14268/api/tracesquarkus.jaeger.service-name=book-servicequarkus.jaeger.sampler-type=constquarkus.jaeger.sampler-param=1
复制代码


现在,我们发送一个请求:


curl -H "Authorization: Bearer ..." localhost:8080/book/1
{"bookId":1,"name":"Book 1","rating":3}
复制代码


访问 Jaeger UI 来校验调用过程被进行了跟踪:


结论

开发和实现微服务架构要比开发单体应用更具挑战性。我们相信,微服务特性能够促使你在应用基础设施方面正确地开发服务。


我们在这里所阐述的微服务特性(除 API 和管道之外)都是新的理念,或者说在单体应用中会以不同的方式来实现。其中的原因在于,现在应用被拆分成了多个组成部分,所有的这些组成部分需要在网络中进行相互连接。


如果你打算开发微服务并将它们部署到 Kubernetes 的话,那么 Quarkus 是一个很好的解决方案,因为它可以很平滑地与 Kubernetes 进行集成,实现大多数的微服务特性都非常简单,只需要几行代码就能实现。


用来阐述本文的源码都可以在github上找到。


作者简介:


Alex Soto 是红帽公司的开发者体验总监。他对 Java 领域、软件自动化充满热情,他相信开源软件模式。Soto 是Manning的《Testing Java Microservices》O’Reilly的《Quarkus Cookbook》两本书的共同作者,他还是多个开源项目的贡献者。自 2017 年以来,他一直是 Java Champion,是国际演讲者和 Salle URL 大学的教师。


英文原文:


Implementing Microservicilities with Quarkus and MicroProfile

2021-10-20 14:112424

评论

发布
暂无评论
发现更多内容

从功能测试进阶自动化测试,熬夜7天整理出这一份3000字超全学习指南【附网盘资源】

伤心的辣条

Python 程序员 软件测试 IT 自动化测试

给你一个项目,你将如何开展性能测试工作?

伤心的辣条

Python 程序员 IT 自动化测试 接口测试

测试员该知道的软件测试流程,你都知道吗?

伤心的辣条

Python 程序员 软件测试 IT 自动化测试

俄航天局局长:外星生命或正在研究人类文明

Dylan

俄罗斯 外星人 航天局

Git 不要只会 pull 和 push,学学这 5 条提高效率的命令

CRMEB

35人首次上榜、行者皆勇者——创业邦3040新青年创投峰会圆满落幕

创业邦

Vue-8-计算属性和侦听属性

Python研究所

6月月更

UI自动化测试框架搭建-优化企业微信通知

伤心的辣条

Python 程序员 软件测试 自动化测试 UI自动化

OSPO如何帮助保护你的软件供应链

安势信息

开源 DevOps 开源社区 SCA opensource

博云《应用上容器指南》首发!详解应用容器化改造

BoCloud博云

容器 云原生 容器云 应用

Executor

急需上岸的小谢

6月月更

LeaRun.Java表单快速开发工具

力软低代码开发平台

国家先进计算产业创新(宜昌)中心正式落地 由中科曙光、升哲科技联合运营

SENSORO

人工智能 物联网 新基建 智慧城市

元气部落仿站开发,元气部落盲盒系统APP开发

WDL22119

盲盒小程序开发 盲盒源码 盲盒H5开发 盲盒APP系统开发 元气部落仿站开发

InnoDB体系架构

龙空白白

MySQL InnoDB

GPU渲染全解读:GPU渲染器的发展与对比

Finovy Cloud

渲染器 GPU服务器

安势信息加入OpenSSF (开源安全基金会), 共建软件供应链安全

安势信息

Linux DevOps SCA工具 opensource

三星堆重大发现!信息量巨大

Dylan

三星堆 四川省 文物

转行软件测试跳槽到新公司,工作如何快速上手?

伤心的辣条

Python 程序员 软件测试 自动化测试 接口测试

如何高效的进行接口测试?【工具篇】

Liam

测试 Postman 接口测试 API接口管理 接口测试工具

养老金融政策频出,市场有多大?

易观分析

养老消费

想学好软件测试,这些软件必不可少

伤心的辣条

Python 程序员 程序人生 软件测试 自动化测试

CVPR2022 |小红书首创多图交互建模挑战热门研究课题,大幅提升行人重识别性能

小红书技术REDtech

Transformer CVPR2022 行人重识别

云上360行丨深耕快消品行业数字化转型,纷享销客与华为云合力同行

华为云开发者联盟

人工智能 modelarts 快消品 纷享销客

前端工程化:保姆级教学 Jenkins 部署前端项目

伤心的辣条

Python 程序员 jenkins 自动化测试 接口测试

国际SaaS企业有哪些机遇和挑战

ToB行业头条

打造软件供应链安全平台,「安势信息」完成数千万元天使轮融资

安势信息

直播回顾 | 传统应用进行容器化改造,如何既快又稳?

BoCloud博云

云原生 容器云 应用

3 个技巧来破解你可以立即使用的 Flutter 生产力!

坚果

6月月更

信用卡业务愈卷愈烈,银行机构如何突围?

易观分析

信用卡业务

工业互联网生态建设加速,小程序容器技术跨端开发特性助力突围

Speedoooo

跨端开发 软件安全 降本增效 敏捷迭代 多端运行

如何借助Quarkus和MicroProfile实现微服务_云原生_Alex Soto_InfoQ精选文章