52. Metrics

Spring Boot Actuator 包含具有“量规”和“计数器”支持的 Metrics 服务。 “量规”记录单个值; “计数器”记录增量(增量或减量)。 Spring Boot Actuator 还提供了一个PublicMetrics接口,您可以实施该接口以公开无法通过这两种机制之一记录的 Metrics。以SystemPublicMetrics为例。

所有 HTTP 请求的 Metrics 都会自动记录,因此,如果您点击metrics端点,您应该会看到类似以下的响应:

{
    "counter.status.200.root": 20,
    "counter.status.200.metrics": 3,
    "counter.status.200.star-star": 5,
    "counter.status.401.root": 4,
    "gauge.response.star-star": 6,
    "gauge.response.root": 2,
    "gauge.response.metrics": 3,
    "classes": 5808,
    "classes.loaded": 5808,
    "classes.unloaded": 0,
    "heap": 3728384,
    "heap.committed": 986624,
    "heap.init": 262144,
    "heap.used": 52765,
    "nonheap": 0,
    "nonheap.committed": 77568,
    "nonheap.init": 2496,
    "nonheap.used": 75826,
    "mem": 986624,
    "mem.free": 933858,
    "processors": 8,
    "threads": 15,
    "threads.daemon": 11,
    "threads.peak": 15,
    "threads.totalStarted": 42,
    "uptime": 494836,
    "instance.uptime": 489782,
    "datasource.primary.active": 5,
    "datasource.primary.usage": 0.25
}

在这里,我们可以看到基本的memoryheapclass loadingprocessorthread pool信息以及一些 HTTPMetrics。在这种情况下,root('/')和/metrics URL 已分别返回HTTP 200响应203次。似乎root URL 返回HTTP 401(未授权)4次。双星号(star-star)来自 Spring MVC 匹配为/**(通常是静态资源)的请求。

gauge显示请求的最后响应时间。因此,对root的最后一个请求花了2ms进行响应,而对/metrics的最后一个请求花了3ms

Note

在此示例中,我们实际上是使用/metrics URL 通过 HTTP 访问端点,这解释了为什么metrics出现在响应中。

52.1 系统 Metrics

Spring Boot 公开了以下系统 Metrics:

  • 系统总内存,以 KB 为单位(mem)

  • 可用内存量,以 KB 为单位(mem.free)

  • 处理器数量(processors)

  • 系统正常运行时间,以毫秒为单位(uptime)

  • 应用程序上下文的正常运行时间,以毫秒为单位(instance.uptime)

  • 平均系统负载(systemload.average)

  • 堆信息,以 KB(heapheap.committedheap.initheap.used)为单位

  • 线程信息(threadsthread.peakthread.daemon)

  • 类加载信息(classesclasses.loadedclasses.unloaded)

  • 垃圾收集信息(gc.xxx.countgc.xxx.time)

52.2 数据源 Metrics

针对应用程序中定义的每个受支持的DataSource公开以下 Metrics:

  • Active 连接数(datasource.xxx.active)

  • 连接池的当前使用情况(datasource.xxx.usage)。

所有数据源 Metrics 共享datasource.前缀。对于每个数据源,该前缀进一步符合条件:

  • 如果数据源是主要数据源(即唯一的可用数据源或现有数据源中标记为@Primary的数据源),则前缀为datasource.primary

  • 如果数据源 Bean 名称以DataSource结尾,则前缀是不包含DataSource的 Bean 名称(即datasource.batch表示batchDataSource)。

  • 在所有其他情况下,都使用 Bean 的名称。

通过使用自定义版本DataSourcePublicMetrics注册 bean,可以覆盖部分或全部默认值。默认情况下,Spring Boot 为所有支持的数据源提供元数据。如果不支持立即使用您喜欢的数据源,则可以添加其他DataSourcePoolMetadataProvider bean。有关示例,请参见DataSourcePoolMetadataProvidersConfiguration

52.3 缓存 Metrics

针对应用程序中定义的每个受支持的缓存公开以下 Metrics:

  • 当前缓存的大小(cache.xxx.size)

  • 命中率(cache.xxx.hit.ratio)

  • 错过率(cache.xxx.miss.ratio)

Note

缓存提供程序不会以一致的方式公开命中率/未命中率。尽管有些暴露了“汇总”值(即自上次清除统计信息以来的命中率),而另一些暴露了“时间”值(即最后一秒的命中率)。检查您的缓存提供程序文档以获取更多详细信息。

如果两个不同的高速缓存 Management 器碰巧定义了相同的高速缓存,则高速缓存的名称将以CacheManager bean 的名称为前缀。

通过使用自定义版本CachePublicMetrics注册 bean,可以覆盖部分或全部默认值。默认情况下,Spring Boot 为 EhCache,Hazelcast,Infinispan,JCache 和 Guava 提供缓存统计信息。如果不支持立即使用您喜欢的缓存库,则可以添加其他CacheStatisticsProvider bean。有关示例,请参见CacheStatisticsAutoConfiguration

52.4 Tomcat 会话 Metrics

如果您将 Tomcat 用作嵌入式 Servlet 容器,则会话 Metrics 将自动公开。 httpsessions.activehttpsessions.max键提供 Active 会话数和最大会话数。

52.5 记录自己的 Metrics

要记录自己的 Metrics,请向您的 bean 中注入CounterService和/或GaugeServiceCounterService公开incrementdecrementreset方法; GaugeService提供了submit方法。

这是一个简单的示例,该示例计算方法被调用的次数:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.metrics.CounterService;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    private final CounterService counterService;

    @Autowired
    public MyService(CounterService counterService) {
        this.counterService = counterService;
    }

    public void exampleMethod() {
        this.counterService.increment("services.system.myservice.invoked");
    }

}

Tip

您可以将任何字符串用作度量标准名称,但应遵循所选 Store/制图技术的准则。 Matt Aimonetti 的博客提供了一些适用于 Graphite 的良好准则。

52.6 添加自己的公开 Metrics

要添加每次调用度量端点时计算的其他度量,只需注册其他PublicMetrics实现 bean。默认情况下,所有此类 bean 均由端点收集。您可以通过定义自己的MetricsEndpoint轻松更改它。

52.7 Java 8 的特殊功能

Spring Boot 提供的GaugeServiceCounterService的默认实现取决于您所使用的 Java 版本。使用 Java 8(或更高版本)时,该实现将切换到针对快速写入进行优化的高性能版本,并由原子内存缓冲区支持,而不是由不变但相对昂贵的Metric<?>类型支持(计数器的速度快大约 5 倍,而测量的速度大约是两倍)与基于存储库的实现一样快)。即使对于 Java 7(它们具有某些 Java 8 并发库的反向移植),Dropwizard 度量标准服务(请参阅下文)也非常有效,但是它们不记录度量标准值的时间戳。如果需要考虑度量收集的性能,则始终建议使用高性能选项之一,并且不经常读取度量,以便在本地缓冲写入操作,仅在需要时才读取。

Note

如果您使用的是 Java 8 或使用 DropwizardMetrics,则默认情况下不会使用旧的MetricRepository及其InMemoryMetricRepository实现。

52.8Metrics 编写器,导出器和聚合

Spring Boot 提供了一种称为Exporter的标记接口的实现,可用于将 Metrics 读数从内存中的缓冲区复制到可以分析和显示它们的位置。确实,如果您提供实现MetricWriter接口(对于简单用例为GaugeWriter)并将其标记为@ExportMetricWriter@Bean,则它将自动连接至Exporter,并每 5 秒提供一次 Metrics 更新(通过spring.metrics.export.delay-millis配置)。此外,您定义并标记为@ExportMetricReader的任何MetricReader的值都将由默认导出器导出。

Note

此功能使您可以在应用程序(@EnableScheduling)中启用计划,如果您运行集成测试,这将是一个问题,因为您自己的计划任务将开始。您可以通过将spring.metrics.export.enabled设置为false来禁用此行为。

默认的导出器是MetricCopyExporter,它试图通过不复制自上次调用以来从未更改过的值来优化自身(可以使用标志spring.metrics.export.send-latest来关闭优化)。另请注意,Dropwizard MetricRegistry不支持时间戳,因此,如果您使用 Dropwizard 度量标准,则优化不可用(所有度量标准都会在每个刻度上复制)。

导出触发器的默认值(delay-millisincludesexcludessend-latest)可以设置为spring.metrics.export.*。可以将特定MetricWriters的各个值设置为spring.metrics.export.triggers.<name>.*,其中<name>是 Bean 名称(或用于匹配 Bean 名称的模式)。

Warning

如果您关闭默认的MetricRepository(例如,使用 DropwizardMetrics),则会禁用 Metrics 的自动导出。您可以pass 语句自己的MetricReader类型的 bean 并将其声明为@ExportMetricReader来获得相同的功能。

52.8.1 示例:导出到 Redis

如果您提供类型为RedisMetricRepository@Bean并将其标记为@ExportMetricWriter,则 Metrics 将导出到 Redis 缓存以进行聚合。为此,RedisMetricRepository有两个重要的参数来配置它:prefixkey(传递到其构造函数中)。最好使用应用程序实例唯一的前缀(例如,使用随机值以及应用程序的逻辑名称,以使其可以与同一应用程序的其他实例相关联)。 “键”用于保留所有度量标准名称的全局索引,因此对于系统而言,它应该是“全局”唯一的(例如,对于您的系统而言,这是唯一的(例如,如果同一系统的两个实例具有不同的键,则它们可以共享 Redis 缓存)) 。

Example:

@Bean
@ExportMetricWriter
MetricWriter metricWriter(MetricExportProperties export) {
    return new RedisMetricRepository(connectionFactory,
        export.getRedis().getPrefix(), export.getRedis().getKey());
}

application.properties.

spring.metrics.export.redis.prefix: metrics.mysystem.${spring.application.name:application}.${random.value:0000}
spring.metrics.export.redis.key: keys.metrics.mysystem

该前缀的末尾是应用程序名称和 ID,因此以后可以轻松地使用它来标识具有相同逻辑名称的一组进程。

Note

同时设置keyprefix非常重要。该密钥用于所有存储库操作,并且可以由多个存储库共享。如果多个存储库共享一个密钥(例如,您需要在它们之间进行聚合),那么通常您会有一个只读的“主”存储库,该存储库具有一个简短但可识别的前缀(例如“ metrics.mysystem”),以及许多带有以主前缀开头的前缀的只写存储库(如上例中的metrics.mysystem.*)。像这样从“主”存储库中读取所有密钥是有效的,但是读取具有较长前缀的子集是无效的(例如,使用其中一个写入存储库)。

Tip

上面的示例使用MetricExportProperties来注入和提取密钥和前缀。为了方便起见,Spring Boot 为您提供了合理的默认配置。只要遵循建议,您就无法阻止您使用自己的价值观。

52.8.2 示例:导出到 Open TSDB

如果您提供类型为OpenTsdbGaugeWriter@Bean并将其标记为@ExportMetricWriter,则 Metrics 将导出到Open TSDB以进行汇总。 OpenTsdbGaugeWriter具有url属性,您需要将其设置为 Open TSDB“/put”端点,例如localhost:4242/api/put)。它还具有namingStrategy,您可以自定义或配置namingStrategy以使度量标准与服务器上所需的数据结构相匹配。默认情况下,它仅通过度量标准名称作为 Open TSDB 度量标准名称传递,并添加标签“ domain”(值为“ org.springframework.metrics”)和“ process”(其值等于命名的对象哈希)战略)。因此,在运行应用程序并生成一些 Metrics 之后,您可以在 TSD UI(默认为localhost:4242)中检查 Metrics。

Example:

curl localhost:4242/api/query?start=1h-ago&m=max:counter.status.200.root
[
    {
        "metric": "counter.status.200.root",
        "tags": {
            "domain": "org.springframework.metrics",
            "process": "b968a76"
        },
        "aggregateTags": [],
        "dps": {
            "1430492872": 2,
            "1430492875": 6
        }
    }
]

52.8.3 示例:导出到 Statsd

要将度量导出到 Statsd,请首先确保已添加com.timgroup:java-statsd-client作为项目的依赖项(Spring Boot 为此提供了依赖项 Management)。然后将spring.metrics.export.statsd.host值添加到application.properties文件中。除非提供spring.metrics.export.statsd.port覆盖,否则将打开到端口8125的连接。如果需要自定义前缀,可以使用spring.metrics.export.statsd.prefix

或者,您可以提供StatsdMetricWriter类型的@Bean并将其标记为@ExportMetricWriter

@Value("${spring.application.name:application}.${random.value:0000}")
private String prefix = "metrics";

@Bean
@ExportMetricWriter
MetricWriter metricWriter() {
    return new StatsdMetricWriter(prefix, "localhost", 8125);
}

52.8.4 示例:导出到 JMX

如果您提供类型JmxMetricWriter标记为@ExportMetricWriter@Bean,那么度量标准将作为 MBeans 导出到本地服务器(MBeanExporter是由 Spring Boot JMX 自动配置提供的,只要它已打开)。然后可以使用任何了解 JMX 的工具(例如 JConsole 或 JVisualVM)对 Metrics 进行检查,绘制图形,发出警报等。

Example:

@Bean
@ExportMetricWriter
MetricWriter metricWriter(MBeanExporter exporter) {
    return new JmxMetricWriter(exporter);
}

每个度量标准都作为单独的 MBean 导出。 ObjectNames的格式由ObjectNamingStrategy给出,该ObjectNamingStrategy可以注入JmxMetricWriter(默认值将 break 度量标准名称并标记前两个句点分隔的部分,其方式应能使 JVisualVM 或 JConsole 中的度量标准组很好地组合)。

52.9 汇总来自多个来源的 Metrics

您可以使用AggregateMetricReader合并来自不同物理来源的 Metrics。相同逻辑度量标准的源只需要使用句点分隔的前缀发布它们,阅读器就会进行汇总(通过截断度量标准名称并删除前缀)。对计数器求和,其他所有值(即仪表)取其最新值。

如果多个应用程序实例正在馈送到中央(例如 Redis)存储库,并且您想显示结果,这将非常有用。特别推荐与MetricReaderPublicMetrics结合使用,以将结果连接到“/metrics”端点。

Example:

@Autowired
private MetricExportProperties export;

@Bean
public PublicMetrics metricsAggregate() {
    return new MetricReaderPublicMetrics(aggregatesMetricReader());
}

private MetricReader globalMetricsForAggregation() {
    return new RedisMetricRepository(this.connectionFactory,
        this.export.getRedis().getAggregatePrefix(), this.export.getRedis().getKey());
}

private MetricReader aggregatesMetricReader() {
    AggregateMetricReader repository = new AggregateMetricReader(
        globalMetricsForAggregation());
    return repository;
}

Note

上面的示例使用MetricExportProperties来注入和提取密钥和前缀。 Spring Boot 为方便起见向您提供了此设置,默认设置是合理的。它们在MetricExportAutoConfiguration中设置。

Note

上面的MetricReaders不是@Beans,也没有标记为@ExportMetricReader,因为它们只是从其他存储库收集和分析数据,并且不希望导出其值。

52.10 DropwizardMetrics

当您声明对io.dropwizard.metrics:metrics-core库的依赖关系时,将创建默认的MetricRegistry Spring bean。如果需要自定义,还可以注册自己的@Bean实例。 Dropwizard“Metrics”库的用户将发现 Spring BootMetrics 自动发布到com.codahale.metrics.MetricRegistryMetricRegistry中的 Metrics 也会通过/metrics端点自动公开

使用 DropwizardMetrics 时,默认的CounterServiceGaugeService替换为DropwizardMetricServices,它是MetricRegistry的包装器(因此您可以@Autowired这些服务之一并可以正常使用它)。您还可以通过为 Metrics 名称添加适当的类型(即timer.*histogram.*(用于仪表)和meter.*)来创建“特殊” DropwizardMetrics。

52.11 消息通道集成

如果存在一个名为metricsChannelMessageChannel bean,那么将创建一个MetricWriter并将度量写入该通道。发送到该通道的每个消息将包含DeltaMetric有效负载,并具有metricName头。编写器自动连接到导出器(对于所有编写器),因此所有度量标准值都将显示在通道上,并且订阅者可以执行其他分析或操作(由您提供 Channels 和所需的任何订阅者) )。