SpringBootAdmin2.0實現微服務應用監控

Spring Boot Admin 監控介紹

Spring Boot Admin是一個Web應用,用于管理和監視Spring Boot應用程序的運行狀態。
每個Spring Boot應用程序都被視為客戶端并注冊到管理服務器。
背后的數據采集是由Spring Boot Actuator端點提供。

Spring Boot Admin 是由服務端和客戶端組成

在 Spring Boot 項目中,Spring Boot Admin 作為 Server 端,其他的要被監控的應用作為 Client 端

Spring Boot Admin 設計目的

問題:在微服務生態中,由于一個項目中服務過多,導致排查問題等造成很大的困難。
目的:實時監控各個服務的健康狀態,日志及時查看,服務異常及時通知人員進行修復等。

Spring Boot Admin 實現原理

1.所有需要被監控的服務,均加上SpringBoot提供的Actuator包
2.啟動Admin Server端,作為注冊中心,監控所有客戶端當前狀態(自己也需要被注冊并且被監控)
3.啟動Admin Clinet端,第一次主動向Admin Server端提供健康信息
4.Admin Server端定時輪詢所有監控Admin Client端的節點及時獲得最新信息
5.Admin Client端如果發生異常,Admin Server端提供了郵件功能等,及時通知用戶進行修復

Spring Boot Admin 提供了哪些功能

  • 顯示健康狀況
  • 顯示詳細信息,例如
    • JVM和內存指標
    • micrometer.io指標
    • 數據源指標
    • 緩存指標
  • 顯示內部編號
  • 關注并下載日志文件
  • 查看JVM系統和環境屬性
  • 查看Spring Boot配置屬性
  • 支持Spring Cloud的可發布/ env-和// refresh-endpoint
  • 輕松的日志級別管理
  • 與JMX-beans交互
  • 查看線程轉儲
  • 查看http跟蹤
  • 查看審核事件
  • 查看http端點
  • 查看預定的任務
  • 查看和刪除活動會話(使用spring-session)
  • 查看Flyway / Liquibase數據庫遷移
  • 下載heapdump
  • 狀態更改通知(通過電子郵件,Slack,Hipchat等)
  • 狀態更改的事件日志(非持久性)

SpringBootAdmin2.0集成eureka

創建sunny-eureka-service

這是eureka-server端,注冊中心。

pom文件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

application.yml

配置應用名和端口信息,以及向sunny-admin-server-service注冊的地址為http://localhost:8888,最后暴露自己的actuator的所有端口信息,具體配置如下:

#服務端口號
server:
  port: 8888

spring:
  application:
    name: sunny-eureka-service

eureka:
  instance:
    #為false時,那么注冊到Eureka中的Ip地址就是本機的Ip地址
    prefer-ip-address: false
    #服務注冊中心實例的主機名
    hostname: localhost
    health-check-url-path: /actuator/health
    status-page-url-path: /actuator/info
  client:
    # 表示是否從 eureka server 中獲取注冊信息(檢索服務),默認是true
    fetch-registry: false
    # 表示是否將自己注冊到 eureka server(向服務注冊中心注冊自己),默認是true
    register-with-eureka: false
    service-url:
      #服務注冊中心的配置內容,指定服務注冊中心的位置,eureka 服務器的地址(注意:地址最后面的 /eureka/ 這個是固定值)
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #2、在原先的基礎上添加security用戶名和密碼(例如:http://username:password@localhost:8000/eureka/)
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS #顯示詳細信息

啟動類

@EnableEurekaServer
@SpringBootApplication
public class SpringBootApplicationEurekaServer {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplicationEurekaServer.class);
    }
}

創建sunny-admin-server-service

這是SpringBootAdmin Server端

pom文件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--如果spring-boot-starter-web 排除掉tomcat,則可以引入jetty-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>

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

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

        <!-- 健康監控 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

application.yml

management.endpoints.web.exposure.include 配置,我這里的配置暴露的所有節點進行監控

server:
  port: 8889

spring:
  application:
    name: sunny-admin-server-service
    
eureka:
  instance:
    #服務注冊中心實例的主機名
    hostname: localhost
    health-check-url-path: /actuator/health
    status-page-url-path: /actuator/info
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:8888/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS #顯示詳細信息

啟動類

啟動類添加@EnableAdminServer注解,開啟監控

@EnableDiscoveryClient
@SpringBootApplication
public class SpringBootApplicationMainAdminServer {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplicationMainAdminServer.class);
    }
}

創建sunny-admin-client-service

這是SpringBootAdmin Client端

pom文件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

application.yml

server:
  port: 8183

spring:
  application:
    name: sunny-admin-client-service

eureka:
  instance:
    #服務注冊中心實例的主機名
    hostname: localhost
    health-check-url-path: /actuator/health
    status-page-url-path: /actuator/info
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:8888/eureka/


management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS #顯示詳細信息

啟動類

@EnableDiscoveryClient
@SpringBootApplication
public class SpringBootApplicationMainAdminClient {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplicationMainAdminClient.class);
    }

}

啟動三個工程,在瀏覽器上輸入localhost:8889 ,監控平臺顯示的界面如下:

Spring Boot Admin Server 可以監控的功能很多,使用起來沒有難度,下面描述下可以監測的部分內容:

  • 應用運行狀態,如時間、垃圾回收次數,線程數量,內存使用走勢。
  • 應用性能監測,通過選擇 JVM 或者 Tomcat 參數,查看當前數值。
  • 應用環境監測,查看系統環境變量,應用配置參數,自動配置參數。
  • 應用 bean 管理,查看 Spring Bean ,并且可以查看是否單例。
  • 應用計劃任務,查看應用的計劃任務列表。
  • 應用日志管理,動態更改日志級別,查看日志。
  • 應用 JVM 管理,查看當前線程運行情況,dump 內存堆棧信息。
  • 應用映射管理,查看應用接口調用方法、返回類型、處理類等信息。

SpringBootAdmin2.0集成eureka+securty認證

Web應用程序中的身份驗證和授權有多種方法,因此Spring Boot Admin不提供默認方法。默認情況下,spring-boot-admin-server-ui提供登錄頁面和注銷按鈕。我們結合 Spring Security 實現需要用戶名和密碼登錄的安全認證

創建sunny-eureka-service

這是eureka-server端,注冊中心。

pom文件

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
</parent>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

application.yml

改動點:
1.默認設置security登錄賬號密碼
2.注冊中心的地址,需要加上自己設置的賬號密碼

#服務端口號
server:
  port: 8888

spring:
  application:
    name: sunny-eureka-service
  security:
    user:
      name: admin
      password: 123456

eureka:
  instance:
    #為false時,那么注冊到Eureka中的Ip地址就是本機的Ip地址
    prefer-ip-address: false
    #服務注冊中心實例的主機名
    hostname: localhost
    health-check-url-path: /actuator/health
    status-page-url-path: /actuator/info
    metadata-map:
      user.name:  ${spring.security.user.name}
      user.password:  ${spring.security.user.password}
  client:
    # 表示是否從 eureka server 中獲取注冊信息(檢索服務),默認是true
    fetch-registry: false
    # 表示是否將自己注冊到 eureka server(向服務注冊中心注冊自己),默認是true
    register-with-eureka: false
    service-url:
      #服務注冊中心的配置內容,指定服務注冊中心的位置,eureka 服務器的地址(注意:地址最后面的 /eureka/ 這個是固定值)
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #2、在原先的基礎上添加security用戶名和密碼(例如:http://username:password@localhost:8000/eureka/)
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@${eureka.instance.hostname}:${server.port}/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS #顯示詳細信息

config類

新版本的spring-cloud2.0中: Spring Security默認開啟了CSRF攻擊防御
CSRF會將微服務的注冊也給過濾了,雖然不會影響注冊中心,但是其他客戶端是注冊不了的,這里配置i就是將csrf給關閉掉

@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and().httpBasic()
                .and()
                .csrf()
                .disable();
    }
}

啟動類

@EnableEurekaServer
@SpringBootApplication
public class SpringBootApplicationEurekaServer {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplicationEurekaServer.class);
    }
}

創建sunny-admin-server-service

這是SpringBootAdmin Server端。

pom文件

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!--如果spring-boot-starter-web 排除掉tomcat,則可以引入jetty-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>

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

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

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

    <!-- 健康監控 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>

</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

application.yml

server:
  port: 8889

spring:
  application:
    name: sunny-admin-server-service
  security:
    user:
      name: admin
      password: 123456

eureka:
  instance:
    #服務注冊中心實例的主機名
    hostname: localhost
    health-check-url-path: /actuator/health
    status-page-url-path: /actuator/info
    metadata-map:
      user.name:  ${spring.security.user.name}
      user.password:  ${spring.security.user.password}
  client:
    serviceUrl:
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@${eureka.instance.hostname}:8888/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS #顯示詳細信息

config類

@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

    private final String adminContextPath;

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        successHandler.setTargetUrlParameter( "redirectTo" );

        http.authorizeRequests()
                .antMatchers( adminContextPath + "/assets/**" ).permitAll()
                .antMatchers( adminContextPath + "/login" ).permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().loginPage( adminContextPath + "/login" ).successHandler( successHandler ).and()
                .logout().logoutUrl( adminContextPath + "/logout" ).and()
                .httpBasic().and()
                .csrf().disable();
        // @formatter:on
    }
}

啟動類

@EnableAdminServer
@EnableDiscoveryClient
@SpringBootApplication
public class SpringBootApplicationMainAdminServer {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplicationMainAdminServer.class);
    }
}

創建sunny-admin-client-service

這是SpringBootAdmin Server端。

pom文件

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

application.yml

server:
  port: 8183

spring:
  application:
    name: sunny-admin-client-service
  security:
    user:
      name: admin
      password: 123456

eureka:
  instance:
    #服務注冊中心實例的主機名
    hostname: localhost
    health-check-url-path: /actuator/health
    status-page-url-path: /actuator/info
    metadata-map:
      user.name:  ${spring.security.user.name}
      user.password:  ${spring.security.user.password}
  client:
    serviceUrl:
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@${eureka.instance.hostname}:8888/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS #顯示詳細信息

啟動類

@EnableDiscoveryClient
@SpringBootApplication
public class SpringBootApplicationMainAdminClient {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplicationMainAdminClient.class);
    }
}

SpringBootAdmin集成郵箱服務

郵件通知

在 Spring Boot Admin 中 當注冊的應用程序狀態更改為DOWN、UNKNOWN、OFFLINE 都可以指定觸發通知,下面講解配置郵件通知。

在sunny-admin-server-service工程的pom文件中,加上email的依賴,如下

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

在配置文件application.yml文件中,配置收發郵件的配置:

spring:
  application:
    name: sunny-admin-server-service
  boot:
    admin:
      ui:
        title: sunny-admin-server-service
      notify:
        mail:
          from: xxxx@163.com #發件人
          to: xxxx@163.com,xxxx@163.com  #逗號分隔的收件人列表
          cc: xxxx@163.com,xxxx@163.com #逗號分隔的抄送收件人列表
          enabled: true # 開啟郵箱通知
  mail:
    host: smtp.163.com 
    username: xxxx@163.com #自己的郵箱
    password: xxx #授權碼
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true
    default-encoding: utf-8

配置后,重啟sunny-admin-server-service工程,之后若出現注冊的客戶端的狀態從 UP 變為 OFFLINE 或其他狀態,服務端就會自動將電子郵件發送到上面配置的收件地址。

注意 : 配置了郵件通知后,會出現 反復通知 service offline / up。這個問題的原因在于 查詢應用程序的狀態和信息超時,下面給出兩種解決方案:

#方法一:增加超時時間(單位:ms)

spring.boot.admin.monitor.read-timeout=20000

#方法二:關閉閉未使用或不重要的檢查點

management.health.db.enabled=false
management.health.mail.enabled=false
management.health.redis.enabled=false
management.health.mongo.enabled=false

自定義通知

可以通過添加實現Notifier接口的Spring Beans來添加您自己的通知程序,最好通過擴展 AbstractEventNotifier或AbstractStatusChangeNotifier。在sunny-admin-server-service工程中編寫一個自定義的通知器:

@Component
public class CustomNotifier  extends AbstractStatusChangeNotifier {
    private static final Logger LOGGER = LoggerFactory.getLogger( LoggingNotifier.class);

    public CustomNotifier(InstanceRepository repository) {
        super(repository);
    }

    @Override
    protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
        return Mono.fromRunnable(() -> {
            if (event instanceof InstanceStatusChangedEvent) {
                LOGGER.info("Instance {} ({}) is {}", instance.getRegistration().getName(), event.getInstance(),
                        ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());

                String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();

                switch (status) {
                    // 健康檢查沒通過
                    case "DOWN":
                        System.out.println("發送 健康檢查沒通過 的通知!");
                        break;
                    // 服務離線
                    case "OFFLINE":
                        System.out.println("發送 服務離線 的通知!");
                        break;
                    //服務上線
                    case "UP":
                        System.out.println("發送 服務上線 的通知!");
                        break;
                    // 服務未知異常
                    case "UNKNOWN":
                        System.out.println("發送 服務未知異常 的通知!");
                        break;
                    default:
                        break;
                }

            } else {
                LOGGER.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),
                        event.getType());
            }
        });
    }
}

效果圖,郵件通知

我的博客即將同步至騰訊云+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=12tesopfl6i5t

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。