本文会来看一下Spring Boot Actuator提供给咱们的监控端点Endpoint、健康检查Health和打点指标Metrics等所谓的Production-ready(生产环境必要的一些)功能。java
咱们先来新建一个模块:git
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.josephzhu</groupId>
<artifactId>spring101-ops</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring101-ops</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>me.josephzhu</groupId>
<artifactId>spring101</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
复制代码
引入了必要的actuator和web启动器,此外,还引入了data-redis启动器用于测试一些功能。 而后建立主程序:github
package me.josephzhu.spring101ops;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@Configuration
public class Spring101OpsApplication {
public static void main(String[] args) {
SpringApplication.run(Spring101OpsApplication.class, args);
}
@Bean
RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}
}
复制代码
建立一个测试Controller:web
package me.josephzhu.spring101ops;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@RestController
@RequestMapping("api")
public class MyController {
@Autowired
StringRedisTemplate stringRedisTemplate;
@GetMapping("items")
public List<MyItem> items(@RequestParam(value = "count",defaultValue = "10") int count){
stringRedisTemplate.opsForValue().set("testKey", "value" + count);
return IntStream.rangeClosed(1,count).mapToObj(i->new MyItem("name" + i,i)).collect(Collectors.toList());
}
}
复制代码
这里有用到一个MyItem:redis
package me.josephzhu.spring101ops;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class MyItem {
private String name;
private Integer price;
}
复制代码
最后配置一下application.properties:spring
management.server.port=8081
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
复制代码
这里作了几个配置:数据库
启动程序访问以下地址http://localhost:8081/actuator,能够看到页面列出了支持功能的连接,经常使用的有:apache
还有一些其它的自带的端点,这里就不说了,好比用于数据迁移的flyway,用于给prometheus拉取metrics数据的端点,端点还能够自定义。 别小看这些功能,这些功能使得咱们线上对应用程序进行运维能够很方便:后端
先来访问/actuator/health重点看一下健康检查: api
package me.josephzhu.spring101ops;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@Component
public class MyServiceHealthIndicator implements HealthIndicator {
@Autowired
private RestTemplate restTemplate;
@Override
public Health health() {
try {
ResponseEntity<List<MyItem>> responseEntity =
restTemplate.exchange("http://localhost:8080/api/items",
HttpMethod.GET, null, new ParameterizedTypeReference<List<MyItem>>() {});
if (responseEntity.getStatusCode().is2xxSuccessful())
return Health.up().build();
else
return Health.down().status(responseEntity.getStatusCode().toString()).build();
} catch (Exception ex) {
return Health.down(ex).build();
}
}
}
复制代码
实现很简单,实现HealthIndicator接口便可,咱们的类是XXHealthIndicator,那么自动就会加入一个叫XX的项。在这里,咱们访问了远程的一个服务,当服务出现非2XX的响应或调用服务出现异常的时候,咱们认为这个服务的健康是DOWN的,不然就是UP状态。在down的时候咱们能够传入状态、异常等补充信息,好比这是一个DOWN的状况:
在本节中,咱们来看一下如何进行简单配置实现暴露以下应用信息的功能:
info.app.name=Test SpringBoot Actuator
info.app.description=Test how to configure Health/Info/Metrics etc. with Spring Boot Actuator
info.app.version=1.0.1
info.app.author=JosephZhu
复制代码
截图中第二项能够看到git这个JSON暴露了程序git相关的信息,实现方式是加入一个插件到pom中:
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.1.15</version>
</plugin>
复制代码
此外,若是须要查看git详细信息的话须要加入以下配置到配置文件:
management.info.git.mode=full
复制代码
截图中第三项能够看到build这个JSON暴露了程序构建一些信息,这个经过Spring Boot的maven插件就能够实现,加入build-info这个Goal来生成:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
复制代码
咱们使用maven运行一下这两个插件,能够看到编译后多了build-info.properties和git.properties,这也就是Actuator获取信息的来源:
package me.josephzhu.spring101ops;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
@Component
public class MyInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("key","value").build();
}
}
复制代码
对外暴露一些程序内部的重要信息每每也是很重要排查线上问题的手段。Info适合展现不太会变更的一些复杂信息,若是但愿整个历史状态信息都能保留和监控的话更适合采用下面的打点方式。
访问/actuator/metrics能够看到下面的信息:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-influx</artifactId>
</dependency>
复制代码
固然,须要先在本机安装一下influxdb,MacOS也就是一行命令,brew install influxdb便可。 第二步,加入配置:
management.metrics.web.server.auto-time-requests=true
management.metrics.export.influx.enabled=true
management.metrics.export.influx.auto-create-db=true
management.metrics.export.influx.db=myapp
management.metrics.export.influx.step=10s
复制代码
逐一说明一下这些配置:
咱们能够启动程序,多访问几回http://localhost:8080/api/items,而后打开http://localhost:8081/actuator/metrics/http.server.requests查看,能够看到具体请求的执行次数和执行时间(证实1):
2018-10-08 20:49:41.429 INFO 16390 --- [pool-1-thread-1] i.micrometer.influx.InfluxMeterRegistry : successfully sent 73 metrics to influx
2018-10-08 20:49:51.483 INFO 16390 --- [pool-1-thread-1] i.micrometer.influx.InfluxMeterRegistry : successfully sent 73 metrics to influx
复制代码
有73个监控指标每隔10秒发送到一次influxdb,咱们能够进入influx客户端,查看这个measurement的信息(先输入命令use myapp):
咱们再来看一下如何自定义Metrics项实现本身的打点,修改一下咱们的Controller:
@Autowired
MeterRegistry meterRegistry;
@GetMapping("items")
public List<MyItem> items(@RequestParam(value = "count",defaultValue = "10") int count){
stringRedisTemplate.opsForValue().set("testKey", "value" + count);
meterRegistry.timer("mytimer").record(()-> {
try {
Thread.sleep(count);
} catch (InterruptedException e) {
}
});
meterRegistry.counter("mycounter").increment(count);
meterRegistry.gauge("currentValue1", count);
return IntStream.rangeClosed(1,count).mapToObj(i->new MyItem("name" + i,i)).collect(Collectors.toList());
}
复制代码
在这里,咱们注入了MeterRegistry类,而后经过这个类咱们能够方便进行各类信息的上报。在MicroMeter中,信息抽象为了这么几种:
package me.josephzhu.spring101ops;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Status;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import static java.util.Collections.emptyList;
@Configuration
class HealthMetricsConfiguration {
private CompositeHealthIndicator compositeHealthIndicator;
public HealthMetricsConfiguration(HealthAggregator healthAggregator, List<HealthIndicator> healthIndicators, MeterRegistry registry) {
compositeHealthIndicator = new CompositeHealthIndicator(healthAggregator);
for (Integer i = 0; i < healthIndicators.size(); i++) {
compositeHealthIndicator.addHealthIndicator(i.toString(), healthIndicators.get(i));
}
registry.gauge("health", emptyList(), compositeHealthIndicator, health -> {
Status status = health.health().getStatus();
switch (status.getCode()) {
case "UP":
return 3;
case "OUT_OF_SERVICE":
return 2;
case "DOWN":
return 1;
case "UNKNOWN":
default:
return 0;
}
});
}
}
复制代码
重启应用后稍等一下,看一下InfluxDb中的数据,的确是一些值为3的记录,表明UP:
本文咱们经过一些例子覆盖了以下内容:
的确,每个功能都是简单的几步配置,Spring Boot Actuator真的很方便,这些功能是一个真正的可用于生产环境的程序必不可少的一些功能,Spring Boot不只仅为咱们提供了方便,并且为咱们定义了架构模板,让每个开发人员都能有意识,应该作一些什么,这也就是我为何一直说Spring引领了企业级单机开发,Spring Boot引领了互联网微服务开发。
可是,Spring Boot由于在高速发展,会不断吸取好的开源项目整合到生态中去,因此在API上变化会较多,API一直在修改,增长了很多学习成本和坑。任何事情都有两面性,咱们在要求Spring生态为咱们提供愈来愈多功能的时候,享受到便利的同时,也必须去适应Spring的快速变化。
老样子,本系列文章代码见个人github:github.com/JosephZhu19…