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

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

1,准备工作

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

1 <dependency>

2    <groupId>org.springframework.boot</groupId>

3    <artifactId>spring-boot-starter-actuator</artifactId>

4 </dependency>

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

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

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个接口,可以分为三大类:配置接口、度量接口和其它接口,具体如下表:

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-boot的actuator接口进行UI美化封装的监控工具),可以实现图形化界面的方式展示Spring Boot应用的配置信息、Beans信息、环境属性、线程信息、JVM状况等。官方说明文档点这里。选择版本文档说明,内有详情使用说明。

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

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

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

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

1.建立Spring Boot Admin Server服务端

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

新建SpringBoot项目(当前版本2.4.0)。

修改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>

复制代码

修改yml配置文件

毕竟服务端属于一个独立SpringBoot的项目,管理的客户端也是一个独立的项目,如果不更改端口,可能端口会出现占用情况,所以更新配置文件修改端口

复制代码

1 server:

2  #servlet:

3    # 配置访问路径(可选)

4    #context-path: /admin-server

5  # 配置端口

6  port: 9090

复制代码

启动类添加注解@EnableAdminServer

开启SpringBootAdmin-Server服务端

1 @SpringBootApplication

2 @EnableAdminServer

3 public class SpringbootAdminServerApplication {

启动服务访问

http://localhost:9090/  效果图如下

因为还没添加客户端,所以监控列表里是空的,接下来创建一个Spring Boot应用作为客户端。

1.建立Spring Boot Admin Client客户端

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

修改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。

修改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

复制代码

启动客户端项目

之前服务端启动后,项目监控为0,当这个客户端启动后,需要稍等片刻,重新请求访问服务端地址(http://localhost:9090),即可看到如下:

点击左上“应用墙”进入SpringBootAdmin主页,显示运行时间,项目个数。点击进入详情页,即可已图形报表UI界面方式显示所有监控信息:

如上的操作更多的可能是涉及到了测试/运维的问题,所以这里就不深究了,但某些时候需要我们开发人员配和实现更多操作,例如邮件方式发送检测日志,信息等。详情参考SpringBootAdmin

二,SpringBoot中的异步调用

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

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

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

容错性。(不能因为积分赠送失败,导致用户注册不成功!)

注册用户是主要业务,积分赠送失败,可以在提供有针对性的异常补偿!

提升性能和接口吞吐量

用户注册,需要20s,送积分需要10s,如果同步调用,则用户需要等待30s,如果异步调用,用户只需要消耗20s即可注册成功。

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 }

复制代码

编写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 }

复制代码

页面测试访问,查看控制台运行总耗时.

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即可。

新增配置类AsyncConifg,使用注解@EnableAsync开启异步调用 ,并将配置类加入到Spring容器中。

  准确的说注解@EnableAsync直接在SpringBoot启动类上使用即可。那么这个新增配置类的意义何在呢?SpringBoot异步调用的实质是,为异步调用方法开启了新的线程(提供这个配置类,是为了便于后面自定义线程池的)当然如果不考虑自定义线程池,则可以直接选择在SpringBoot启动类上使用注解,这样就可以省略配置类了。但程序....你细品。

复制代码

1 @Configuration // 将类注入到Spring容器中

2 @EnableAsync //开启SpringBoot异步调用(针对异步调用的方法,开启新线程),在启动类上使用也可以

3 public class AsyncConfig {

4

5 }

复制代码

在需要异步调用的业务方法上使用注解@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 }

复制代码

启动服务测试,查看控制台耗时。

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的包装类。

修改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 }

复制代码

修改注解@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 }

复制代码

启动服务,测试自定义线程池实现异步调用,查看控制台结果

复制代码

注册成功.......

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

龙华大道1号 http://www.kinghill.cn/Dynamics/2106.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容