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

    結束語:線程實現自定義 

相關文章
相關標籤/搜索