天天看點

SpringBoot Admin 應用監控

目錄

      • 概述
      • 監控普通的springboot應用
        • admin server
        • admin client
      • 監控微服務
        • eureka server
      • 說明

大型分布式系統都應該提供監控功能,監控系統各部分的運作狀态。

監控的好處

  • 便于檢視分布式系統各個節點的運作狀态,及時發現可能存在的隐患
  • 系統故障時便于排查
  • 可根據監控提供的qps、硬體使用情況等針對性地對系統進行優化

監控次元

  • cpu、記憶體、硬碟、帶寬等硬體的使用情況
  • db、redis、tomcat、kafka等元件的狀态、相關名額
  • 接口qps、響應時間的95線|99線等應用本身的名額

springboot提供的actuator可以監控應用,但需要通路actuator相關接口檢視監控資訊,直接使用很麻煩。springboot admin內建了actuator,可以将actuator擷取到的監控資訊可視化地展示出來,直覺、友善。

springboot admin是codecentric公司的開源項目,并非springboot官方元件,分為server、client兩部分,被監控的springboot應用作為admin client,admin server提供web界面,可檢視監控資訊。

大公司往往都有自己的監控元件,對于小公司而言,springboot admin可以作為應用監控的一個不錯選擇。

依賴

建立項目時勾選

  • Web -> Spring Web
  • Security -> Spring Security
  • I/O -> Java Mail Sender
  • Ops -> Codecentric’s Spring Boot Admin(Server)

也可以手動添加依賴

<!-- 因為包含web界面,需要web的依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 已經包含了spring-boot-starter-actuator -->
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>

<!-- 登入密碼 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 非必需 -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

<!-- 郵件通知 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
           

引導類

加@EnableAdminServer

yml

server:
  port: 7501

spring:
  application:
    name: springboot-admin-server
    
  #指定admin server的使用者名、密碼
  security:
    user:
      name: chy
      password: abcd

  #郵件伺服器配置
  mail:
    #郵件伺服器位址。qq是smtp.qq.com,163是smtp.163.com,阿裡雲是smtp.aliyun.com
    host: smtp.qq.com
    #賬号
    username: [email protected]
    #密碼(授權碼)
    password: xxxxxxxx

  #郵件通知配置
  boot:
    admin:
      notify:
        mail:
          #發件郵箱,與上面配置的郵箱伺服器賬号保持一緻
          from: [email protected]
          #收件郵箱,有多個時逗号分隔
          to: [email protected]
          #抄送
          cc: [email protected]
          #指定郵件模闆,預設為 classpath:/META-INF/spring-boot-admin-server/mail/status-changed.html 可輕按兩下shift搜尋此檔案,copy到resources下修改
#          template:
           

節點上線、下線都會自動發郵件通知收件人,開發環境下屏蔽收件人設定

配置類

config.SecuritySecureConfig

/**
 * 配置security的登入驗證
 */
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

    private final String contextPath;

    public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
        this.contextPath = adminServerProperties.getContextPath();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置跨域,admin client注冊到admin server的/instances下
        http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .ignoringAntMatchers(contextPath + "/instances");

        // 配置靜态資源
        http.authorizeRequests().antMatchers(contextPath + "/assets/**").permitAll();

        // 所有請求都必須通過認證
        http.authorizeRequests().anyRequest().authenticated();

        // 登入登出的頁面配置
        http.formLogin().loginPage("/login").permitAll();
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login");

        // 啟用basic認證
        http.httpBasic();
    }

    
}
           

  • Ops -> Codecentric’s Spring Boot Admin(Client)
<!-- 已經包含了spring-boot-starter-actuator -->
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>

<!-- web項目,以維持運作狀态 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
           

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    
    <property name="LOG_HOME" value="C:/Users/chy/Desktop/日志"/>

    <!-- 指定彩色日志的渲染規則 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>

    <!-- 指定彩色日志的格式,LN後面是行數 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:-}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(LN:%L  ){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!-- 控制台輸出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 引用日志格式 -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- 每日檔案輸出 -->
    <appender name="DAY_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志檔案名 -->
            <FileNamePattern>${LOG_HOME}/user-server-%d{yyyy-MM-dd}.log</FileNamePattern>
            <!-- 日志檔案保留天數 -->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 指定格式:%d表示日期,%thread表示線程名,%-5level:級别從左顯示5個字元寬度%msg:日志消息,%n是換行符 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <!-- 日志檔案最大體積 -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>500MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!-- 輸出到指定檔案中 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/user-server-all.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 指定格式:%d表示日期,%thread表示線程名,%-5level:級别從左顯示5個字元寬度%msg:日志消息,%n是換行符 -->
            <!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>-->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 預設輸出級别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="DAY_FILE"/>
        <appender-ref ref="FILE"/>
    </root>

    <!-- 給特殊的包指定輸出級别 -->
    <logger name="com.apache.ibatis" level="WARN" />
    <logger name="java.sql.Connection" level="WARN" />
    <logger name="java.sql.Statement" level="WARN" />
    <logger name="java.sql.PreparedStatement" level="WARN" />
    <logger name="java.sql.ResultSet" level="DEBUG" />
    <logger name="com.alibaba.druid.pool.DruidPooledResultSet" level="ERROR" />

    <logger name="org.apache.shiro" level="WARN" />
    <logger name="springfox.documentation" level="WARN" />

</configuration>
           

注意:admin server、tail -f都可以顯示彩色日志,但使用記事本之類的普通文本閱讀器打開看到的是亂碼。

server:
  port: 7502

spring:
  application:
    name: user-server

  boot:
    admin:
      client:
        #指定admin server的位址
        url: http://localhost:7501
        #如果admin server設定了密碼,admin client也要密碼才能注冊到admin server上
        username: chy
        password: abcd
        #以ip注冊到admin server上,預設false使用hostname注冊
        instance:
          prefer-ip: true


management:
  #暴露actuator的全部endpoint(即/actuator系列路徑),預設隻暴露少數endpoint
  endpoints:
    web:
      exposure:
        include: "*"
  #顯示節點健康的具體資訊,/actuator/health預設隻傳回節點狀态(up|down),不傳回節點的具體資訊
  endpoint:
    health:
      show-details: always


#指定日志檔案位置,要與logback中配置的日志檔案位置一緻,此處的檔案名不能使用%d{yyyy-MM-dd}之類的格式,識别不了
#會把此檔案中的日志傳輸到admin server,在admin server中也可以實時看到此應用的日志
logging:
  file:
    name: C:/Users/chy/Desktop/日志/user-server-all.log
           

admin server實時顯示日志需要滿足的條件

  • 如果沒有logback的配置檔案,直接在yml中logging.file.name指定日志輸出位置即可
  • 如果有logback的配置檔案,則yml中的logging.file.name必須和logback配置檔案中指定的日志檔案位置保持一緻

大體流程:所有服務(包括admin server)都作為eureka client注冊到eureka server上,并将狀态資訊傳給eureka server,admin server從eureka server拿各服務的狀态資訊。

就是一個普通的eureka server,不需要加額外的配置。

建立子產品時勾選 Spring Cloud Discovery -> Eureka Server ,也可以手動添加依賴

<!-- 已經包含了spring-boot-starter-actuator -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
           

加 @EnableEurekaServer

server:
  port: 7500

spring:
  application:
    name: eureka-server


eureka:
  instance:
    #所在機器的hostname或者ip
    hostname: 127.0.0.1
  client:
    #不注冊到其它eureka server上
    registerWithEureka: false
    #不從其它eureka server上拉取、同步注冊資訊
    fetchRegistry: false
  #此eureka server綁定的注冊中心位址
  serviceUrl:
    defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/


#日志檔案位置
logging:
  file:
    name: C:/Users/chy/Desktop/日志/eureka-server-all.log
           

建立子產品時勾選

  • Spring Cloud Discovery -> Eureka Discovery Client
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 非必需 -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

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

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
           

加 @EnableAdminServer、@EnableEurekaClient

server:
  port: 7501

spring:
  application:
    name: springboot-admin-server

  #指定admin server的使用者名、密碼
  security:
    user:
      name: chy
      password: abcd

  #郵件伺服器配置
  mail:
    #郵件伺服器位址。qq是smtp.qq.com,163是smtp.163.com,阿裡雲是smtp.aliyun.com
    host: smtp.qq.com
    #賬号
    username: [email protected]
    #密碼(授權碼)
    password: xxxxxxxxx

  boot:
    admin:
      #配置web路徑字首,值為網關路由中配置的admin-server子產品的路徑,預設路由為服務名。如果不通過網關通路,可不用配置
      ui:
        public-url: /admin-server
      #郵件通知配置
      notify:
        mail:
          #發件郵箱,與上面配置的郵箱伺服器賬号保持一緻
          from: [email protected]
          #收件郵箱,有多個時逗号分隔
          to: [email protected]
#         #抄送
          cc: [email protected]
          #郵件模闆
#          template:


management:
  #暴露actuator的全部endpoint
  endpoints:
    web:
      exposure:
        include: "*"
  #顯示節點健康的具體資訊
  endpoint:
    health:
      show-details: always


#日志檔案位置
logging:
  file:
    name: C:/Users/chy/Desktop/日志/springboot-admin-server-all.log


eureka:
  instance:
  	#預設就是/actuator/health,可預設
    #health-check-url-path: /actuator/health
    #發送心跳包的時間間隔,預設30,開發、測試環境可設定小些
    lease-renewal-interval-in-seconds: 10
    #中繼資料
    metadata-map:
      user.name: ${spring.security.user.name}
      user.password: ${spring.security.user.password}
  client:
    #ribbon更新節點清單的時間間隔,預設30,開發、測試環境可設定小些
    registry-fetch-interval-seconds: 10
    #注冊中心位址
    service-url:
      defaultZone: http://localhost:7500/eureka/
           
  • admin server是從注冊中心拿各服務節點的狀态資訊,可以監測各個eureka client(包括 admin server本身)的狀态。
  • 單機版eureka server是監測不到eureka server自身狀态的,eureka server叢集後,eureka server也會作為eureka client注冊到其它eureka server上,這時可以監測到eureka server的狀态。上面eureka server的yml中我沒有暴露eureka server自身的全部端點,需要的可以自己加上。
  • 關于日志,通常不太關心eureka server、admin server自身的日志,是以我隻輸出到一個日志檔案中,沒有逐天輸出,需要的可以自行加上logback-spring.xml。
/**
 * 配置security的登入驗證
 */
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

    private final String contextPath;

    public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
        this.contextPath = adminServerProperties.getContextPath();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置跨域,admin client注冊到admin server的/instances下
        http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .ignoringAntMatchers(contextPath + "/instances");

        // 配置靜态資源
        http.authorizeRequests().antMatchers(contextPath + "/assets/**").permitAll();

        // 所有請求都必須通過認證
        http.authorizeRequests().anyRequest().authenticated();

        // 登入登出的頁面配置
        http.formLogin().loginPage("/login").permitAll();
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login");

        // 啟用basic認證
        http.httpBasic();
    }

    
}
           

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

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<!-- 已經包含了spring-boot-starter-actuator -->
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
    <version>2.3.1</version>
</dependency>
           

admin client的依賴都是公共依賴,很多服務中已經包含了這些公共依賴,基本不用添加admin client的依賴。

加不加 @EnableEurekaClient 均可

server:
  port: 7502

spring:
  application:
    name: user-server


management:
  #暴露actuator的全部endpoint
  endpoints:
    web:
      exposure:
        include: "*"
  #顯示節點健康的具體資訊
  endpoint:
    health:
      show-details: always


#指定日志檔案位置,要與logback中配置的日志檔案位置一緻
logging:
  file:
    name: C:/Users/chy/Desktop/日志/user-server-all.log


eureka:
  instance:
  	#預設就是/actuator/health,可以預設
    health-check-url-path: /actuator/health
    #發送心跳包的時間間隔,預設30,開發、測試可設定小些
    lease-renewal-interval-in-seconds: 10
  client:
    #ribbon更新節點清單的時間間隔,預設30,開發、測試環境可設定小些
    registry-fetch-interval-seconds: 10
    service-url:
      defaultZone: http://localhost:7500/eureka/
           
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

    <property name="LOG_HOME" value="C:/Users/chy/Desktop/日志"/>

    <!-- 指定彩色日志的渲染規則 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>

    <!-- 指定彩色日志的格式,LN後面是行數 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:-}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(LN:%L  ){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!-- 控制台輸出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 引用日志格式 -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- 每日檔案輸出 -->
    <appender name="DAY_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志檔案名 -->
            <FileNamePattern>${LOG_HOME}/user-server-%d{yyyy-MM-dd}.log</FileNamePattern>
            <!-- 日志檔案保留天數 -->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 指定格式:%d表示日期,%thread表示線程名,%-5level:級别從左顯示5個字元寬度%msg:日志消息,%n是換行符 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <!-- 日志檔案最大體積 -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>500MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!-- 輸出到指定檔案中 -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_HOME}/user-server-all.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 指定格式:%d表示日期,%thread表示線程名,%-5level:級别從左顯示5個字元寬度%msg:日志消息,%n是換行符 -->
            <!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>-->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 預設輸出級别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="DAY_FILE"/>
        <appender-ref ref="FILE"/>
    </root>

    <!-- 給特殊的包指定輸出級别 -->
    <logger name="com.apache.ibatis" level="WARN" />
    <logger name="java.sql.Connection" level="WARN" />
    <logger name="java.sql.Statement" level="WARN" />
    <logger name="java.sql.PreparedStatement" level="WARN" />
    <logger name="java.sql.ResultSet" level="DEBUG" />
    <logger name="com.alibaba.druid.pool.DruidPooledResultSet" level="ERROR" />

    <logger name="org.apache.shiro" level="WARN" />
    <logger name="springfox.documentation" level="WARN" />

</configuration>
           

1、像springboot admin這種第三方元件,等springboot新版本推出一段時候後才會慢慢适配,盡量不要使用很新的springboot版本。

2、@EnableAdminServer、@EnableHystrixDashboard 這2個注解有沖突,如果同時标在同一個引導類上,hystrix dashboard的靜态資源會404,盡量不要在同一個子產品中同時使用springboot admin、hystrix dashboard 2個監控。

3、內建spring security監控微服務這一塊,應用到生産中有很多坑,不一定非要內建內建spring security,可以走内網通路。

繼續閱讀