Spring Boot Actuator是Spring Boot 2发布后最改进的项目之一。它已经通过了主要的改进,旨在简化定制,包括一些新的功能,例如对其他Web技术的支持,例如新的反应式模块——SpringWebFlux。它还增加了对将度量导出到influxdb的开箱即用支持,influxdb是一个开源时间序列数据库,设计用于处理大量时间戳数据。与使用SpringBoot1.5的版本相比,这确实是一个很大的简化。您可以通过阅读我以前的文章中的一篇使用grafana和influxdb定制度量可视化来了解自己的价值。我在这里描述了如何使用@exportmetricswriter bean将Spring引导执行器生成的度量导出到influxdb。示例Spring引导应用程序可用于分支主服务器中关于Github存储库示例Spring Graphite(https://github.com/piomin/sample-spring-graphite.git)的文章。在当前的文章中,我创建了spring2分支(https://github.com/piomin/sample-spring-graphite/tree/spring2),它演示了如何使用2.0版的Spring Boot和Spring Boot Actuator实现相同的功能。
此外,我将向您展示如何将相同的度量导出到另一个流行的监控系统,以有效地存储时间序列数据-prometheus。infloxdb和prometheus之间的输出度量模型有一个主要的区别。第一个是基于推的系统,第二个是基于拉的系统。因此,我们的示例应用程序需要主动地将数据发送到influxdb监控系统,而使用prometheus,它只需要公开将定期获取数据的端点。让我们从influxdb开始。
1. Running InfluxDB
第一步对于我的例子来说是典型的——我们将运行带有influxdb的docker容器。这是在本地计算机上运行influxdb并通过8086端口公开HTTP API的最简单命令。
$ docker run -d --name influx -p 8086:8086 influxdb
一旦我们启动了这个容器,您可能会想在那里登录并执行一些命令。没什么简单的,只要运行下面的命令就可以了。登录后,您应该看到目标Docker容器上运行的influxdb版本。
$ docker exec -it influx influx
Connected to http://localhost:8086 version 1.5.2
InfluxDB shell version: 1.5.2
第一步是创建数据库。正如您可能猜测的那样,可以使用命令create database来实现TT。然后切换到新创建的数据库。
$ create database springboot
$ use springboot
你对这个语义熟悉吗?是的,influxdb提供了与SQL非常相似的查询语言。它被称为inluxql,允许您定义select语句、group by或into子句等等。但是,在执行这样的查询之前,我们应该将数据存储在数据库中,对吗?现在,让我们继续下一步,以生成一些测试度量。
2. 整合 Spring Boot 应用和InfluxDB
如果micrometer-registry-influx加入项目的依赖项,将自动启用到influxdb的导出。当然,我们还需要包括Spring Boot Actuator。
org.springframework.boot
spring-boot-starter-actuator
io.micrometer
micrometer-registry-influx
唯一要做的就是重写influxdb的默认地址,因为我们正在VM上运行influxdb docker容器。默认情况下,Spring引导数据尝试连接名为mydb的数据库。但是,我已经创建了数据库SpringBoot,所以我也应该覆盖这个默认值。在SpringBoot的版本2中,所有与 Spring Boot Actuator endpoints相关的配置属性都已移到Management.*部分。
在启动SpringBoot应用程序之后,类路径中包含了actuator,您可能会有点惊讶,因为它默认只公开两个HTTP端点/actuator/info和/actuator/health。这就是为什么在最新版本的SpringBoot中,除了/health和/info之外的所有执行器在默认情况下都是禁用的,用于安全目的。要启用所有执行器enpoint,必须将property management.endpoints.web.exposure.include设置为“*”。
在最新版本的Spring引导中,对HTTP度量的监视得到了显著的改进。我们可以通过将property management.metrics.web.server.auto-time-requests设置为true来收集所有Spring MVC度量。或者,当它设置为false时,您可以通过用@timed对其进行注释来为特定的REST控制器启用度量。您还可以在控制器内注释单个方法,以仅为特定端点生成度量。
3. 建立Spring Boot
SpringBoot的示例Spring引导应用程序由单个控制器组成,该控制器实现用于操作人员实体、存储库bean和实体类的基本CRUD操作。应用程序使用提供CRUD实现的SpringDataJPA存储库连接到MySQL数据库。这是控制器类。
@RestController
@Timed
public class PersonController {
protected Logger logger = Logger.getLogger(PersonController.class.getName());
@Autowired
PersonRepository repository;
@GetMapping("/persons/pesel/{pesel}")
public List findByPesel(@PathVariable("pesel") String pesel) {
logger.info(String.format("Person.findByPesel(%s)", pesel));
return repository.findByPesel(pesel);
}
@GetMapping("/persons/{id}")
public Person findById(@PathVariable("id") Integer id) {
logger.info(String.format("Person.findById(%d)", id));
return repository.findById(id).get();
}
@GetMapping("/persons")
public List findAll() {
logger.info(String.format("Person.findAll()"));
return (List) repository.findAll();
}
@PostMapping("/persons")
public Person add(@RequestBody Person person) {
logger.info(String.format("Person.add(%s)", person));
return repository.save(person);
}
@PutMapping("/persons")
public Person update(@RequestBody Person person) {
logger.info(String.format("Person.update(%s)", person));
return repository.save(person);
}
@DeleteMapping("/persons/{id}")
public void remove(@PathVariable("id") Integer id) {
logger.info(String.format("Person.remove(%d)", id));
repository.deleteById(id);
}
}
在运行应用程序之前,我们已经设置了mysql数据库。最方便的实现方法是通过mysql docker image。下面的命令运行带有数据库grafana的容器,定义用户和密码,并在Mysql上公开33306端口。
docker run -d --name mysql -e MYSQL_DATABASE=grafana -e MYSQL_USER=grafana -e MYSQL_PASSWORD=grafana -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -p 33306:3306 mysql:5
然后我们需要在应用程序端设置一些数据库配置属性。由于将spring.jpa.properties.hibernate.hbm2ddl.auto属性设置为更新,所有必需的表都将在应用程序启动时创建。
4。生成metrics
在启动应用程序和所需的Docker容器之后,唯一需要做的就是生成一些测试统计信息。我创建了JUnit测试类,它生成一些测试数据,并在循环中调用应用程序公开的端点。这是那个测试方法的片段。
int ix = new Random().nextInt(100000);
Person p = new Person();
p.setFirstName("Jan" + ix);
p.setLastName("Testowy" + ix);
p.setPesel(new DecimalFormat("0000000").format(ix) + new DecimalFormat("000").format(ix%100));
p.setAge(ix%100);
p = template.postForObject("http://localhost:2222/persons", p, Person.class);
LOGGER.info("New person: {}", p);
p = template.getForObject("http://localhost:2222/persons/{id}", Person.class, p.getId());
p.setAge(ix%100);
template.put("http://localhost:2222/persons", p);
LOGGER.info("Person updated: {} with age={}", p, ix%100);
template.delete("http://localhost:2222/persons/{id}", p.getId());
现在,让我们回到步骤1。您可能还记得,我已经向您展示了如何在influxdb docker容器中运行influx客户机。工作几分钟后,测试单元应该多次调用暴露的端点。我们可以检查存储在influx上的metric http_server_请求的值。下面的查询返回在过去3分钟内收集的测量值列表。
如您所见,所有由Spring引导执行器生成的度量都用以下信息标记:方法、URI、状态和异常。由于有了这些标签,我们可以很容易地对每个签名端点的度量进行分组,包括失败和成功百分比。让我们看看如何在grafana中配置和查看它。
5.使用Gravana实现度量可视化
一旦我们成功地将度量导出到influxdb,现在是时候使用grafana可视化它们了。首先,让我们用grafana运行docker container。
$ docker run -d --name grafana -p 3000:3000 grafana/grafana
Grafana为创建流入查询提供了用户友好的界面。我们定义了一个图形,它可视化每个调用端点的请求处理时间和应用程序接收的请求总数。如果我们按方法类型和URI过滤存储在表http_server_请求中的统计信息,我们将收集每个端点生成的所有度量。
应为其他端点创建类似的定义。我们将在一个图表上对它们进行说明。
这是最后的结果。
下面是可视化发送到应用程序的请求总数的图表。
6. 运行Prometheus
在本地运行Prometheus最合适的方法显然是通过码头集装箱。API暴露在端口9090下。我们还应该传递初始配置文件和Docker网络的名称。为什么?您将在本步骤描述的下一部分中找到所有答案。
docker run -d --name prometheus -p 9090:9090 -v /tmp/prometheus.yml:/etc/prometheus/prometheus.yml --network springboot prom/prometheus
与influxdb不同,prometheus从应用程序中提取度量。因此,我们需要启用为普罗米修斯公开度量的执行器端点,这在默认情况下是禁用的。要启用它,请将property management.endpoint.prometheus.enabled设置为true,如下面的配置片段所示。
然后我们应该在prometheus配置文件中设置应用程序公开的执行器端点的地址。scrape_配置部分负责指定一组目标和描述如何与它们连接的参数。默认情况下,prometheus尝试每分钟从定义的目标端点收集一次数据。
与集成influxdb类似,我们需要将以下工件包含到项目的依赖项中。
io.micrometer
micrometer-registry-prometheus
在我的例子中,Docker在VM上运行,并且在IP 192.168.99.100下可用。如果我希望prometheus能够连接我的应用程序,它作为docker容器启动,我也应该作为docker容器启动它。连接两个独立容器最方便的方法是通过Docker网络。如果两个容器都被分配到同一个网络,它们将能够使用容器的名称作为目标地址彼此连接。Dockerfile在示例应用程序源代码的根目录中可用。下面可见的第二个命令(docker build)不是必需的,因为我的docker hub存储库中提供了必需的image piomin/person服务。
$ docker network create springboot
$ docker build -t piomin/person-service .
$ docker run -d --name person-service -p 2222:2222 --network springboot piomin/person-service
7.集成prometheus和Grafana
prometheus在地址192.168.99.100:9090下公开了Web控制台,您可以在其中指定带有度量的查询和显示图形。但是,我们可以将它与Grafana集成,以利用该工具提供的更好的可视化效果。首先,您应该创建普罗米修斯数据源。
然后,我们应该定义从PrometheusAPI收集度量的查询。Spring Boot Actuator公开了与HTTP流量相关的三个不同指标:http_server_requests_seconds_count、http_server_requests_seconds_sum和http_server_requests_seconds_max。例如,我们可以计算http_server_requests_seconds_sum的每秒平均时间序列增长率,该值返回所花费的总秒数。使用rate()函数处理请求。可以使用内的表达式按方法和URI筛选值。下图说明了每个端点的rate()函数的配置。
这是图表。
总结
在SpringBoot的1.5和2.0版本之间,度量生成的改进是显著的。现在将数据导出到流行的监控系统(如infloxdb或prometheus)比以前容易得多,不需要任何额外的开发。与HTTP流量相关的度量更加详细,并且由于标记指示HTTP请求的URI、类型和状态,它们可能很容易与特定端点关联。我认为,与以前版本的SpringBoot相比,SpringBoot执行器中的修改可能是将应用程序迁移到最新版本的主要动机之一。