Vert.x Micrometer 指标监控
这个项目是 Vert.x Metrics Service Provider Interface (SPI) 的一个实现。 它使用 Micrometer 来管理运行指标并向后端报告。
特性
-
Vert.x core 组件监控:TCP/HTTP 客户端和服务端、
DatagramSocket
、EventBus
和各类 pool -
用户通过Micrometer定义的监控指标
-
向所有 Micrometer 支持的后端发送报告
-
内置可选项: InfluxDB 、 Prometheus 、 JMX 报告。
InfluxDB
预先准备
按照 说明文档启动并运行 InfluxDb 。
开始
必须要在classpath下添加 vertx-micrometer-metrics 和 micrometer-registry-influx 模块。
Maven 用户应在 pom文件中添加如下依赖:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-micrometer-metrics</artifactId>
<version>4.0.3</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.0.3'
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)));
Prometheus
预先准备
按照 手册启动并运行Prometheus 。
开始
必须在classpath中添加 vertx-micrometer-metrics 和 micrometer-registry-prometheus 模块。 您也许需要 vertx-web 来开放监控指标。
Maven用户在pom文件中添加如下依赖:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-micrometer-metrics</artifactId>
<version>4.0.3</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.0.3'
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-metrics 和 micrometer-registry-jmx 。
Maven用户在pom文件中添加如下依赖:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-micrometer-metrics</artifactId>
<version>4.0.3</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.0.3'
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);
}
});
也可以从以下链接见到更多的直方图和百分比:
-
from Micrometer doc
-
from Prometheus doc
另外,您可以下载一些 完整工作示例 。 其中有少量安装 Prometheus和在Grafana中创建视图仪表盘的说明。
用户定义的指标
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重命名,
用 MetricsNaming
和 setMetricsNaming
即可。
在 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。 |
快照
创建一个 MetricsService
可以用 Measured
对象,
这样便于对相关指标和度量做出一个快照。
这个快照以 JsonObject
形式返回。
一个所熟知的 Measured 对象便是 Vertx
:
MetricsService metricsService = MetricsService.create(vertx);
JsonObject metrics = metricsService.getMetricsSnapshot();
System.out.println(metrics);
其他组件,例如 EventBus
或 HttpServer
是可测量的:
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
指标名称 | 标签 | 类型 | 描述 |
---|---|---|---|
|
|
Counter |
从远程服务接收到的字节数。 |
|
|
Counter |
发送到远程服务的字节数。 |
|
|
Gauge |
当前正处于打开状态的连接数。 |
|
|
Counter |
错误数。 |
HTTP Client
指标名称 | 标签 | 类型 | 描述 |
---|---|---|---|
|
|
Counter |
从远程服务接收到的字节数。 |
|
|
Counter |
发送到远程服务的字节数。 |
|
|
Gauge |
当前正处于打开状态的连接数。 |
|
|
Counter |
错误数。 |
|
|
Timer |
被执行之前,在队列中花费的时间,秒为单位。 |
|
|
Gauge |
队列中挂起状态的元素数量。 |
|
|
Gauge |
当前正在执行且正等待响应的请求数量。 |
|
|
Counter |
已发送的请求数。 |
|
|
Summary |
请求的大小(字节数)。 |
|
|
Timer |
响应时间(秒)。 |
|
|
Counter |
接收到的响应数量。 |
|
|
Summary |
响应的大小(字节数) |
|
|
Gauge |
当前打开状态的websocket数量。 |
Net Server
指标名称 | 标签 | 类型 | 描述 |
---|---|---|---|
|
|
Counter |
Net Server收到的字节数。 |
|
|
Counter |
Net Server发送的字节数。 |
|
|
Gauge |
Net Server 开启的连接数。 |
|
|
Counter |
错误数。 |
HTTP Server
指标名称 | 标签 | 类型 | 描述 |
---|---|---|---|
|
|
Counter |
HTTP Server接收的字节数。 |
|
|
Counter |
HTTP Server发送的字节数。 |
|
|
Gauge |
HTTP Server开启的连接数。 |
|
|
Counter |
错误数。 |
|
|
Gauge |
当前正在执行状态的请求数。 |
|
|
Counter |
执行完毕的请求数。 |
|
|
Counter |
被重置的请求数。 |
|
|
Summary |
请求大小(字节)。 |
|
|
Timer |
请求执行的时间(秒)。 |
|
|
Summary |
响应大小(字节)。 |
|
|
Gauge |
当前开启状态的websocket。 |
Datagram socket
指标名称 | 标签 | 类型 | 描述 |
---|---|---|---|
|
|
Summary |
于 |
|
(none) |
Summary |
发送到远程的字节总数。 |
|
|
Counter |
错误总数。 |
Event Bus
指标名称 | 标签 | 类型 | 描述 |
---|---|---|---|
|
|
Summary |
从事件总线集群读取消息时接收到的总字节数。 |
|
|
Summary |
向事件总线集群发送消息的总字节数。 |
|
|
Gauge |
正在使用中的事件总线处理器数量。 |
|
|
Gauge |
还未被执行的消息数。 |
|
|
Counter |
已执行完毕的消息数。 |
|
|
Counter |
消息广播数(广播/订阅)。 |
|
|
Counter |
被丢弃的消息数(例如,处理器未注册时被挂起的消息或消息溢出)。 |
|
|
Counter |
发送的消息数(点对点)。 |
|
|
Counter |
接收的消息数。 |
|
|
Counter |
已发送到处理器的消息数。 |
|
|
Counter |
回复失败的消息数。 |
Vert.x pool 指标
本章列举出了所有监控 Vert.x pool 而生成的指标。
当前支持两个类型:
-
worker (见
WorkerExecutor
) -
datasource (用 Vert.x JDBC client 创建)
注意
|
Vert.x 前期创建两个worker pools,即 worker-thread 和 internal-blocking 。 |
指标名称 | 标签 | 类型 | 描述 |
---|---|---|---|
|
|
Timer |
被执行之前,在队列中花费的时间(秒)。 |
|
|
Gauge |
队列中挂起状态的元素数。 |
|
|
Timer |
使用资源的时间(例如,worker pools 的执行时间)。 |
|
|
Gauge |
被占用的资源数。 |
|
|
Counter |
此资源下的已完成的元素数(例如,worker pool已执行完毕的任务数)。 |
|
|
Gauge |
(仅在pool指定最大值的情况下才存在)。 |
其他客户端
除了核心的HTTP 客户端 / Net 客户端以外,Vert.x客户端可以实现一组标准的客户端指标。例如,SQL client。
这些客户端指标以 "客户端类型" 标识符命名,下表中以 $TYPE
代替。
例如, 对于SQL客户端来讲, vertx_$TYPE_queue_pending
就是 vertx_sql_queue_pending
。
namespace
标签的意义,由客户端的实现来描述。
指标名称 | 标签 | 类型 | 描述 |
---|---|---|---|
|
|
Gauge |
队列中挂起状态的元素数。 |
|
|
Timer |
被执行之前,在队列中花费的时间(秒)。 |
|
|
Gauge |
正在执行的元素数。 |
|
|
Timer |
从开始发送请求到响应结束的执行时间(秒)。 |
|
|
Counter |
重置数。 |