Spring Boot Actuator:健康检查、审计、统计和监控
原文链接
Spring Boot Actuator可以帮助你监控和管理Spring Boot应用,比如健康检查、审计、统计和HTTP追踪等。所有的这些特性可以通过JMX或者HTTP endpoints来获得。
Actuator同时还可以与外部应用监控系统整合,比如 Prometheus, Graphite, DataDog, Influx, Wavefront, New Relic等。这些系统提供了非常好的仪表盘、图标、分析和告警等功能,Actuator使用Micrometer来整合上面提到的外部应用监控系统。这使得只要通过非常小的配置就可以集成任何应用监控系统。
增加Spring Boot Actuator到一个存在的应用
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
Actuator创建了所谓的endpoint来暴露HTTP或者JMX来监控和管理应用。
举个例子,有一个叫/health的endpoint,提供了关于应用健康的基础信息。/metricsendpoints展示了几个有用的度量信息,比如JVM内存使用情况、系统CPU使用情况、打开的文件等等。/loggersendpoint展示了应用的日志和可以让你在运行时改变日志等级。
启动程序后,可以通过http://localhost:8080/actuator来展示所有通过HTTP暴露的endpoints。(8080端口号,具体根据进程确定)
{"_links":{"self":{"href":"http://localhost:8080/actuator","templated":false},"health":{"href":"http://localhost:8080/actuator/health","templated":false},"info":{"href":"http://localhost:8080/actuator/info","templated":false}}}
打开http://localhost:8080/actuator/health,则会显示如下内容:
{"status":"UP"}
状态将是UP只要应用是健康的。如果应用不健康将会显示DOWN,比如与仪表盘的连接异常或者缺水磁盘空间等。
默认,只有health和info通过HTTP暴露了出来。
以下是一些非常有用的actuator endpoints列表:
通过设置management.endpoint..enabled to true or false(id是endpoint的id)来决定打开还是关闭一个actuator endpoint。
暴露Actuator Endpoints
默认,所有的actuator endpoint通过JMX被暴露,而通过HTTP暴露的只有health和info。
通过应用的properties可以通过HTTP和JMX暴露的actuator endpoint。
1.通过HTTP暴露Actuator endpoints。
Use “*” to expose all endpoints, or a comma-separated list to expose selected ones
management.endpoints.web.exposure.include=health,info
management.endpoints.web.exposure.exclude=
2.通过JMX暴露Actuator endpoints。
Use “*” to expose all endpoints, or a comma-separated list to expose selected ones
management.endpoints.jmx.exposure.include=*
management.endpoints.jmx.exposure.exclude=
解析常用的actuator endpoint
1./health endpoint
health endpoint通过合并几个健康指数检查应用的健康情况。
Spring Boot Actuator有几个预定义的健康指标比如DataSourceHealthIndicator, DiskSpaceHealthIndicator, MongoHealthIndicator, RedisHealthIndicator, CassandraHealthIndicator等。它使用这些健康指标作为健康检查的一部分。
举个例子,如果你的应用使用Redis,RedisHealthindicator将被当作检查的一部分。如果使用MongoDB,那么MongoHealthIndicator将被当作检查的一部分。
你也可以关闭特定的健康检查指标,比如在prpperties中使用如下命令:
management.health.mongo.enabled=false
显示详细的健康信息
health endpoint只展示了简单的UP和DOWN状态。为了获得健康检查中所有指标的详细信息,你可以通过在application.yaml中增加如下内容:
management:
endpoint:
health:
show-details: always
创建一个自定义的健康指标
你可以通过实现HealthIndicator接口来自定义一个健康指标,或者继承AbstractHealthIndicator类。
package com.example.actuator.health;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.stereotype.Component;
@Component
public class CustomHealthIndicator extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
// Use the builder to build the health status details that should be reported.
// If you throw an exception, the status will be DOWN with the exception message.
builder.up()
.withDetail("app", "Alive and Kicking")
.withDetail("error", "Nothing! I'm good.");
}
}
一旦你增加上面的健康指标到你的应用中去后,health endpoint将展示如下细节:
{
"status":"UP",
"details":{
"custom":{
"status":"UP",
"details":{
"app":"Alive and Kicking",
"error":"Nothing! I'm good."
}
},
"diskSpace":{
"status":"UP",
"details":{
"total":250790436864,
"free":97949245440,
"threshold":10485760
}
}
}
}
2. /metrics endpoint
{
"names": [
"jvm.memory.max",
"http.server.requests",
"process.files.max",
...
"tomcat.threads.busy",
"process.start.time",
"tomcat.servlet.error"
]
}
想要获得每个度量的详细信息,你需要传递度量的名称到URL中,像
http://localhost:8080/actuator/metrics/{MetricName}
3. /loggers endpoint
loggers endpoint,可以通过访问http://localhost:8080/actuator/loggers来进入。它展示了应用中可配置的loggers的列表和相关的日志等级。
你同样能够使用http://localhost:8080/actuator/loggers/{name}来展示特定logger的细节。
举个例子,为了获得root logger的细节,你可以使用http://localhost:8080/actuator/loggers/root:
{
"configuredLevel":"INFO",
"effectiveLevel":"INFO"
}
在运行时改变日志等级
loggers endpoint也允许你在运行时改变应用的日志等级。
举个例子,为了改变root logger的等级为DEBUG ,发送一个POST请求到http://localhost:8080/actuator/loggers/root,加入如下参数
{
"configuredLevel": "DEBUG"
}
使用Spring Security来保证Actuator Endpoints安全
Actuator endpoints是敏感的,必须保障进入是被授权的。如果Spring Security是包含在你的应用中,那么endpoint是通过HTTP认证被保护起来的。
如果没有, 你可以增加以下以来到你的应用中去:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
接下去让我们看一下如何覆写spring security配置,并且定义你自己的进入规则。
下面的例子展示了一个简单的spring securiy配置。它使用叫做EndPointRequest
的ReqeustMatcher工厂模式来配置Actuator endpoints进入规则。
package com.example.actuator.config;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.context.ShutdownEndpoint;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {
/*
This spring security configuration does the following
1. Restrict access to the Shutdown endpoint to the ACTUATOR_ADMIN role.
2. Allow access to all other actuator endpoints.
3. Allow access to static resources.
4. Allow access to the home page (/).
5. All other requests need to be authenticated.
5. Enable http basic authentication to make the configuration complete.
You are free to use any other form of authentication.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(EndpointRequest.to(ShutdownEndpoint.class))
.hasRole("ACTUATOR_ADMIN")
.requestMatchers(EndpointRequest.toAnyEndpoint())
.permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations())
.permitAll()
.antMatchers("/")
.permitAll()
.antMatchers("/**")
.authenticated()
.and()
.httpBasic();
}
}
为了能够测试以上的配置,你可以在application.yaml中增加spring security用户。
//Spring Security Default user name and password
spring:
security:
user:
name: actuator
password: actuator
roles: ACTUATOR_ADMIN
Spring Boot Metrics监控之Prometheus&Grafana
Prometheus
Prometheus是一个开源的监控系统,由以下几个核心组件构成:
数据爬虫:根据配置的时间定期的通过HTTP抓去metrics数据。
time-series 数据库:存储所有的metrics数据。
简单的用户交互接口:可视化、查询和监控所有的metrics。
Grafana
Grafana使你能够把来自不同数据源比如Elasticsearch, Prometheus, Graphite, influxDB等多样的数据以绚丽的图标展示出来。
Spring Boot使用Micrometer,一个应用metrics组件,将actuator metrics整合到外部监控系统中。
为了整合Prometheus,你需要增加micrometer-registry-prometheus依赖:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
一旦你增加上述的依赖,Spring Boot会自动配置一个PrometheusMeterRegistry和CollectorRegistry来收集和输出格式化的metrics数据,使得Prometheus服务器可以爬取。
所有应用的metrics数据是根据一个叫/prometheus的endpoint来设置是否可用。Prometheus服务器可以周期性的爬取这个endpoint来获取metrics数据。
prometheus endpoint暴露了格式化的metrics数据给Prometheus服务器。通过prometheus endpoint(http://localhost:8080/actuator/prometheus)看到被暴露的metrics数据。
Prometheus配置(prometheus.yml)
my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
scrape_timeout is set to the global default (10s).
Load rules once and periodically evaluate them according to the global ‘evaluation_interval’.
rule_files:
- “first_rules.yml”
- “second_rules.yml”
A scrape configuration containing exactly one endpoint to scrape:
Here it’s Prometheus itself.
scrape_configs:
The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: 'prometheus'
metrics_path defaults to '/metrics'
scheme defaults to 'http'.
static_configs:
- targets: ['127.0.0.1:9090']
- job_name: 'spring-actuator'
metrics_path: '/actuator/prometheus'
scrape_interval: 5s
static_configs:
- targets: ['HOST_IP:8080']
上面中比较重要的配置项是spring-actuator job中的scrape_configs选项。
metrics_path是Actuator中prometheus endpoint中的路径。targes包含了Spring Boot应用的HOST和PORT。
请确保替换HOST_IP为你Spring Boot应用运行的电脑的IP地址。值得注意的是,localhost将不起作用,因为我们将从docker container中连接HOST机器。你必须设置网络IP地址。
配置Grafana导入Prometheus中的metrics数据
1.在Grafana上增加Prometheus数据源
2.建立一个仪表盘图表
3.添加一个Prometheus查询
4.默认的可视化
Prometheus 查询语言
原文链接
PromQL(Prometheus Query Language)
它可以对时序数据进行筛选和聚合
1. PromQL 语法
1.1 数据类型
瞬时向量 (Instant vector): 一组时序,每个时序只有一个采样值
区间向量 (Range vector): 一组时序,每个时序包含一段时间内的多个采样值
标量数据 (Scalar): 一个浮点数
字符串 (String): 一个字符串,暂时未用
1.2 时序选择器
1.2.1 瞬时向量选择器
瞬时向量选择器用来选择一组时序在某个采样点的采样值。
最简单的情况就是指定一个度量指标,选择出所有属于该度量指标的时序的当前采样值。比如下面的表达式:
http_requests_total
可以通过在后面添加用大括号包围起来的一组标签键值对来对时序进行过滤。比如下面的表达式筛选出了 job 为 prometheus,并且 group 为 canary 的时序:
http_requests_total{job="prometheus", group="canary"}
匹配标签值时可以是等于,也可以使用正则表达式。总共有下面几种匹配操作符:
=:完全相等
!=: 不相等
=~: 正则表达式匹配
!~: 正则表达式不匹配
下面的表达式筛选出了 environment 为 staging 或 testing 或 development,并且 method 不是 GET 的时序:
http_requests_total{environment=~"staging|testing|development",method!="GET"}
度量指标名可以使用内部标签 name 来匹配,表达式 http_requests_total 也可以写成 {name=“http_requests_total”}。表达式 {name=~“job:.*”} 匹配所有度量指标名称以 job: 打头的时序。
1.2.2 区间向量选择器
区间向量选择器类似于瞬时向量选择器,不同的是它选择的是过去一段时间的采样值。可以通过在瞬时向量选择器后面添加包含在 [] 里的时长来得到区间向量选择器。比如下面的表达式选出了所有度量指标为 http_requests_total 且 job 为 prometheus 的时序在过去 5 分钟的采样值。
http_requests_total{job="prometheus"}[5m]
说明:时长的单位可以是下面几种之一:
s:seconds
m:minutes
h:hours
d:days
w:weeks
y:years
1.2.3 偏移修饰器
前面介绍的选择器默认都是以当前时间为基准时间,偏移修饰器用来调整基准时间,使其往前偏移一段时间。偏移修饰器紧跟在选择器后面,使用 offset 来指定要偏移的量。比如下面的表达式选择度量名称为 http_requests_total 的所有时序在 5 分钟前的采样值
http_requests_total offset 5m
下面的表达式选择 http_requests_total 度量指标在 1 周前的这个时间点过去 5 分钟的采样值。
http_requests_total[5m] offset 1w
- PromQL 操作符
2.1 二元操作符
PromQL 的二元操作符支持基本的逻辑和算术运算,包含算术类、比较类和逻辑类三大类。
2.1.1 算术类二元操作符
算术类二元操作符有以下几种:
+:加
-:减
*:乘
/:除
%:求余
^:乘方
算术类二元操作符可以使用在标量与标量、向量与标量,以及向量与向量之间。
二元操作符上下文里的向量特指瞬时向量,不包括区间向量。
标量与标量之间,结果很明显,跟通常的算术运算一致。
向量与标量之间,相当于把标量跟向量里的每一个标量进行运算,这些计算结果组成了一个新的向量。
向量与向量之间,会稍微麻烦一些。运算的时候首先会为左边向量里的每一个元素在右边向量里去寻找一个匹配元素(匹配规则后面会讲),然后对这两个匹配元素执行计算,这样每对匹配元素的计算结果组成了一个新的向量。如果没有找到匹配元素,则该元素丢弃。
2.1.2 比较类二元操作符
比较类二元操作符有以下几种:
== (equal)
!= (not-equal)
(greater-than)
< (less-than)
= (greater-or-equal)
<= (less-or-equal)
比较类二元操作符同样可以使用在标量与标量、向量与标量,以及向量与向量之间。默认执行的是过滤,也就是保留值。
也可以通过在运算符后面跟 bool 修饰符来使得返回值 0 和 1,而不是过滤。
标量与标量之间,必须跟 bool 修饰符,因此结果只可能是 0(false) 或 1(true)。
向量与标量之间,相当于把向量里的每一个标量跟标量进行比较,结果为真则保留,否则丢弃。如果后面跟了 bool 修饰符,则结果分别为 1 和 0。
向量与向量之间,运算过程类似于算术类操作符,只不过如果比较结果为真则保留左边的值(包括度量指标和标签这些属性),否则丢弃,没找到匹配也是丢弃。如果后面跟了 bool 修饰符,则保留和丢弃时结果相应为 1 和 0。
2.1.3 逻辑类二元操作符
逻辑操作符仅用于向量与向量之间。
and:交集
or:合集
unless:补集
具体运算规则如下:
vector1 and vector2 的结果由在 vector2 里有匹配(标签键值对组合相同)元素的 vector1 里的元素组成。
vector1 or vector2 的结果由所有 vector1 里的元素加上在 vector1 里没有匹配(标签键值对组合相同)元素的 vector2 里的元素组成。
vector1 unless vector2 的结果由在 vector2 里没有匹配(标签键值对组合相同)元素的 vector1 里的元素组成。
2.1.4 二元操作符优先级
PromQL 的各类二元操作符运算优先级如下:
^
*, /, %
+, -
==, !=, <=, <, >=, >
and, unless
or
2.2 向量匹配
见原文
2.3 聚合操作符
PromQL 的聚合操作符用来将向量里的元素聚合得更少。总共有下面这些聚合操作符:
sum:求和
min:最小值
max:最大值
avg:平均值
stddev:标准差
stdvar:方差
count:元素个数
count_values:等于某值的元素个数
bottomk:最小的 k 个元素
topk:最大的 k 个元素
quantile:分位数
聚合操作符语法如下:
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
其中 without 用来指定不需要保留的标签(也就是这些标签的多个值会被聚合),而 by 正好相反,用来指定需要保留的标签(也就是按这些标签来聚合)。
下面来看几个示例:
sum(http_requests_total) without (instance)
http_requests_total 度量指标带有 application、instance 和 group 三个标签。上面的表达式会得到每个 application 的每个 group 在所有 instance 上的请求总数。效果等同于下面的表达式:
sum(http_requests_total) by (application, group)
下面的表达式可以得到所有 application 的所有 group 的所有 instance 的请求总数。
sum(http_requests_total)
- 函数
Prometheus 内置了一些函数来辅助计算,下面介绍一些典型的。
abs():绝对值
sqrt():平方根
exp():指数计算
ln():自然对数
ceil():向上取整
floor():向下取整
round():四舍五入取整
delta():计算区间向量里每一个时序第一个和最后一个的差值
sort():排序
Metrics类型
Prometheus定义了4中不同的指标类型(metric type):Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)、Summary(摘要)。
1.counter:此类型的指标其工作方式和计数器一样,只增不减(除非系统发生重置)。例如 node_cpu_seconds_total{mode=“idle”} cpu空闲时间。
2.Gauge:用于反应该样本的当前状态,该样本数可增可减。例如可用内存大小。
3.Histogram与Summary:都是比例型的数值,统计数据的分布情况,如最小值,最大值,中间值,中位数,75百分位,90百分位,95百分位,98百分位,99百分位和99.9百分位(percentiles),近似于百分比估算数值。两种区别在于summary分位数是客户端计算上报,histogram中位数涉及服务端计算。
此处Http_response_time来解释此类型数据:
http请求响应时间:一次用户http请求在系统传输和执行过程中总共花费的时间,nginx的access_log有一列就为此时间。
需求:抓取某个业务当天access_log,并监控用户的访问时间,如何操作?
方案1:所有请求访问时间总和求平均值 假如当天100w次访问平均值为0.05s
情景1: 假如当天发生线上故障:中午1:00 - 1:05,整体用户请求响应时间0.5-1s。此种方案无法反映此段故障。
情景2: 慢请求,有一小部分用户由于程序bug,或系统或其他原因,请求响应时间比平均值大很多,甚至5s,10s 。此种方案也无法反应此情况。
方案2:基于Histogram的metrics类型(prometheus提供了一个基于Histogram算法的函数可供直接使用)分别统计出各段响应时间的用户:
~=0.0.5s 的请求数 , 0~0.05s的请求数 ,>2s的请求数 ,>10s的请求数
以下两个函数都用于counter类型数据
increase( )
eg:某一分钟cpu使用时间 increase()[1m]=该分钟末cpu使用时间-该分钟初cpu使用时间
rate()
eg:某一分钟cpu使用率 rate()[1m]=某一分钟cpu使用时间/60s
即 rate()=increase( )/60s
topk(3,rate(监控项(表达式))) 可用于监控单核cpu使用率前3 > xxx告警
sum() by ()
将某表达式查出的所有数据相加即为sum(), 再将相加的值通过某个特性进行分组,即为 sum() by()
例如监控某台主机(非单核)的cpu使用率
count()
对于满足某个表达式的监控项进行计数
eg: cpu使用率大于80%的服务器超过30台告警
_over_time()
以下函数允许聚合给定范围向量的每个系列随时间的变化并返回具有每系列聚合结果的即时向量:
avg_over_time(range-vector): 范围向量内每个度量指标的平均值。
min_over_time(range-vector): 范围向量内每个度量指标的最小值。
max_over_time(range-vector): 范围向量内每个度量指标的最大值。
sum_over_time(range-vector): 范围向量内每个度量指标的求和值。
count_over_time(range-vector): 范围向量内每个度量指标的样本数据个数。
quantile_over_time(scalar, range-vector): 范围向量内每个度量指标的样本数据值分位数,φ-quantile (0 ≤ φ ≤ 1)
stddev_over_time(range-vector): 范围向量内每个度量指标的总体标准偏差。
`stdvar_over_time(range-vector): 范围向量内每个度量指标的总体标准方差。
eg:
该主机1天内node_load5的最大值
max_over_time (node_load5{instance=“1.1.1.1:9100”}[24h])
1h内的内存使用率 100 * (1 - ((avg_over_time(node_memory_MemFree_bytes[1h]) + avg_over_time(node_memory_Cached_bytes[1h]) + avg_over_time(node_memory_Buffers_bytes[1h])) / avg_over_time(node_memory_MemTotal_bytes[1h])))