zoukankan      html  css  js  c++  java
  • 服务监控之 Spring Boot Admin.

    一、概述

     开始阅读这篇文章之前,建议先阅读下《SpringBoot 之Actuator》,该篇文章提到 Spring Boot Actuator 提供了对单个Spring Boot的监控,信息包含:应用状态、内存、线程、堆栈等等,比较全面的监控了Spring Boot应用的整个生命周期。但是美中不足的是:

    1. 所有的监控都需要调用固定的接口来查看,如果全面查看应用状态需要调用很多接口,并且接口返回的 Json 信息不方便运营人员理解;
    2. 如果Spring Boot 应用集群非常大,每个应用都需要调用不同的接口来查看监控信息,操作非常繁琐低效。

     在这样的背景下,就诞生了另外一个开源软件:Spring Boot Admin。那么什么是 Spring Boot Admin 呢?Spring Boot Admin 是一个针对 Spring Boot Actuator 进行UI美化封装的监控工具。集群的每个应用都认为是一个客户端(或者说实例),通过HTTP或者使用 Eureka 注册到 Spring Boot Admin Server中进行展示,Spring Boot Admin UI 使用AngularJs将数据展示在前端。

     下面将给大家介绍如何使用Spring Boot Admin对Spring Boot应用进行监控。

    二、spring-boot-admin-starter-server

    下面介绍 spring-boot-admin-server 的构建,要监控的每个客户端(或者说实例),都可以把 Actuator 数据注册到 server 中进行 UI 渲染展示。

    1. pom.xml

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

    2. application.yml

    server:
      port: 3333
    
    spring:
      application:
        name: monitor
    

    3. Application.java

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

    做完以上动作,我们一个 spring-boot-admin-server 项目就搭建好了。以下是一些附加的功能:权限认证和邮件预警。

    4. 配置 spring-security 权限验证

    • pom.xml
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-server-ui-login</artifactId>
                <version>1.5.7</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
    
    • application.yml
    security:
      user:
        name: ${monitor.user}
        password: ${monitor.password}
    
    • SecurityConfig.java
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // Page with login form is served as /login.html and does a POST on /login
            http.formLogin().loginPage("/login.html").loginProcessingUrl("/login").permitAll();
            // The UI does a POST on /logout on logout
            http.logout().logoutUrl("/logout");
            // The ui currently doesn't support csrf
            http.csrf().disable();
    
            // Requests for the login page and the static assets are allowed
            //允许登录页面和静态资源的请求
            http.authorizeRequests().antMatchers("/login.html", "/**/*.css", "/img/**", "/third-party/**")
                    .permitAll();
            // ... and any other request needs to be authorized
            //这点重要:所有请求都需要认证
            http.authorizeRequests().antMatchers("/**").authenticated();
    
            // Enable so that the clients can authenticate via HTTP basic for registering
            http.httpBasic();
        }
    }
    
    • 效果

    5、邮件预警

    • pom.xml
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-mail</artifactId>
                <version>1.5.12.RELEASE</version>
            </dependency>
    
    • application.yml
    spring:
      mail:
        host: smtp.exmail.qq.com
        port: 465
        username: xxx
        password: xxx
        properties:
          mail:
            smtp:
              auth: true
              debug: true
              timeout: 0
              socketFactory:
                port: 465
                class: javax.net.ssl.SSLSocketFactory
    
    • NotifierConfig.java
    /**
     * 重新配置消息通知
     *
     * @author : cuixiuyin
     */
    @Configuration
    @EnableScheduling
    public class NotifierConfig {
        private static final Logger log = LoggerFactory.getLogger(NotifierConfig.class);
    
        @Autowired
        private JavaMailSender javaMailSender;
    
        @Autowired
        private RemindingNotifier remindingNotifier;
    
        @Bean
        @Primary
        public RemindingNotifier remindingNotifier() {
    
            RemindingNotifier remindingNotifier = new RemindingNotifier(new AbstractEventNotifier() {
    
                @Override
                protected void doNotify(ClientApplicationEvent event) throws Exception {
                    if (event instanceof ClientApplicationStatusChangedEvent) {
                        ClientApplicationStatusChangedEvent changedEvent = (ClientApplicationStatusChangedEvent) event;
                        log.info("Application {} ({}) is {}", event.getApplication().getName(), event.getApplication().getId(), changedEvent.getTo().getStatus());
                        String text = String.format("应用:%s 服务ID:%s,服务ip:%s 状态改变为:[%s ---> %s],时间:%s"
                                , event.getApplication().getName()
                                , event.getApplication().getId()
                                , event.getApplication().getHealthUrl()
                                , changedEvent.getFrom().getStatus()
                                , changedEvent.getTo().getStatus()
                                , new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(changedEvent.getTimestamp())));
                        log.warn(text);
                        SimpleMailMessage message = new SimpleMailMessage();
                        message.setFrom("xxx@qq.com");
                        message.setTo("xxx@163.com");
                        message.setSubject(event.getApplication().getName() + "服务状态改变");
                        message.setText(text);
                        javaMailSender.send(message);
                    } else {
                        log.info("Application {} ({}) {}", event.getApplication().getName(), event.getApplication().getId(), event.getType());
                    }
                }
            });
            // 每5分钟就需要提醒一次,并不一定会提醒,有 RemindingNotifier 里面的状态进行决定
            remindingNotifier.setReminderPeriod(TimeUnit.MINUTES.toMillis(5));
            return remindingNotifier;
        }
    
        /**
         * 每隔一分钟检查还有那些需要进行提醒
         */
        @Scheduled(fixedRate = 1_000L)
        public void remind() {
            remindingNotifier.sendReminders();
        }
    }
    
    • 效果

    三、spring-boot-admin-starter-client

    我们已经有了一个 spring-boot-admin-server,现在要做的就是如何把客户端(或者说实例)的 Actuator 数据注册到 Server 中。

    1. pom.xml

            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-starter-client</artifactId>
                <version>2.1.5</version>
            </dependency>
    

    2. application.yml

    spring:
      application:
        name: dubbo-provider
      boot:
        admin:
          enabled: true
          client:
            instance:
              name: ${spring.application.name}
              prefer-ip: true
            url: http://127.0.0.1:3333
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    

    如此,我们就把客户端(或者说实例)的 Actuator 数据注册到 Server 中了。

    附录

    1. 效果图


    2.源代码地址

    Github 演示代码地址:https://github.com/JMCuixy/dubbo-demo

  • 相关阅读:
    BZOJ4896 THUSC2016补退选(trie)
    BZOJ4892 Tjoi2017dna(后缀数组)
    BZOJ4890 Tjoi2017城市
    BZOJ4888 Tjoi2017异或和(树状数组)
    BZOJ4887 Tjoi2017可乐(动态规划+矩阵快速幂)
    BZOJ4883 棋盘上的守卫(环套树+最小生成树)
    BZOJ4881 线段游戏(二分图+树状数组/动态规划+线段树)
    BZOJ4878 挑战NP-Hard(dfs树)
    BZOJ5466 NOIP2018保卫王国(倍增+树形dp)
    BZOJ4873 Shoi2017寿司餐厅(最小割)
  • 原文地址:https://www.cnblogs.com/jmcui/p/11025819.html
Copyright © 2011-2022 走看看