SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂)

SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂)

  Spring Boot Actuatorspring boot项目一个监控模块,提供了不少原生的端点,包含了对应用系统的自省和监控的集成功能,好比应用程序上下文里所有的Bean运行情况检查、康指标环境变量各种重要度量指标等等,以图形化界面的方式展现这些信息,经过这些监控信息,咱们就能随时了解应用的运行状况了。java

  做用:能够经过监控运行状态检查获取应用的运行状态,潜在问题等。能够更具这些且在风险对项目进行优化,排除问题保证项目的运行。能够经过监控度量指标获取应用内存占用,线程数量,垃圾回收过程对项目进行深刻分析。git

一.Spring Boot Actuator的度量指标监控入门

1,准备工做

  在项目中引入Actuator依赖,该以来由SprngBoot官方提供。github

1 <dependency>
2     <groupId>org.springframework.boot</groupId>
3     <artifactId>spring-boot-starter-actuator</artifactId>
4 </dependency>

  当项目中引入了Actuator依赖后,那么当前的项目就表示拥有了度量指标监控能力了,启动SpringBoot项目,控制台以下:web

 

 

 框起来的那段内容表示:SpringBoot监控已经默认暴露了两个基础端点,可供咱们访问获取应用监控数据,基础访问路径是"/actuator"spring

2,访问基础端点测试

  输入访问路径:localhost:8080/actuator  结果以下:(为便于查看,我已将JSON结果格式化)编程

 1 {
 2     "_links": {
 3         "self": {
 4             "href": "http://localhost:8080/actuator",  // 基础访问地址
 5             "templated": false
 6         },
 7         "health-path": {
 8             "href": "http://localhost:8080/actuator/health/{*path}",  
 9             "templated": true
10         },
11         "health": {
12             "href": "http://localhost:8080/actuator/health",  // 暴露的端点一 (访问URL)
13             "templated": false
14         },
15         "info": {
16             "href": "http://localhost:8080/actuator/info",  // 暴露的端点二 (访问URL)
17             "templated": false
18         }
19     }
20 }

  那么这些暴露的URL访问后分别表明什么呢?Actuator提供了13个接口,能够分为三大类:配置接口、度量接口和其它接口,具体以下表:json

HTTP 方法 路径 描述
GET /autoconfig 提供了一份自动配置报告,记录哪些自动配置条件经过了,哪些没经过
GET /configprops

描述配置属性(包含默认值)如何注入Bean缓存

●prefix属性表明 了属性的配置前缀
●properties表明 了各个属性的名称和值。网络

GET /beans

描述应用程序上下文里所有的Bean,以及它们的关系多线程

●bean:Bean的名称
●scope:Bean的做用域
●type:Bean的Java类型
●reource:class文件的具体路径
●dependencies:依赖的Bean名称

GET /dump 获取线程活动的快照
GET /env 获取所有环境属性。包括:环境变量、JVM属性.应用的配置配置。命令行中的参数等
GET /env/{name} 根据名称获取特定的环境属性值。/env接口还能用来获取单个属性的值。只须要在请求时在/env/+属性名便可。
GET /health 报告应用程序的健康指标(运行状态),这些值由HealthIndicator的实现类提供.(默认暴露的接口)
GET /info

获取应用程序的自定义的定制信息,这些信息由info打头的属性提供。默认状况下.该端点只会返回一个空的json内容,咱们能够在application.properties配置文件中经过info前骚来设置一些属性(默认暴露的接口)

GET /mappings 描述所有的URI路径,以及它们和控制器(包含Actuator端点)的映射关系,罗列出应用程序发布的所有接口。

●bean属性标识了 该映射关系的请求处理器
●method属性标识了该映射关系的具体处理类和处理函数。

GET /metrics 报告各类应用程序度量信息,好比内存用量,线程信息,垃圾回收信息,HTTP请求计数等
GET /metrics/{name} 报告指定名称的应用程序度量值
POST /shutdown 关闭应用程序,要求endpoints.shutdown.enabled设置为true
GET /trace 提供基本的HTTP请求跟踪信息(时间戳、HTTP头等)

  访问一个试试?localhost:8080/actuator/health   访问后结果:运行状态为正常运行(说明:Actuator监控获取的全部数据都是JSON格式的。

1 {"status":"UP"}

  那么若是但愿访问其余接口怎么办?,默认只开启了info、health两个端点,须要额外开启端点,须要额外去配置的!!!

 1 #配置访问端点的根路径
 2 management: 
 3   endpoints:
 4     web:
 5       # 配置访问端点的根路径,默认是/actuator
 6       #base-path: /actuator
 7       exposure:
 8         #配置开启其余端点的URI,开启全部的端点访问: *,也能够指定开启端点访问:如: /beans, /env
 9         include: "*"
10         # - /beans
11         # - /env
12         #配置排除其余端点的URI(排除即不开启)
13         #exclude:
14         # - /beans
15         # - /env

 

 

  重启SpringBoot服务,以下:

   具体访问测试就不演示了,Actuator监控获取的全部数据都是JSON格式的,能够本身访问测试后经过网络工具格式化JSON

二.可视化UI界面实现监控应用

  Actuator来监控Spring Boot应用,其提供了许多REST接口来查看应用的信息。但其返回的是大量的JSON格式数据,信息看上去不直观也不易于理解。Spring Boot Admin(SBA)是一款基于Actuator开发的开源软件(是一个针对spring-bootactuator接口进行UI美化封装的监控工具),能够实现图形化界面的方式展现Spring Boot应用的配置信息、Beans信息、环境属性、线程信息、JVM情况等。官方说明文档点这里。选择版本文档说明,内有详情使用说明。

  SpringBootAdmin的使用是须要创建服务端与客户端的。Spring Boot Admin包含admin-serveradmin-client两个组件,admin-server经过采集actuator端点数据,显示在spring-boot-admin-ui上。

  服务端:独立的项目,会将搜集到的数据在本身的图形界面中展现。依赖admin-server

  客户端:须要监控的项目。依赖Actuator,admin-client

  对应关系:一个服务端能够监控多个客户端。

 1.创建Spring Boot Admin Server服务端

  舒适提示:服务端属于一个独立SpringBoot的项目(新建项目)。

  1. 新建SpringBoot项目(当前版本2.4.0)。
  2. 修改pom引入SpringBootAdmin-Server依赖。
    既然是一个服务端,那确定是须要启动容器(Tomcat)的,因此具体的依赖,你看状况添加(能够选择根据SpringBoot新建项目时勾选依赖,也能够从Maven中查找)
    1 <!-- spring-boot-admin-服务端依赖 -->
    2 <dependency>
    3     <groupId>de.codecentric</groupId>
    4     <artifactId>spring-boot-admin-starter-server</artifactId>
    5     <version>2.3.1</version>
    6 </dependency>
  3. 修改yml配置文件
    毕竟服务端属于一个独立SpringBoot的项目,管理的客户端也是一个独立的项目,若是不更改端口,可能端口会出现占用状况,因此更新配置文件修改端口
    1 server:
    2   #servlet:
    3     # 配置访问路径(可选)
    4     #context-path: /admin-server
    5   # 配置端口
    6   port: 9090
  4. 启动类添加注解@EnableAdminServer
    开启SpringBootAdmin-Server服务端
    1 @SpringBootApplication
    2 @EnableAdminServer
    3 public class SpringbootAdminServerApplication {
  5. 启动服务访问
    http://localhost:9090/   效果图以下

    由于还没添加客户端,因此监控列表里是空的,接下来建立一个Spring Boot应用做为客户端。

 1.创建Spring Boot Admin Client客户端

   admin-server经过采集actuator端点数据,将信息解析展现在UI界面的。那么客户端就须要依赖Actuator和admin-clietn。

  1. 修改pom引入admin-client依赖
    本次案例演示,直接在前面的Actuator项目中更新
    1 <!-- spring-boot-admin-starter-client客户端依赖:注意要与服务端版本一致 -->        
    2 <dependency>
    3     <groupId>de.codecentric</groupId>
    4     <artifactId>spring-boot-admin-starter-client</artifactId>
    5     <version>${spring-boot-admin.version}</version>
    6 </dependency>

    注意:1.版本要与服务端一致。2.客户端项目依赖不能少了Actuator。

  2. 修改yml文件添加必须配置
    更多配置及应用参考:Spring-Boot-Admin官方文档
     1 #配置访问端点的根路径
     2 management: 
     3   endpoints:
     4     web:
     5       # 配置访问端点的根路径,默认是/actuator
     6       #base-path: /actuator
     7       exposure:
     8         #配置开启其余端点的URI,开启全部的端点访问: *,也能够指定开启端点访问:如: /beans, /env
     9         include: "*"
    10         # - /beans
    11         # - /env
    12         #配置排除其余端点的URI(排除即不开启)
    13         #exclude:
    14         # - /beans
    15         # - /env
    16         
    17 spring:
    18   boot:
    19     admin:
    20       client:
    21         # 配置客户端,被监控的服务端地址(官方说明也很详细的,这个是必须配置的)
    22         url:
    23         - http://localhost:9090
  3. 启动客户端项目
    以前服务端启动后,项目监控为0,当这个客户端启动后,须要稍等片刻,从新请求访问服务端地址(http://localhost:9090),便可看到以下:

     点击左上“应用墙”进入SpringBootAdmin主页,显示运行时间,项目个数。点击进入详情页,便可已图形报表UI界面方式显示全部监控信息:
     如上的操做更多的多是涉及到了测试/运维的问题,因此这里就不深究了,但某些时候须要咱们开发人员配和实现更多操做,例如邮件方式发送检测日志,信息等。详情参考SpringBootAdmin

二,SpringBoot中的异步调用

  实际开发中,有一些业务可能和实际业务无关,但又不能没有,例如:注册新用户,当即送积分(没有点击领取但积分已到帐),或下单成功,发送push消息等等。

  一般咱们开发的程序都是同步调用的,即程序按照代码的顺序一行一行的逐步往下执行,每一行代码都必须等待上一行代码执行完毕才能开始执行。而异步编程则没有这个限制,代码的调用再也不是阻塞的。因此在一些情景下,经过异步编程能够提升效率,提高接口的吞吐量。

  使用异步的好处?就拿注册用户送积分来讲:

  1. 容错性。(不能由于积分赠送失败,致使用户注册不成功!)
    注册用户是主要业务,积分赠送失败,能够在提供有针对性的异常补偿!
  2. 提高性能和接口吞吐量
    用户注册,须要20s,送积分须要10s,若是同步调用,则用户须要等待30s,若是异步调用,用户只须要消耗20s便可注册成功。

1.没有异步调用代码测试

  不使用异步调用,即同步调用测试。

  1. 编写Service提供两个方法,一个实现注册,一个实现送积分。
    为便于清晰测试,在积分方法中使用线程休眠。
     1 @Service
     2 public class AsynService {
     3     
     4     /**
     5      * 注册方法
     6      */
     7     public void register() {
     8         System.out.println("注册成功.......");
     9     }
    10     /**
    11      * 异步方法送积分
    12      */
    13     public void asynIntegral() {
    14         try {
    15             Thread.sleep(3000);// 休息三秒
    16         } catch (InterruptedException e) {
    17             // TODO Auto-generated catch block
    18             e.printStackTrace();
    19         }
    20         System.out.println("送积分100分....执行者线程名为:"+Thread.currentThread().getName());
    21     }
    22     
    23 }
  2. 编写Controoler注册功能,在注册后调用送积分方法。
     1 @RestController
     2 @Slf4j // 获取log对象,Lombok插件中的注解
     3 public class AsynController {
     4     
     5     @Autowired
     6     private AsynService asynService;
     7     
     8     @RequestMapping("/register")
     9     public String asynTest() {
    10         long startTmie = System.currentTimeMillis();
    11         // 注册逻辑:调用注册方法
    12         asynService.register();
    13         // 调用送积分方法
    14         asynService.asynIntegral();
    15         long endtTmie = System.currentTimeMillis();
    16         log.info("消耗时间:"+(endTime-starttTmie));
    17         return "ok";
    18     }
    19     
    20 }
  3. 页面测试访问,查看控制台运行总耗时.
    localhost:8080/register
    注册成功.......
    送积分100分....执行者线程名称为:http-nio-8080-exec-1
    2020-12-02 20:00:15.112  INFO 4604 --- [nio-8080-exec-1] c.xsge123.app.controller.AsynController  : 消耗时间:3002

    结束语:在同步调用时,页面不会马上刷新注册结果,只有注册和送积分的功能所有执行完成后,页面才会显示注册通知。客户需等待较长的时间。程序总耗时较长。

2,异步调用代码测试

  在同步代码基础上,新增配置类AsyncConfig,配置开启异步调用,同时在须要使用异步调用的方法上使用注解@Async便可。

  1. 新增配置类AsyncConifg,使用注解@EnableAsync开启异步调用 ,并将配置类加入到Spring容器中。
      准确的说注解@EnableAsync直接在SpringBoot启动类上使用便可。那么这个新增配置类的意义何在呢?SpringBoot异步调用的实质是,为异步调用方法开启了新的线程(提供这个配置类,是为了便于后面自定义线程池的)固然若是不考虑自定义线程池,则能够直接选择在SpringBoot启动类上使用注解,这样就能够省略配置类了。但程序....你细品。
    1 @Configuration // 将类注入到Spring容器中
    2 @EnableAsync //开启SpringBoot异步调用(针对异步调用的方法,开启新线程),在启动类上使用也能够 
    3 public class AsyncConfig {
    4 
    5 }
  2. 在须要异步调用的业务方法上使用注解@Aynsc,表示当前方法为异步方法
     1 /**
     2  * 异步方法送积分
     3  */
     4 @Async // 标注当前方法为异步方法
     5 public void asynIntegral() {
     6     try {
     7         Thread.sleep(3000);// 休息3秒
     8     } catch (InterruptedException e) {
     9         // TODO Auto-generated catch block
    10         e.printStackTrace();
    11     }
    12     System.out.println("送积分100分...."+Thread.currentThread().getName());
    13 }
  3. 启动服务测试,查看控制台耗时。
    localhost:8080/register
    注册成功.......
    2020-12-02 20:18:11.764  INFO 4604 --- [nio-8080-exec-2] c.xsge123.app.controller.AsynController  : 消耗时间:6
    送积分100分....task-1
    送积分100分....score-2
    送积分100分....score-3

    结束语:在异步调用的状况下,页面即刻响应注册结果无需等待,后台等待3秒后,送积分程序显示执行结果。

3,自定义异步调用线程池

  @Async注解,在默认状况下,用的是SimpleAsyncTaskExecutor线程池,该线程池不是真正意义上的线程池,由于线程不可重用,每次调用都会新建一条线程。能够经过控制台日志输出查看,每次打印的线程名都是[task -1]、[task -2]、[task-3]、[task-4].....递增的。

  @Async注解异步框架提供有多种线程池支持:
  SimpLeAsyncTaskExecutor:不是真的线程池,这个类不可重用线程,每次调用都会建立一个新的线程 。
  SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操做。只适用于不须要多线程的地方
  ConcurrentTaskExecutor:Executor的适配类,不推荐使用。若是ThreadPoolTaskExecutor不知足要求时,才用考虑使用这个类
  ThreadPoolTaskScheduler:可使用cron表达式。
  ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent .ThreadPoolExecutor的包装类。

  1.  修改AsyncConfig配置类,添加自定义线程池方法,注入bean
     1 @Configuration // 将类注入到Spring容器中
     2 @EnableAsync //开启SpringBoot异步调用(针对异步调用的方法,开启新线程) 
     3 public class AsyncConfig {
     4     
     5     @Bean(name = "scorePoolTaskExecutor")
     6     public ThreadPoolTaskExecutor getScorePoolTaskExecutor() {
     7         // 建立线程池对象
     8         ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
     9         //核心线程数
    10         taskExecutor.setCorePoolSize(10);
    11         //线程池维护线程的最大数量,只有在缓冲队列满了以后才会申请超过核心线程数的线程
    12         taskExecutor.setMaxPoolSize(100);
    13         //缓存队列
    14         taskExecutor.setQueueCapacity(50) ;
    15         //许的空闲时间,当超过了核心线程出以外的线程在空闲时间到达以后会被销毁
    16         taskExecutor.setKeepAliveSeconds (200) ;
    17         //.异步方法内部线程名称
    18         taskExecutor.setThreadNamePrefix("score-");
    19         /** 
    20         * 当线程池的任务缓存队列已满,而且线程池中的线程数目达到maximumPoolSize,若是还有任务到来就会采起任务拒绝策略
    21         * 一般有如下四种策略:
    22         * ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecuti onException异常。
    23         * ThreadPoolExecutor.DiscardPolicy: 也是丢弃任务,可是不抛出异常。
    24         * ThreadPoolExecutor. DiscardOldestPolicy: 丢弃队列最前面的任务,而后从新尝试执行任务(重复此过程)
    25         * ThreadPoolExecutor . CallerRunsPolicy:重试添加当前的任务,自动重复调用execute()方法,直到成功
    26         */
    27         taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    28         taskExecutor.initialize() ;
    29         return taskExecutor;
    30     }
    31 
    32 }
  2. 修改注解@Async的使用,在使用注解时,指定使用的自定义线程
     1 /**
     2  * 异步方法送积分
     3  */
     4 @Async("scorePoolTaskExecutor") // 标注当前方法为异步方法
     5 public void asynIntegral() {
     6     try {
     7         Thread.sleep(3000);
     8     } catch (InterruptedException e) {
     9         // TODO Auto-generated catch block
    10         e.printStackTrace();
    11     }
    12     System.out.println("送积分100分...."+Thread.currentThread().getName());
    13 }
  3. 启动服务,测试自定义线程池实现异步调用,查看控制台结果
    注册成功.......
    2020-12-02 20:45:57.898  INFO 4604 --- [nio-8080-exec-3] c.xsge123.app.controller.AsynController  : 消耗时间:2
    送积分100分....score-1
    送积分100分....score-2
    送积分100分....score-3

    结束语:线程实现自定义 

相关文章
相关标签/搜索