1. Actuator 介绍


  • SpringBoot Actuator 提供 http(或 JMX)端点来实现对应用程序的监视和管理、收集运行状态等功能。
  • 引入 spring-boot-starter-actuator 可启用这些功能。

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-actuator</artifactId>
    4. </dependency>
  • 默认情况下,通过访问 /actuator 可以看到所有启动的端点,也可以通过配置修改这个路径地址。

    management.endpoints.web.base-path=/manage
    

2. 端点配置


  • 文档:https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/htmlsingle/#production-ready-endpoints
  • SpringBoot 包含许多内置端点,允许添加自己的端点,可以配置端点是否对外开放或关闭。

    • 设置默认关闭所有端点(默认开启了 health 和 info)

      management.endpoints.enabled-by-default=false
      
    • 启动指定的端点

      management.endpoint.<name>.enabled=true
      
      • <name> 使用对应的端点名称代替。
    • 数据缓存

      • 端点自动缓存对不带任何参数的读取操作的响应。要配置端点缓存响应的时间量:

        management.endpoint.<name>.cache.time-to-live=10s
        
      • <name> 使用对应的端点名称代替。

        3. HTTP 端点配置


  • http 配置

    • 通过 http 公开除了 env 和 beans 端点之外的所有内容
      management.endpoints.web.exposure.include="*"
      management.endpoints.web.exposure.exclude=env,beans
      
  • CORS 跨域支持(默认情况下禁用 CORS 支持)

    management.endpoints.cors.allowed-origins=http://example.com
    management.endpoints.cors.allowed-methods=GET,POST
    
  • 修改 ManagerServer 服务器配置

    management.server.port=8081  #如果设置为-1代表禁用http端点
    management.server.address=127.0.0.1
    
    • 可以配置和 web 服务使用不同的端口,同时绑定指定 IP。(不同端口,代表启动多个 tomcat 容器。)

      4. 端点讲解 - Health 健康检查


  • 访问 /actuator/health 查看程序中组件检查项的运行情况信息,在出现故障时能及时发现。
  • SpringBoot 默认提供了对 Redis、RabbitMQ、DataSource、MongoDB 等组件的检查项。
  • 展示更详细内容(默认 never)

    management.endpoint.health.show-details=never(或者 when-authorized|always)
    
  • 返回结果

    • 如果有检查项处于非检查状态,http 状态码为 503,返回值为 DOWN 或者 OUT_OF_SERVICE。
    • 如果没有检查出问题,返回 http 状态码为 200,返回值 UP 或者 UNKNOWN
  • 自定义检查项

    • 实现 HealthIndicator 接口,通过 spring 实例化一个对象,SpringBoot 会自动触发健康检查,并归入 health 的结果。

      @Component
      public class MyHealthCheck1 implements HealthIndicator {
      public Health health() {
         int i = new Random().nextInt();
         if (i % 2 == 0) {
             return Health.up().withDetail("细节", "1").build();
         } else {
             return Health.down().withDetail("细节", "2").build();
         }
      }
      }
      
    • 或者继承 AbstractHealthIndicator 类,实现 doHealthCheck() 方法

      @Component
      public class MyHealthCheck2 extends AbstractHealthIndicator {
      @Override
      protected void doHealthCheck(Health.Builder builder) throws Exception {
         int i = new Random().nextInt();
         if (i % 2 == 0) {
             builder.withDetail("细节", "1").up();
         } else {
             builder.withDetail("细节", "2").down();
         }
      }
      }
      

5. 端点讲解 - 日志配置


  • SpringBoot 日志配置

    logging.level.root=WARN
    logging.level.org.springframework.web=DEBUG
    logging.level.org.hibernate=ERROR
    
  • 通过 /actuator/loggers 查看日志配置

  • 运行时修改配置
    curl -XPOST -H 'Content-Type: application/json' -i 'http://127.0.0.1:8081/manage/loggers/ROOT' --data '{
      "configuredLevel": "DEBUG"
    }'
    

6. 端点讲解 - metrics


https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/htmlsingle/#production-ready-metrics

  • metrics 是生产应用中很重要的功能,简单可理解为对运行时具体功能的监控。SpringBoot 中集成了 micrometer 实现。
  • 支持查看哪些数据?
    • 通过 /actuator/metrics 查看所有支持的信息,/metrics/requiredMetircName 查看指定某一项指标。
    • JVM 内存、线程、GC 信息、类加载情况、CPU 指标、Http 请求统计、Tomcat 信息…..。
  • 与监控系统的集成
    • 支持将数据导出到:AppOptics、Atlas、Datadog、Dynatrace、Elastic、Ganglia、Graphite、Humio、Influx、JMX、KairosDB、New Relic、Prometheus、SignalFx、Simple(in-memory)、Stackdriver、StatsD、Wavefront。
  • 自定义监控指标

    • 代码中注入 MeterRegistry 对象,然后进行手动注册。

      @Component
      public class MyMetrics {
      private final List<String> words = new CopyOnWriteArrayList<String>();
      
      public MyMetrics(MeterRegistry meterRegistry) {
         meterRegistry.gaugeCollectionSize("dictionary.size", Tags.empty(), this.words);
      }
      }
      

7. 自定义端点


  • 可以理解为“概念上类似 SpringMVC 的 controller 写法,却又是完全不同的一套 API。”。
  • 端点定义:@Endpoint @WebEndpoint 或 @JmxEndpoint。
  • 端点操作:@ReadOperation、@WriteOperation、@DeleteOperation。
  • 参数接收:web 环境下添加 @Selector。
@Endpoint(id = "myEndPoint")
@Component
public class MyEndpoint {

    String name = "default";

    @ReadOperation
    public String getName() {
        return "{\"name\":\"" + name + "\"}";
    }

    @DeleteOperation
    public void delName() {
        name = "";
    }

    @WriteOperation
    public void setName(@Selector String arg0) {
        this.name = arg0;
    }

}
curl -XGET http://localhost:8090/actuator/myEndPoint
curl -XPOST http://localhost:8090/actuator/myEndPoint/12345677889
curl -XDELETE http://localhost:8090/actuator/myEndPoint

8. 快速理解 JMX 机制


  • Java Management Extensions(JMX)提供了一种监视和管理应用程序的标准机制。
  • tomcat、kafka、druid 都是用的 JMX 技术来实现对外暴露管理接口和监控信息。
  • Jconsole 工具如何通过 JMX 技术实现对应用的监控和管理?
  • 通过 Spring 框架快速增加自定义 MBean。
    • 默认情况下,SpringBoot 将管理端点公开为 org.springframework.boot 域下的 JMX MBean。
  • 通过 JMX 公开所有端点并仅显示 health 和 info 端点。
    management.endpoints.jmx.exposure.exclude=*
    management.endpoints.jmx.exposure.include=info,health
    
public interface JmxMBean {
    public String getName();
    public void setName(String name);
    public String printHello();
    public String printHello(String whoName);
}
@ManagedResource
public class JmxTest implements JmxMBean {
    private String name;

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    public String printHello() { return "JmxTest " + name; }

    public String printHello(String whoName) { return "JmxTest " + whoName; }
}
// 注册定义自己的 MBean
public class TestJMXRegListener implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    JmxTest jmxTest;

    public void onApplicationEvent(ContextRefreshedEvent event) {
        try {
            // create mbean server
            MBeanServer server = ManagementFactory.getPlatformMBeanServer();
            // create object name
            ObjectName objectName = null;
            objectName = new ObjectName("jmxBean:name=testJMX");
            // 注册
            server.registerMBean(jmxTest, objectName);
            /**
             * JMXConnectorServer server
             * 这句话非常重要,不能缺少!注册一个端口,绑定 url 后,客户端就可以使用 rmi 通过 url 方式来连接 JMXConnectorServer
             */
            Registry registry = LocateRegistry.createRegistry(1099);

            // 构造 JMXServiceURL
            JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
            // 构建 JMXConnectorServer
            JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, null, server);
            // 启动
            cs.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}