精选. PNG
Spring Boot Actuator 是 Spring Boot 2 发布后最改进的项目之一. 它已经通过了主要的改进, 旨在简化定制, 包括一些新的功能, 例如对其他 web 技术的支持, 例如新的反应式模块 --SpringWebFlux. 它还增加了对将度量导出到 influxdb 的开箱即用支持, influxdb 是一个开源时间序列数据库, 设计用于处理大量时间戳数据. 与使用 SpringBoot1.5 的版本相比, 这确实是一个很大的简化. 您可以通过阅读我以前的文章中的一篇使用 grafana 和 influxdb 定制度量可视化来了解自己的价值. 我在这里描述了如何使用 @exportmetricswriter bean 将 Spring 引导执行器生成的度量导出到 influxdb. 示例 Spring 引导应用程序可用于分支主服务器中关于 GitHub 存储库示例 Spring Graphite()的文章. 在当前的文章中, 我创建了 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.
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- <dependency>
- <groupId>io.micrometer</groupId>
- <artifactId>micrometer-registry-influx</artifactId>
- </dependency>
唯一要做的就是重写 influxdb 的默认地址, 因为我们正在 VM 上运行 influxdb docker 容器. 默认情况下, Spring 引导数据尝试连接名为 mydb 的数据库. 但是, 我已经创建了数据库 SpringBoot, 所以我也应该覆盖这个默认值. 在 SpringBoot 的版本 2 中, 所有与 Spring Boot Actuator endpoints 相关的配置属性都已移到 Management.* 部分.
图片. PNG
在启动 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 控制器启用度量. 您还可以在控制器内注释单个方法, 以仅为特定端点生成度量.
图片. PNG
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 属性设置为更新, 所有必需的表都将在应用程序启动时创建.
图片. PNG
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 分钟内收集的测量值列表.
图片. PNG
如您所见, 所有由 Spring 引导执行器生成的度量都用以下信息标记: 方法, URI, 状态和异常. 由于有了这些标签, 我们可以很容易地对每个签名端点的度量进行分组, 包括失败和成功百分比. 让我们看看如何在 grafana 中配置和查看它.
5. 使用 Gravana 实现度量可视化
一旦我们成功地将度量导出到 influxdb, 现在是时候使用 grafana 可视化它们了. 首先, 让我们用 grafana 运行 docker container.
$ docker run -d --name grafana -p 3000:3000 grafana/grafana
Grafana 为创建流入查询提供了用户友好的界面. 我们定义了一个图形, 它可视化每个调用端点的请求处理时间和应用程序接收的请求总数. 如果我们按方法类型和 URI 过滤存储在表 http_server_请求中的统计信息, 我们将收集每个端点生成的所有度量.
图片. PNG
应为其他端点创建类似的定义. 我们将在一个图表上对它们进行说明.
图片. PNG
这是最后的结果.
图片. PNG
下面是可视化发送到应用程序的请求总数的图表.
图片. PNG
6. 运行 Prometheus
在本地运行 Prometheus 最合适的方法显然是通过码头集装箱. API 暴露在端口 9090 下. 我们还应该传递初始配置文件和 Docker 网络的名称. 为什么? 您将在本步骤描述的下一部分中找到所有答案.
docker run -d --name prometheus -p 9090:9090 -v /tmp/prometheus.YAML:/etc/prometheus/prometheus.YAML --network springboot prom/prometheus
与 influxdb 不同, prometheus 从应用程序中提取度量. 因此, 我们需要启用为普罗米修斯公开度量的执行器端点, 这在默认情况下是禁用的. 要启用它, 请将 property management.endpoint.prometheus.enabled 设置为 true, 如下面的配置片段所示.
图片. PNG
然后我们应该在 prometheus 配置文件中设置应用程序公开的执行器端点的地址. scrape_配置部分负责指定一组目标和描述如何与它们连接的参数. 默认情况下, prometheus 尝试每分钟从定义的目标端点收集一次数据.
图片. PNG
与集成 influxdb 类似, 我们需要将以下工件包含到项目的依赖项中.
- <dependency>
- <groupId>io.micrometer</groupId>
- <artifactId>micrometer-registry-prometheus</artifactId>
- </dependency>
在我的例子中, 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 集成, 以利用该工具提供的更好的可视化效果. 首先, 您应该创建普罗米修斯数据源.
图片. PNG
然后, 我们应该定义从 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()函数的配置.
图片. PNG
这是图表.
图片. PNG
总结
在 SpringBoot 的 1.5 和 2.0 版本之间, 度量生成的改进是显著的. 现在将数据导出到流行的监控系统 (如 infloxdb 或 prometheus) 比以前容易得多, 不需要任何额外的开发. 与 HTTP 流量相关的度量更加详细, 并且由于标记指示 HTTP 请求的 URI, 类型和状态, 它们可能很容易与特定端点关联. 我认为, 与以前版本的 SpringBoot 相比, SpringBoot 执行器中的修改可能是将应用程序迁移到最新版本的主要动机之一.
来源: http://www.jianshu.com/p/abd44103f445