Spring Boot Actuator包含一个带有“gauge”和“counter”支持的指标服务。 'gauge'记录单个值; 并且'counter'记录增量(增加或减少)。 Spring Boot Actuator还提供了一个PublicMetrics接口,可以实现该接口以公开无法通过这两种机制之一记录的指标。 参考org.springframework.boot.actuate.endpoint.SystemPublicMetrics类。
所有HTTP请求的度量标准都会自动记录,因此如果点击 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
}
在这里,我们可以看到基本内存、堆、类加载、处理器和线程池信息以及一些HTTP指标。 在这种情况下,root('/') 和 /metrics URL分别返回HTTP 200响应 20 和 3次。 还会看到根URL返回HTTP 401(未授权)4次。 双星号(star-star)来自Spring MVC匹配的请求/**(通常是静态资源)。
gauge显示请求的最后响应时间。 因此,对root的最后一个请求需要2ms才能响应,而最后一个请求需要3ms。
注:在此示例中,我们实际上是使用 /metrics URL通过HTTP访问端点,这解释了为什么metrics出现在响应中。
1. 系统指标
Spring Boot暴露了以下系统指标:
- 系统总内存,单位:KB(mem)(KB)
- 可用内存量,单位:KB(mem.free)
- 处理器数量(processors)
- 系统正常运行时间,单位:毫秒(uptime)
- 应用程序上下文的正常运行时间,单位:毫秒(instance.uptime)
- 平均系统负载(systemload.average)
- 堆信息,单位:KB(heap,heap.committed,heap.init,heap.used)
- 线程信息(threads,thread.peak,thread.daemon)
- 类加载信息(classes,classes.loaded,classes.unloaded)
- 垃圾收集信息(gc.xxx.count,gc.xxx.time)
2. 数据源指标
为应用程序中定义的每个受支持的DataSource暴露以下指标:
- 活动连接数(datasource.xxx.active)
- 连接池的当前用法(datasource.xxx.usage)。
所有数据源指标共享 datasource. 前缀。前缀进一步限定每个数据源:
- 如果数据源是主数据源(即唯一可用的数据源或现有数据源中标记为@Primary的数据源),则前缀为datasource.primary。
- 如果数据源bean名称以DataSource结尾,则前缀是没有DataSource的bean的名称(即batchDataSource的datasource.batch)。
- 在所有其他情况下,使用bean的名称。
通过使用自定义版本的DataSourcePublicMetrics注册bean,可以覆盖部分或全部默认值。默认情况下,Spring Boot为所有支持的数据源提供元数据;如果开箱即用不支持喜欢的数据源,则可以添加其他DataSourcePoolMetadataProvider bean。有关示例,请参阅DataSourcePoolMetadataProvidersConfiguration。
3. 缓存指标
为应用程序中定义的每个支持的缓存公开以下度量标准:
- 当前缓存大小(cache.xxx.size)
- 命中率(cache.xxx.hit.ratio)
- 未命中率(cache.xxx.miss.ratio)
注:缓存提供程序不会以一致的方式公开命中/未命中率。虽然一些暴露了聚合值(即自上次清除统计数据以来的命中率),其他人暴露了时间值(即最后一秒的命中率)。
如果两个不同的缓存管理器碰巧定义了相同的缓存,则缓存的名称以CacheManager bean的名称为前缀。
通过使用自定义版本的CachePublicMetrics注册bean,可以覆盖部分或全部默认值。默认情况下,Spring Boot为EhCache,Hazelcast,Infinispan,JCache和Guava提供缓存统计信息。如果开箱即用不支持使用的缓存库,则可以添加其他CacheStatisticsProvider bean。有关示例,请参阅CacheStatisticsAutoConfiguration。
4. Tomcat会话指标
如果使用Tomcat作为嵌入式servlet容器,则会自动公开会话指标。 httpsessions.active和httpsessions.max键提供活动会话数和最大会话数。
5. 记录自己的指标
要记录自己的指标,请在bean中注入CounterService和GaugeService,或只有GaugeService。 CounterService暴露increment,decrement和reset方法; 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");
}
}
可以使用任何字符串作为指标名称,但应遵循所选 store/graphing 技术的指导原则。 可以参考https://matt.aimonetti.net/posts/2013/06/26/practical-guide-to-graphite-monitoring/
6. 添加自己的公共指标
要添加每次调用指标端点时计算的其他指标,只需注册其他PublicMetrics实现bean即可。默认情况下,端点会收集所有此类Bean。可以通过定义自己的MetricsEndpoint轻松更改它。
7. Java 8的特殊功能
Spring Boot提供的GaugeService和CounterService的默认实现取决于使用的Java版本。使用Java 8(或更好),实现切换到针对快速写入优化的高性能版本,由原子内存缓冲区支持,而不是由不可变但相对昂贵的 Metric <?> 类型(计数器大约快5倍)仪表的速度大约是基于存储库的实现的两倍。 Dropwizard指标服务(见下文)即使对于Java 7也是非常有效的(它们具有一些Java 8并发库的后端),但它们不记录指标值的时间戳。如果关注指标收集的性能是一个问题,那么始终建议使用其中一个高性能选项,并且不经常读取指标,以便在本地缓冲写入并仅在需要时读取。
注:如果使用的是Java 8,或者使用的是Dropwizard指标,则默认情况下不使用旧的MetricRepository及其InMemoryMetricRepository实现。
8. 指标写入,导出和聚合
Spring Boot提供了一些名为Exporter的标记接口实现,可用于将内存缓冲区中的指标读数复制到可以分析和显示它们的位置。实际上,如果提供实现MetricWriter接口的@Bean(或简单用例的GaugeWriter)并将其标记为@ExportMetricWriter,那么它将自动连接到Exporter并每5秒进行一次指标更新(通过spring.metrics.export.delay-millis配置)。此外,定义并标记为@ExportMetricReader的任何MetricReader都将使其值由默认导出器导出。
注:此功能可以在应用程序中启用定时任务(@EnableScheduling),如果在自己的定时任务开始时运行集成测试,这可能会出现问题。可以通过将spring.metrics.export.enabled设置为false来禁用此行为。
默认导出器是MetricCopyExporter,它尝试通过不复制自上次调用以来未更改的值来优化自身(可以使用标志spring.metrics.export.send-latest关闭优化)。另请注意,Dropwizard MetricRegistry不支持时间戳,因此如果使用的是Dropwizard指标,则无法进行优化(所有指标都会在每个刻度上复制)。
导出触发器的默认值(delay-millis,includes,excludes和send-latest)可以设置为spring.metrics.export.*。特定MetricWriters的各个值可以设置为 spring.metrics.export.triggers.<name>.* ,其中<name>是bean名称(或匹配bean名称的模式)。
注:如果关闭默认的MetricRepository(例如,使用Dropwizard指标),则会禁用指标的自动导出。可以返回相同的功能,声明自己的类型为MetricReader的bean,并将其声明为@ExportMetricReader。
8.1 示例:导出到Redis
如果提供类型为RedisMetricRepository的@Bean并将其标记为@ExportMetricWriter,则会将指标导出到Redis缓存以进行聚合。 RedisMetricRepository有两个重要的参数来配置它:prefix和key(传递给它的构造函数)。 最好使用应用程序实例唯一的前缀(例如,使用随机值以及应用程序的逻辑名称,以便可以与同一应用程序的其他实例相关联)。 “密钥”用于保存所有指标名称的全局索引,因此它应该是全局唯一的,无论对系统意味着什么(例如,如果它们具有不同的密钥,则同一系统的两个实例可以共享Redis缓存)。
例:
@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构造,因此可以在以后轻松地用于标识具有相同逻辑名称的一组进程。
注:
- 设置密钥和前缀非常重要。密钥用于所有存储库操作,并且可以由多个存储库共享。如果多个存储库共享一个密钥(就像你需要在它们之间聚合一样),那么你通常有一个只读的“主”存储库,它有一个简短但可识别的前缀(比如“metrics.mysystem”),许多只写的存储库,前缀以主前缀开头(如上例中的metrics.mysystem.*)。从这样的“主”存储库中读取所有密钥是有效的,但是读取具有较长前缀的子集(例如,使用其中一个写入存储库)是低效的。
- 上面的示例使用MetricExportProperties来注入和提取密钥和前缀。这是Spring Boot提供的便利方式,配置了合理的默认值。只要他们遵循建议,没有什么可以阻止你使用自己的值。
8.2 示例:导出到Open TSDB
如果提供类型为OpenTsdbGaugeWriter的@Bean并将其标记为@ExportMetricWriter,则将指标导出到Open TSDB以进行聚合。 OpenTsdbGaugeWriter有一个url属性,需要将其设置为Open TSDB “/put” 端点,例如 localhost:4242/api/put )。它还有一个namingStrategy,可以自定义或配置它,使指标与服务器上所需的数据结构相匹配。默认情况下,它只是将指标名称作为Open TSDB度量标准名称传递,并添加标记“domain”(带有值“org.springframework.metrics”)和“process”(值等于命名的对象哈希值的策略)。因此,在运行应用程序并生成一些指标后,可以检查TSD UI中的指标(默认情况下为localhost:4242)。
例:
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
}
}
]
8.3 示例:导出到Statsd
要将指标导出到Statsd,请首先确保已添加 com.timgroup:java-statsd-client 作为项目的依赖项(Spring Boot为其提供了依赖关系管理)。 然后将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);
}
8.4 示例:导出到JMX
如果提供标记为@ExportMetricWriter的JmxMetricWriter类型的@Bean,则指标将作为MBean导出到本地服务器(只要打开它,MBeanExporter就会由Spring Boot JMX自动配置提供)。 然后可以使用任何了解JMX的工具(例如JConsole或JVisualVM)检查,绘制图表,警告等指标。
例:
@Bean
@ExportMetricWriter
MetricWriter metricWriter(MBeanExporter exporter) {
return new JmxMetricWriter(exporter);
}
每个指标都作为单个MBean导出。 ObjectNames的格式由ObjectNamingStrategy给出,可以将其注入JmxMetricWriter(默认情况下会拆分指标名称,并以一种应该在JVisualVM或JConsole中很好地构建指标组的方式标记前两个句点分隔的部分)。
9. 汇总来自多个来源的指标
可以使用AggregateMetricReader整合来自不同物理来源的指标。同一逻辑指标的源只需要使用以句点分隔的前缀暴露它们,读取器将聚合(通过截断指标名称,并删除前缀)。计数器累加,其他一切(如 gauges)采用最新的值。
如果多个应用程序实例正在向中央(例如Redis)存储库提供并且想要显示结果,那么这非常有用。特别推荐与MetricReaderPublicMetrics结合使用,以便将结果连接到“/metrics”端点。
例:
@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;
}
上面的示例使用MetricExportProperties来注入和提取密钥和前缀。这是Spring Boot提供的方便,默认值是明智的。它们在MetricExportAutoConfiguration中设置。
注:上面的MetricReaders不是@Beans,并且没有标记为@ExportMetricReader,因为它们只是收集和分析来自其他存储库的数据,并且不想导出它们的值。
10. Dropwizard指标
当声明对 io.dropwizard.metrics:metrics-core 库的依赖关系时,将创建默认的MetricRegistry Spring bean;如果需要自定义,还可以注册自己的@Bean实例。 Dropwizard 'Metrics' 库的用户会发现Spring Boot指标会自动发布到com.codahale.metrics.MetricRegistry。 MetricRegistry中的指标也会通过 /metrics 端点自动暴露。
当Dropwizard指标都在使用,默认CounterService和GaugeService被替换为DropwizardMetricServices,是MetricRegistry的包装(这样你就可以@Autowired其中的一个服务,像正常一样使用它)。还可以通过在指标名称前加上适当的类型(即timer.*,gauges的histogram.*,counters的meter.*)来创建 “特殊” Dropwizard指标。
11. 消息通道集成
如果存在名为metricsChannel的MessageChannel bean,则将创建MetricWriter,将指标写入该通道。发送到通道的每条消息都将包含Delta或Metric有效负载,并具有metricName头。写入器自动连接到导出器(与所有写入器一样),因此所有指标值都将出现在通道上,订阅者可以进行其他分析或操作(由自己提供通道和所需的任何订阅者) )。