Vert.x Micrometer 指标监控

这个项目是 Vert.x Metrics Service Provider Interface (SPI) 的一个实现。 它使用 Micrometer 来管理运行指标并向后端报告。

特性

  • Vert.x core 组件监控:TCP/HTTP 客户端和服务端、 DatagramSocketEventBus 和各类 pool

  • 用户通过Micrometer定义的监控指标

  • 向所有 Micrometer 支持的后端发送报告

  • 内置可选项: InfluxDBPrometheus 、 JMX 报告。

InfluxDB

预先准备

开始

必须要在classpath下添加 vertx-micrometer-metricsmicrometer-registry-influx 模块。

Maven 用户应在 pom 文件中添加如下依赖:

<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-micrometer-metrics</artifactId>
 <version>4.4.0</version>
</dependency>
<dependency>
 <groupId>io.micrometer</groupId>
 <artifactId>micrometer-registry-influx</artifactId>
 <version>${micrometer.version}</version>
</dependency>

Gradle 用户,添加如下依赖:

compile 'io.vertx:vertx-micrometer-metrics:4.4.0'
compile 'io.micrometer:micrometer-registry-influx:${micrometer.version}'

配置示例

Vert.x 默认情况下不开启 SPI 的实现。 您必须在 Vert.x options 中启用。

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true))
    .setEnabled(true)));

使用指定的URI

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setUri("http://influxdb.example.com:8888"))
    .setEnabled(true)));

连接到 InfluxDB V2

如果您要连接到 InfluxDB V2 ,那么最少需要设置 org 这个属性。

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setOrg("my-org"))
    .setEnabled(true)));

使用指定的数据库或桶

您可以使用以下代码来配置指定的数据库名称:

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setDb("sales-department"))
    .setEnabled(true)));

对于 InfluxDB V2 来说,您一样可以使用 setBucket 函数来设置指定的桶。

认证

您可以通过以下代码来配置用户名和密码以通过认证:

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setUserName("username")
      .setPassword("password"))
    .setEnabled(true)));

或者您也可以通过配置签名的方式进行认证:

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)
      .setToken(authToken))
    .setEnabled(true)));

Prometheus

预先准备

开始

必须在classpath中添加 vertx-micrometer-metricsmicrometer-registry-prometheus 模块。 您也许需要 vertx-web 来开放监控指标。

Maven用户在pom文件中添加如下依赖:

<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-micrometer-metrics</artifactId>
 <version>4.4.0</version>
</dependency>
<dependency>
 <groupId>io.micrometer</groupId>
 <artifactId>micrometer-registry-prometheus</artifactId>
 <version>${micrometer.version}</version>
</dependency>

Gradle 用户,添加如下依赖:

compile 'io.vertx:vertx-micrometer-metrics:4.4.0'
compile 'io.micrometer:micrometer-registry-prometheus:${micrometer.version}'

配置示例

Vert.x 默认情况下不开启 SPI 的实现。您必须在 Vert.x options 中将其启用。

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setEnabled(true)));

将嵌入式HTTP服务器与自定义终端(custom endpoint)一起使用

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true)
      .setStartEmbeddedServer(true)
      .setEmbeddedServerOptions(new HttpServerOptions().setPort(8080))
      .setEmbeddedServerEndpoint("/metrics/vertx"))
    .setEnabled(true)));

如果没有指定默认服务终端,那么默认为 /metrics

将指标绑定到已存在的Web路由器

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setEnabled(true)));

// 稍后,创建路由器
Router router = Router.router(vertx);
router.route("/metrics").handler(PrometheusScrapingHandler.create());
vertx.createHttpServer().requestHandler(router).listen(8080);

JMX

开始

必须要在classpath中添加 vertx-micrometer-metricsmicrometer-registry-jmx

Maven用户在pom文件中添加如下依赖:

<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-micrometer-metrics</artifactId>
 <version>4.4.0</version>
</dependency>
<dependency>
 <groupId>io.micrometer</groupId>
 <artifactId>micrometer-registry-jmx</artifactId>
 <version>${micrometer.version}</version>
</dependency>

Gradle 用户,添加如下依赖:

compile 'io.vertx:vertx-micrometer-metrics:4.4.0'
compile 'io.micrometer:micrometer-registry-jmx:${micrometer.version}'

配置示例

Vert.x默认情况下不开启SPI的实现。您必须在Vert.x options中启用它。

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setJmxMetricsOptions(new VertxJmxMetricsOptions().setEnabled(true))
    .setEnabled(true)));

添加 step 和 domain

在Micrometer中, step 是指报告周期,以秒为单位。 domain 是 MBeans被注册域名之下的JMX域名。

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setJmxMetricsOptions(new VertxJmxMetricsOptions().setEnabled(true)
      .setStep(5)
      .setDomain("my.metrics.domain"))
    .setEnabled(true)));

其他后端或其组合

即使Vert.x并不对所有的Micrometer支持的后台提供实现,但是 创建Micrometer注册信息并将其传入Vert.x依然是可能的。

The list of available backends includes Graphite, Ganglia, Atlas, etc. It also enables the Micrometer Composite Registry in order to report the same metrics to multiple backends. 可用的后端包括 Graphite、Ganglia、Atlas 等等 。 它也允许 Micrometer 组合注册 从而可以向多个后端报告同一项指标。

在以下例子中,指标同时向 JMX 和 Graphite报告:

CompositeMeterRegistry myRegistry = new CompositeMeterRegistry();
myRegistry.add(new JmxMeterRegistry(s -> null, Clock.SYSTEM));
myRegistry.add(new GraphiteMeterRegistry(s -> null, Clock.SYSTEM));

Vertx vertx = Vertx.vertx(new VertxOptions()
  .setMetricsOptions(new MicrometerMetricsOptions()
    .setMicrometerRegistry(myRegistry)
    .setEnabled(true)));

高级用法

请查阅 MicrometerMetricsOptions 以获取更多的options信息。

Prometheus 中的平均值和分位数

默认情况下,当使用Prometheus注册信息时,指标的直方图不会包括平均值和分位数的分析。

平均值并非开箱即用,他们通常是用 promql 在查询时计算出来 的。 例如,Http客户端在过去5分钟内平均响应时间:

 rate(vertx_http_client_response_time_seconds_sum[5m])
/
 rate(vertx_http_client_response_time_seconds_count[5m])

要计算分位数,则有两个方案可选择。第一种,激活全局分位数分析, 并让 Prometheus 的 histogram_quantile 函数可以使用分位数:

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true)
      .setPublishQuantiles(true))
    .setEnabled(true)));

然后,例如用 promql 查询HTTP client响应时间在最近5分钟内百分之九十九的分位点:

 histogram_quantile(0.99, sum(rate(vertx_http_client_response_time_seconds_bucket[5m])) by (le))

这个方案的优点是可以在 promql 中跨维度聚合使用。 坏处是它为了统计数据而创建了大量的时间序列。

第二个方案是创建分析限制,不许跨维度聚合。 这就需要直接访问 Micrometer / Prometheus 注册信息:

PrometheusMeterRegistry registry = (PrometheusMeterRegistry) BackendRegistries.getDefaultNow();
registry.config().meterFilter(
    new MeterFilter() {
      @Override
      public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
        return DistributionStatisticConfig.builder()
            .percentiles(0.95, 0.99)
            .build()
            .merge(config);
      }
    });

也可以从以下链接见到更多的直方图和百分比:

另外,您可以下载一些 完整工作示例 。 其中有少量安装 Prometheus和在Grafana中创建视图仪表盘的说明。

禁用一些指标域

可以使用 disabledMetricsCategories 来 限制对Vert.x模块的监控。

完整的域列表详见 MetricsDomain

用户定义的指标

Micrometer 注册信息可以被访问,以便于创建新的指标或者抓去已存在的。 默认使用一个唯一的注册信息,并共享于JVM中的Vert.x实例。

MeterRegistry registry = BackendRegistries.getDefaultNow();

通过在options中给出注册信息名称的方式,可以给每个Vert.x实例分配注册信息。 然后可以分别获取:

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setInfluxDbOptions(new VertxInfluxDbOptions().setEnabled(true)) // or VertxPrometheusOptions
    .setRegistryName("my registry")
    .setEnabled(true)));

// Later on:
MeterRegistry registry = BackendRegistries.getNow("my registry");

做为示例,这里有一个自定义定时器来追踪代码块的执行时间,且经常被调用:

MeterRegistry registry = BackendRegistries.getDefaultNow();
Timer timer = Timer
  .builder("my.timer")
  .description("a description of what this timer does")
  .register(registry);

vertx.setPeriodic(1000, l -> {
  timer.record(() -> {
    // Running here some operation to monitor
  });
});

更多示例关于Micrometer注册信息文档以及如何创建指标,详见 Micrometer doc

复用一个已存在的 registry

您可以复用一个现存的 registry (或从Prometheus java客户端获取 CollectorRegistry ), 在 Vert.x metrics options 中注入它:

PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);

// You could also reuse an existing registry from the Prometheus Java client:
CollectorRegistry prometheusClientRegistry = new CollectorRegistry();
registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT, prometheusClientRegistry, Clock.SYSTEM);

// It's reused in MicrometerMetricsOptions.
// Prometheus options configured here, such as "setPublishQuantiles(true)", will affect the whole registry.
Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true)
      .setPublishQuantiles(true))
    .setMicrometerRegistry(registry)
    .setEnabled(true)));

JVM 或者其他平台

因为已经提供了对Micrometer registry的原始访问方式,所以可以直接使用 Micrometer API 。 例如,监控JVM:

MeterRegistry registry = BackendRegistries.getDefaultNow();

new ClassLoaderMetrics().bindTo(registry);
new JvmMemoryMetrics().bindTo(registry);
new JvmGcMetrics().bindTo(registry);
new ProcessorMetrics().bindTo(registry);
new JvmThreadMetrics().bindTo(registry);

详见 Micrometer 文档

指标名称

每一个Vert.x提供的指标都可以通过options重命名, 用 MetricsNamingsetMetricsNaming 即可。 在 Vert.x 4 中,默认指标名称出现了变化,目的在于更好的适应于后端约定, 但是依旧可以用 Vert.x 3.x 的指标名称,以求兼容:

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setMetricsNaming(MetricsNaming.v3Names())
    .setEnabled(true)));

Labels 和 matchers

Vert.x Micrometer Metrics 定义了一系列label(又称为 tag 或 field),用于对某一指标提供维度。 例如,和事件总线消息相关的指标有 address label, 它允许对一个事件总线地址查询时间序列,或者对比每个地址的时间序列, 或者做各种API允许的聚合操作。

当设置指标option的时候,您可以指定您想要开启的label:

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setLabels(EnumSet.of(Label.REMOTE, Label.LOCAL, Label.HTTP_CODE, Label.HTTP_PATH))
    .setEnabled(true)));

完整的label列表详见: Label

警告
启用label可能导致由大量值对象引起的后台问题以及性能问题。 所以必须谨慎使用它。 大体上,如果可能的label值是有界值,那么启用label是一个比较好的做法。

正因如此,默认开启的label被限制为已知的有界值。

除了启用/禁用,您也可以对label做更多的操作。这有两种方式可以做到:

使用 matcher

Match 对象可以通过字符串 直接匹配或者正则匹配(前者更高效)的方式来过滤或者重命名label值

以下为一个仅用 local=localhost:8080 的label来限制Http服务指标的示例:

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .addLabelMatch(new Match()
      // Restrict HTTP server metrics to those with label "local=localhost:8080" only
      .setDomain(MetricsDomain.HTTP_SERVER)
      .setLabel("local")
      .setValue("localhost:8080"))
    .setEnabled(true)));

当Match中指定了 alias ,它就会被用来做重命名而不是过滤。

Matcher 对于通过配置来控制label尤为管用, 它们要通过 MicrometerMetricsOptions 来设置。

使用 Micrometer 的 MeterFilter

Micrometer 的 MeterFilter API 可以被直接获取,以便定义规则(rule)和标签(label)。 相比于Matcher,它提供了更多操作标签的特性,但是不能从配置中定义它。 所以,这两者各有优劣。

以下为一个示例,使用正则表达式作为通用格式来替换HTTP请求中实际的 path 标签:

MeterRegistry registry = BackendRegistries.getDefaultNow();
Pattern pattern = Pattern.compile("/foo/bar/.*");

registry.config().meterFilter(
  MeterFilter.replaceTagValues(Label.HTTP_PATH.toString(), actualPath -> {
    Matcher m = pattern.matcher(actualPath);
    if (m.matches()) {
      return "/foo/bar/:id";
    }
    return actualPath;
  }, ""));
注意
Matchers 在底层使用的是 MeterFilters。

自定义标签提供器

您可以自定义一个函数来给 HTTP 服务器或客户端的指标生成额外的标签 (或 labels) 。 这个函数接收一个 HttpRequest 对象作为参数,并返回一个 装有 Tag 类型对象的 Iterable 接口实现类.

以下是一个例子,展示了如何在服务器或客户端的指标中将 x-user 头部转化为自定义的 label user

Vertx vertx = Vertx.vertx(new VertxOptions().setMetricsOptions(
  new MicrometerMetricsOptions()
    .setPrometheusOptions(new VertxPrometheusOptions().setEnabled(true))
    .setServerRequestTagsProvider(req -> {
      String user = req.headers().get("x-user");
      return Collections.singletonList(Tag.of("user", user));
    })
    .setClientRequestTagsProvider(req -> {
      String user = req.headers().get("x-user");
      return Collections.singletonList(Tag.of("user", user));
    })
    .setEnabled(true)));

快照

创建一个 MetricsService 可以用 Measured 对象, 这样便于对相关指标和度量做出一个快照。 这个快照以 JsonObject 形式返回。

一个所熟知的 Measured 对象便是 Vertx

MetricsService metricsService = MetricsService.create(vertx);
JsonObject metrics = metricsService.getMetricsSnapshot();
System.out.println(metrics);

其他组件,例如 EventBusHttpServer 是可测量的:

HttpServer server = vertx.createHttpServer();
MetricsService metricsService = MetricsService.create(server);
JsonObject metrics = metricsService.getMetricsSnapshot();
System.out.println(metrics);

最终,可以按照基本名称来过滤返回的指标:

MetricsService metricsService = MetricsService.create(vertx);
// Client + server
JsonObject metrics = metricsService.getMetricsSnapshot("vertx.http");
System.out.println(metrics);

Vert.x core tools 指标

本节列举了所有由Vert.x core tools生成的指标。

注意
指标后台可能存在不同的约定或规则来命名指标 以下是Vert.x 4 中默认的名称,他们以下划线做分隔符。 实际的名称可能基于指标后台而发生变化。

Net Client

指标名称 标签 类型 描述

vertx_net_client_bytes_read

local, remote

Counter

从远程服务接收到的字节数。

vertx_net_client_bytes_written

local, remote

Counter

发送到远程服务的字节数。

vertx_net_client_active_connections

local, remote

Gauge

当前正处于打开状态的连接数。

vertx_net_client_errors

local, remote, class

Counter

错误数。

HTTP Client

指标名称 标签 类型 描述

vertx_http_client_bytes_read

local, remote

Counter

从远程服务接收到的字节数。

vertx_http_client_bytes_written

local, remote

Counter

发送到远程服务的字节数。

vertx_http_client_active_connections

local, remote

Gauge

当前正处于打开状态的连接数。

vertx_http_client_errors

local, remote, class

Counter

错误数。

vertx_http_client_queue_time_seconds

local, remote

Timer

被执行之前,在队列中花费的时间,秒为单位。

vertx_http_client_queue_pending

local, remote

Gauge

队列中挂起状态的元素数量。

vertx_http_client_active_requests

local, remote, path, method

Gauge

当前正在执行且正等待响应的请求数量。

vertx_http_client_requests_total

local, remote, path, method

Counter

已发送的请求数。

vertx_http_client_request_bytes

local, remote, path, method

Summary

请求的大小(字节数)。

vertx_http_client_response_time_seconds

local, remote, path, method, code

Timer

响应时间(秒)。

vertx_http_client_responses_total

local, remote, path, method, code

Counter

接收到的响应数量。

vertx_http_client_response_bytes

local, remote, path, method, code

Summary

响应的大小(字节数)

vertx_http_client_active_ws_connections

local, remote

Gauge

当前打开状态的websocket数量。

Net Server

指标名称 标签 类型 描述

vertx_net_server_bytes_read

local, remote

Counter

Net Server收到的字节数。

vertx_net_server_bytes_written

local, remote

Counter

Net Server发送的字节数。

vertx_net_server_active_connections

local, remote

Gauge

Net Server 开启的连接数。

vertx_net_server_errors

local, remote, class

Counter

错误数。

HTTP Server

指标名称 标签 类型 描述

vertx_http_server_bytes_read

local, remote

Counter

HTTP Server接收的字节数。

vertx_http_server_bytes_written

local, remote

Counter

HTTP Server发送的字节数。

vertx_http_server_active_connections

local, remote

Gauge

HTTP Server开启的连接数。

vertx_http_server_errors

local, remote, class

Counter

错误数。

vertx_http_server_active_requests

local, remote, path, method

Gauge

当前正在执行状态的请求数。

vertx_http_server_requests_total

local, remote, path, method, code, route

Counter

执行完毕的请求数。

vertx_http_server_request_resets_total

local, remote, path, method

Counter

被重置的请求数。

vertx_http_server_request_bytes

local, remote, path, method

Summary

请求大小(字节)。

vertx_http_server_response_time_seconds

local, remote, path, method, code, route

Timer

请求执行的时间(秒)。

vertx_http_server_response_bytes

local, remote, path, method, code, route

Summary

响应大小(字节)。

vertx_http_client_active_ws_connections

local, remote

Gauge

当前开启状态的websocket。

Datagram socket

指标名称 标签 类型 描述

vertx_datagram_bytes_read

local

Summary

<host>:<port> 上接收到的字节总数。

vertx_datagram_bytes_written

(none)

Summary

发送到远程的字节总数。

vertx_datagram_errors

class

Counter

错误总数。

Event Bus

指标名称 标签 类型 描述

vertx_eventbus_bytes_read

address

Summary

从事件总线集群读取消息时接收到的总字节数。

vertx_eventbus_bytes_written

address

Summary

向事件总线集群发送消息的总字节数。

vertx_eventbus_handlers

address

Gauge

正在使用中的事件总线处理器数量。

vertx_eventbus_pending

address,side (local/remote)

Gauge

还未被执行的消息数。 N 个处理器被注册在同一个地址时,向此地址广播一个消息的话, 这个值则是 N

vertx_eventbus_processed

address,side (local/remote)

Counter

已执行完毕的消息数。

vertx_eventbus_published

address,side (local/remote)

Counter

消息广播数(广播/订阅)。

vertx_eventbus_discarded

address,side (local/remote)

Counter

被丢弃的消息数(例如,处理器未注册时被挂起的消息或消息溢出)。

vertx_eventbus_sent

address,side (local/remote)

Counter

发送的消息数(点对点)。

vertx_eventbus_received

address,side (local/remote)

Counter

接收的消息数。

vertx_eventbus_delivered

address,side (local/remote)

Counter

已发送到处理器的消息数。

vertx_eventbus_reply_failures

address,failure

Counter

回复失败的消息数。

Vert.x pool 指标

本章列举出了所有监控 Vert.x pool 而生成的指标。

当前支持两个类型:

  • worker (见 WorkerExecutor

  • datasource (用 Vert.x JDBC client 创建)

注意
Vert.x 前期创建两个worker pools,即 worker-threadinternal-blocking
指标名称 标签 类型 描述

vertx_pool_queue_time_seconds

pool_type,pool_name

Timer

被执行之前,在队列中花费的时间(秒)。

vertx_pool_queue_pending

pool_type,pool_name

Gauge

队列中挂起状态的元素数。

vertx_pool_usage

pool_type,pool_name

Timer

使用资源的时间(例如,worker pools 的执行时间)。

vertx_pool_in_use

pool_type,pool_name

Gauge

被占用的资源数。

vertx_pool_completed

pool_type,pool_name

Counter

此资源下的已完成的元素数(例如,worker pool已执行完毕的任务数)。

vertx_pool_ratio

pool_type,pool_name

Gauge

(仅在pool指定最大值的情况下才存在)。

其他客户端

除了核心的HTTP 客户端 / Net 客户端以外,Vert.x客户端可以实现一组标准的客户端指标。例如,SQL client。

这些客户端指标以 "客户端类型" 标识符命名,下表中以 $TYPE 代替。 例如, 对于SQL客户端来讲, vertx_$TYPE_queue_pending 就是 vertx_sql_queue_pending

namespace 标签的意义,由客户端的实现来描述。

指标名称 标签 类型 描述

vertx_$TYPE_queue_pending

remote, namespace

Gauge

队列中挂起状态的元素数。

vertx_$TYPE_queue_time_seconds

remote, namespace

Timer

被执行之前,在队列中花费的时间(秒)。

vertx_$TYPE_processing_pending

remote, namespace

Gauge

正在执行的元素数。

vertx_$TYPE_processing_time_seconds

remote, namespace

Timer

从开始发送请求到响应结束的执行时间(秒)。

vertx_$TYPE_resets_total

remote, namespace

Counter

重置数。