springboot04_springboot特性之Actuator


4.1.8.springboot特性之Actuator【上】

時長:23min

4.3.Actuator是干啥的?

  它也是以starter組件方式,進行引入的。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

當添加這個組件之后,再去啟動當前應用,就會看到當前項目的健康狀態,一些相關信息。

是通過Endpoints窗口進行信息展示,如下所示:

 

 4.3.1.通過官方文檔分析actuator有哪些endpoints端點

https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-endpoints

 

 可以看到,springboot-actuator中提供了很多的端點,如:health,beans,mappings,...

http://localhost:8080/actuator/info,本地啟動后,訪問端點,默認情況,只放開info,health,其它訪問

會提示錯誤。

  我們可以通過配置,訪問更多端點,配置如下:

management.endpoints.web.exposure.include=*

 

再次運行項目,就可以訪問更多端點了。如:env,beans,...

http://localhost:8080/actuator/env

4.3.1.1.查看health端點詳情

http://localhost:8080/actuator/health

  設置多端點可訪問之后,啟動springboot項目,查看到的結果是:

 

 只能看到status值。如果想要看到更詳細的信息,應該怎么辦呢?

配置如下的屬性:

 

該配置,默認值為never,現在修改為always.然后重啟項目,訪問health,結果如下:

 

 這時,展示的健康狀態,不僅包含應用本身的狀態,還包含全局配置中其它連接,如:redis連接的狀態。

注意:

  我們如果自己定義一個redis連接組件,然后進行配置是不會監控它的狀態的。它只監控spring默認支持配置

的健康狀態。

  下面來看下redis監控代碼實現:

 

 通過繼承AbstractReactiveHealthIndicator抽象類,並對連接進行監控,up表示連接成功,down表示連接失敗。

4.3.1.2.查看metrics端點詳情

http://localhost:8080/actuator/metrics

監控對象:

  》jvm【垃圾收集器、內存、堆】

  》系統層面【運行時間,平均負載。。】

  》線程池的狀態

  》容器【如tomcat】狀態

1.具體key的詳細信息查看

  以"process.start.time"為例。只需要訪問:

http://localhost:8080/actuator/metrics/process.start.time

結果如下所示:

 

4.1.9.springboot特性之Actuator【下】

時長:1h6min

metrics,主要是系統運行的狀態值進行監控。

  》pheuthous/grafana【圖標展示】

4.3.1.3.loggers監控

  http://localhost:8080/actuator/loggers

  主要用來展示不同包路徑設置的日志級別,它的作用有:

如果在線上想去排查問題,要查看日志的詳細信息,提供一種方式可以修改,可以

對特定節點的日志級別進行修改。

  比如說,要修改ROOT節點的日志級別。默認級別是info,現在准備修改為debug.

1.日志級別修改

修改方法如下:

使用postman發起一個POST請求:http://localhost:8080/actuator/loggers/ROOT,並在

body中傳參json數據:{"configuredLevel": "DEBUG"},如下所示:

 

然后,查看日志級別,已經修改為DEBUB,如下所示:

再看項目后台輸出日志級別,也變成為DEBUG,如下所示:

 

 

 同理,也可以改回INFO級別。

4.3.1.4.查看項目的一些info信息

  需要進行配置,如:info.app.name = @project.name@

  然后,重啟項目。訪問info,即http://localhost:8080/actuator/info,如下所示:

 

 

 4.3.2自已開發endpoint端點

4.3.2.1.注解方式定義一個Indicator

代碼如下所示:

package com.wf.demo.springbootdemo.endpoint;

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName CustomerMetricsIndicator
 * @Description 自定義,用戶狀態監控器
 * @Author wf
 * @Date 2020/7/9 10:23
 * @Version 1.0
 */
@Endpoint(id = "customer")
public class CustomerMetricsIndicator {
    @ReadOperation
    public Map<String,Object> time(){
        Map<String,Object> map = new HashMap<String, Object>();
        Date time = new Date();
        map.put("當前時間",time);
        return map;
    }
}

 

4.3.2.2.定義endpoint配置類注入bean
package com.wf.demo.springbootdemo.endpoint;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName EndpointConfiguration
 * @Description 注入endpoint bean的配置類
 * @Author wf
 * @Date 2020/7/9 10:30
 * @Version 1.0
 */
@Configuration
public class EndpointConfiguration {
    @Bean
    public CustomerMetricsIndicator customerMetricsIndicator(){
        return new CustomerMetricsIndicator();
    }
}

 

然后,重啟項目, 訪問端點:http://localhost:8080/actuator/customer,結果如下:

 

 

 說明: 

  自定義endpoint就成功完成了。

 4.4.actuator的兩種監控狀態

分別是:

》http【web】

》jmx

4.4.1.JMX

所謂JMX,是Java Management Extensions(Java管理擴展)的縮寫,是一個為應用程序植入管理功能的框架。

用戶可以在任何Java應用程序中使用這些代理和服務實現管理。

  使用jmx可以做一些監控。

4.4.1.1.springboot項目jmx監控使用
1.需要配置jmx使能
management.endpoints.jmx.exposure.include=*
spring.jmx.enabled=true

 

然后重啟項目,使用jdk提供jconsole工具連接jmx監控端點。

2.jconsole連接
》jconsle打開

 window下在命令搜索框【win+R打開】中,輸入jconsole,按下enter,打開圖形界面,如下所示:

 

 

 

 》連接某個java進程

  選擇本地啟動項目,所在java進程,然后點擊,連接,如下所示:

 

如果出現如下所示,連接報錯。點擊不安全連接,即可。

 

 連接成功后,進入如下界面:

 

3.查看endpoint信息 

在MBean下可以查看到,相關的endpoint信息,如下所示:

 

 這些監控信息有什么用呢?應該如何應用它?

  我們在做監控系統時,會涉及到當前應用的服務信息上報,總不能從監控平台手動去抓取吧!

  因為監控平台要做這樣一些信息抓取功能,在設計上是很困難的。比如,要抓取哪些信息,是否有用,

還要做數據清洗等,很麻煩。

  一般來說,監控信息更多的是上報,在程序中加埋點,加監控的api,通過report去上報。java里面要把這

些信息上報的話,就可以使用jmx這樣來做。

 

 4.4.1.2.通過示例代碼來說明jmx的作用
1.開發一個接口
package com.wf.demo.springbootdemo;

/**
 * @ClassName SystemInfoMBean
 * @Description 系統信息接口
 * @Author wf
 * @Date 2020/7/9 11:07
 * @Version 1.0
 */
public interface SystemInfoMBean {
    //獲得當前cpu核心數
    int getCpuCore();
    //內存是多大
    long getTotalMemory();

    //關閉
    void shutdown();
}

 

說明:

  定義一個接口,暴露一些要監控的信息,接口命名格式必須固定,如:*MBean【后綴固定】

2.定義接口實現類
package com.wf.demo.springbootdemo;

/**
 * @ClassName SystemInfo
 * @Description 實現類,命名和接口嚴格相關
 * @Author wf
 * @Date 2020/7/9 11:12
 * @Version 1.0
 */
public class SystemInfo implements SystemInfoMBean {
    @Override
    public int getCpuCore() {
        return Runtime.getRuntime().availableProcessors();
    }

    @Override
    public long getTotalMemory() {
        return Runtime.getRuntime().totalMemory();
    }

    @Override
    public void shutdown() {
        System.exit(0);
    }
}

 

注意:

  實現類命名,必須遵照規范。即接口名去掉MBean后綴。

3.發布信息
package com.wf.demo.springbootdemo;

import javax.management.*;
import java.io.IOException;
import java.lang.management.ManagementFactory;

/**
 * @ClassName JMXMain
 * @Description 發布信息
 * @Author wf
 * @Date 2020/7/9 11:32
 * @Version 1.0
 */
public class JMXMain {
    public static void main(String[] args) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException, IOException {
        MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
        ObjectName objectName = new ObjectName("com.wf.demo.springbootdemo:type=SystemInfo");
        //把信息發布出去
        SystemInfo systemInfo = new SystemInfo();
        mBeanServer.registerMBean(systemInfo,objectName);

        //避免main方法結束,阻塞在這里
        System.in.read();
    }
}

 

然后,運行這個main程序。然后重新打開jconsole查看,是否有監控到自定義內容。

 

 

 

 可以看到,jmx監控就完成了。

  在這個監控信息中,有屬性和操作兩個類別,它是如何歸屬的呢?

  它和接口定義的方法有關系,如:是getXX方法,就歸類為屬性,否則歸類為操作。

 

思考:

  現在,我們是通過main方法進行發布監控信息的。那么,springboot是如何做到這個發布功能的呢?

  在前面我們定義的Indicator類,使用了@Endpoint注解,springboot通過掃描這個注解,並自動通過

web和jmx兩種形式的發布。

  

  下面舉例說明,springboot是如何發布信息的。

 

在springApplication中有屬性和操作兩種分類,它們分別是怎么注冊的?

  如果是jmx發布,必然是有一個MBeanServer去完成一個發布。通過搜索springboot的代碼,有

SpringApplicationAdminMXBean接口,定義bean信息。如下所示:

 

 

 根據JMX的規范,上面的接口必然有一相關的實現類SpringApplicationAdmin,但是,這里是一個內部類

如下所示:

 

 是在SpringApplicationAdminMXBeanRegistrar中定義的內部類,這個類是提供注冊功能的類。

 

它的注入,是通過配置類自動裝配的,配置類為SpringApplicationAdminJmxAutoConfiguration

 

 

 4.4.1.3.SpringApplicationAdminMXBeanRegistrar如何實現jmx發布功能原理分析

  該bean實現多個接口功能,如下所示:

public class SpringApplicationAdminMXBeanRegistrar implements ApplicationContextAware, GenericApplicationListener, EnvironmentAware, InitializingBean, DisposableBean {
    private static final Log logger = LogFactory.getLog(SpringApplicationAdminMXBeanRegistrar.SpringApplicationAdmin.class);
    private ConfigurableApplicationContext applicationContext;
    private Environment environment = new StandardEnvironment();
    private final ObjectName objectName;
    private boolean ready = false;
    private boolean embeddedWebApplication = false;

 

1.ApplicationContextAware接口

  獲得讀取上下文能力。在Spring容器中一個bean如果實現了該方法則就可以獲取上下文對象。

 

public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext var1) throws BeansException;
}

 

說明:

  該接口繼承自Aware,定義setApplicationContext,通過set方法,實現bean注入springIOC容器

  實現類中處理,就是一個set注入,如下:

 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Assert.state(applicationContext instanceof ConfigurableApplicationContext, "ApplicationContext does not implement ConfigurableApplicationContext");
        this.applicationContext = (ConfigurableApplicationContext)applicationContext;  //set注入
    }

 

2. 實現GenericApplicationListener接口

  獲取處理事件的能力,同樣在Spring中只要實現該接口,就獲取了事件監聽的能力,

不過具體監聽什么事件要自己去判斷。大家可以根據例子來理解。接口定義 如下:

public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
    boolean supportsEventType(ResolvableType var1);

    default boolean supportsSourceType(@Nullable Class<?> sourceType) {
        return true;
    }

    default int getOrder() {
        return 2147483647;
    }
}
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E var1);
}
 

 

下面看下子類實現:

public boolean supportsEventType(ResolvableType eventType) {
        Class<?> type = eventType.getRawClass();
        if (type == null) {
            return false;
        } else {  //根據事件泛型類型,判斷是否進行事件處理,ApplicationReadyEvent或WebServerInitializedEvent類型就處理 return ApplicationReadyEvent.class.isAssignableFrom(type) || WebServerInitializedEvent.class.isAssignableFrom(type);
        }
    }

    public boolean supportsSourceType(Class<?> sourceType) {
        return true;
    }

    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationReadyEvent) {
            this.onApplicationReadyEvent((ApplicationReadyEvent)event);
        }

        if (event instanceof WebServerInitializedEvent) {
            this.onWebServerInitializedEvent((WebServerInitializedEvent)event);
        }

    }

    public int getOrder() {
        return -2147483648;
    }
  //spring已經准備好了,設置ready=true void onApplicationReadyEvent(ApplicationReadyEvent event) {
        if (this.applicationContext.equals(event.getApplicationContext())) {
            this.ready = true;
        }

    }
  //web應用,這里處理 void onWebServerInitializedEvent(WebServerInitializedEvent event) {
        if (this.applicationContext.equals(event.getApplicationContext())) {
            this.embeddedWebApplication = true;
        }

    }

 

 

3. 實現EnvironmentAware接口

  獲取應用配置環境信息, 和上面一樣實現了Aware結尾的接口,都能獲取對應的Spring內容的對象實例,

然后我們就可以根據該實例,來進行功能擴展。接口定義如下:

public interface EnvironmentAware extends Aware {
    void setEnvironment(Environment var1);
}

  實現類中處理邏輯:

public void setEnvironment(Environment environment) {
        this.environment = environment;  //set注入
    }
4. 實現InitializingBean接口

  這里就要着重看了,在初始化時候將MBean注冊到JMX上。

當然我們可以通過 @PostConstruct注解來聲明初始化方法。接口定義如下:

package org.springframework.beans.factory;

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

  子類實現邏輯:

public void afterPropertiesSet() throws Exception {
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();  //用來發布JMX,SpringApplicationAdmin是要發布接口實現類
        server.registerMBean(new SpringApplicationAdminMXBeanRegistrar.SpringApplicationAdmin(), this.objectName);
        if (logger.isDebugEnabled()) {
            logger.debug("Application Admin MBean registered with name '" + this.objectName + "'");
        }

    }

 

注意:

  this.objectName是如何設置的?

  private final ObjectName objectName;  //通過構造器傳參,是從哪里從過來的呢? private boolean ready = false;
    private boolean embeddedWebApplication = false;

    public SpringApplicationAdminMXBeanRegistrar(String name) throws MalformedObjectNameException {
        this.objectName = new ObjectName(name);
    }

 

 構造器是在配置類中自動裝配時,設置的,如下所示:

public class SpringApplicationAdminJmxAutoConfiguration {
    private static final String JMX_NAME_PROPERTY = "spring.application.admin.jmx-name";
    private static final String DEFAULT_JMX_NAME = "org.springframework.boot:type=Admin,name=SpringApplication";//固定格式 public SpringApplicationAdminJmxAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
    public SpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar(ObjectProvider<MBeanExporter> mbeanExporters, Environment environment) throws MalformedObjectNameException {
        String jmxName = environment.getProperty("spring.application.admin.jmx-name", "org.springframework.boot:type=Admin,name=SpringApplication");
        if (mbeanExporters != null) {
            Iterator var4 = mbeanExporters.iterator();

            while(var4.hasNext()) {
                MBeanExporter mbeanExporter = (MBeanExporter)var4.next();
                mbeanExporter.addExcludedBean(jmxName);
            }
        }

        return new SpringApplicationAdminMXBeanRegistrar(jmxName);  //這里設置jmx監控的包路徑及類名
    }
}

 

 

5. 實現DisposableBean接口

  應用銷毀時候,取消注冊。同樣我們也可以用@PreDestroy注解來實現。

  public void destroy() throws Exception {
        ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.objectName);//取消注冊
    }

 

 

  如果我們自己想要去注入這樣一個注冊bean,可以使用@Component進行注入。

 4.5.大盤展示系統應用監控信息

4.5.1.springboot監控信息可發布到prometheus + grafana

4.5.1.1.安裝prometheus 組件

  它是一個開源監控系統。它有幾個核心模塊組成:

》數據爬蟲,可以根據配置實現定期抓取數據,基於http抓取一些metrics數據,即進行數據采集

》時序數據庫存儲,存儲metrics數據

》可視化,但它的可視化並不好用,所以,才結合grafana組件來可視化展示。

 

1.如何安裝

  去github上搜索,下載安裝包,選擇prometheus-2.19.2.linux-amd64.tar.gz版本進行下載。

https://github.com/prometheus/prometheus/releases/tag/v2.19.2

 

 

  如果是使用xshell連接服務器,使用wget進行下載,可復制出安裝包路徑。

https://github.com/prometheus/prometheus/releases/download/v2.19.2/prometheus-2.19.2.linux-amd64.tar.gz

[root@localhost ~]# wget https://github.com/prometheus/prometheus/releases/download/v2.19.2/prometheus-2.19.2.linux-amd64.tar.gz
-bash: wget: command not found  //沒有wget命令,先安裝
[root@localhost ~]# yum install -y wget

 

由於是從github地址進行下載,雖然只有61M大小,速度還是比較慢。

wget -c https://github.com/prometheus/prometheus/releases/download/v2.19.2/prometheus-2.19.2.linux-amd64.tar.gz  //支持斷點續傳

 

  

2.springboot項目集成prometheus組件

pom.xml添加依賴包:

 <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>//版本由springboot管理

 

 然后,重啟springboot項目,訪問:http://localhost:8080/actuator/prometheus

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM