SpringBoot實戰(深入Actuator)讀書筆記
阿新 • • 發佈:2018-12-25
Spring Boot的Actuator。它提供了很多生產級的特性,比如監控和度 量Spring Boot應用程式。 Actuator的這些特性可以通過眾多REST端點、遠端shell和JMX獲得 對於Maven專案,引入的依賴是這樣的: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> Actuator Web端點 主要作用,檢視配置明細,執行時度量,關閉應用程式, 獲取應用程式資訊(如下圖)
連線 Actuator 的遠端 shell Actuator另一個深入執行中應用程式內部的方式是使用遠端shell。 Spring Boot集成了CRaSH,一種能嵌入任意Java應用程式的shell。 如果用Maven構建專案,你需要在pom.xml檔案裡新增如下依賴: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-remote-shell</artifactId> </dependency>
通過 JMX 監控應用程式
除了REST端點和遠端shell, Actuator還把它的端點以MBean的方式釋出了出來,可以通過
JMX來檢視和管理。使用JMX是管理Spring Boot應用程式的一個好方法,如果你已在用JMX管理
應用程式中的其他MBean,則尤其如此;Actuator的端點都發布在org.springframework.boot域下。比如,你想要檢視應用程式的請求對映關係,那麼可以看一下圖7-6(通過JConsole檢視請求對映端點)。
調整Actuator .1.1.修改端點 ID; 每個Actuator端點都有一個ID用來決定端點的路徑,比方說,/beans端點的預設ID就是beans。如果端點的路徑是由ID決定的,那麼可以通過修改ID來改變端點的路徑。你要做的就是設定一個屬性,屬性名是endpoints.endpoint-id.id。我們用/shutdown端點來做個演示,它會響應發往/shutdown的POST請求。假設你想讓它處理髮往/kill的POST請求,可以通過如下YAML為/shutdown賦予一個新的ID,也就是新的路徑: endpoints: shutdown: id: kill 重新命名端點、修改其路徑的理由很多。最明顯的理由就是,端點的命名要和團隊的術語保持一致。你也可能想重新命名端點,讓那些熟悉預設名稱的人找不到它,藉此增加一些安全感。 .1.2.啟用和禁用端點; 雖然Actuator的端點都很有用,但你不一定需要全部這些端點。預設情況下,所有端點(除了/shutdown)都啟用。我們已經看過如何設定endpoints.shutdown.enabled為true,以此開啟/shutdown端點用同樣的方式,你可以禁用其他的端點,將endpoints.endpoint-id.enabled設定為false。例如,要禁用/metrics端點,你要做的就是將endpoints.metrics.enabled屬性設定為false。在application.yml裡做如下設定: endpoints: metrics: enabled: false .1.3.新增自定義度量資訊; 從/metrics端點獲得執行中應用程式的內部度量資訊,包括記憶體、垃圾回收和執行緒資訊。這些都是非常有用且資訊量很大的度量值,但你可能還想定義自己的度量,用來捕獲應用程式中的特定資訊。比方說,我們想要知道使用者往閱讀列表裡儲存了多少次圖書,最簡單的方法就是在每次呼叫ReadingListController的addToReadingList()方法時增加計數器值,計數器很容易實現,但這個不斷變化的總計值如何同/metrics端點發布的度量資訊一起釋出出來呢? //SpringBoot Actutor支援類 package org.springframework.boot.actuate.metrics; public interface CounterService { void increment(String metricName); void decrement(String metricName); void reset(String metricName); } Actuator的自動配置還會配置一個GaugeService型別的Bean。該介面與CounterService 類似,能將某個值記錄到特定名稱的度量值裡。 GaugeService看起來是這樣的: package org.springframework.boot.actuate.metrics; public interface GaugeService { void submit(String metricName, double value); } @Controller @RequestMapping("/") @ConfigurationProperties("amazon") public class ReadingListController { private CounterService counterService; @Autowired public ReadingListController( ReadingListRepository readingListRepository, AmazonProperties amazonProperties, CounterService counterService, GaugeService gaugeService) { this.readingListRepository = readingListRepository; this.amazonProperties = amazonProperties; this.counterService = counterService; this.gaugeService = gaugeService; } ... @RequestMapping(method=RequestMethod.POST) public String addToReadingList(Reader reader, Book book) { book.setReader(reader); readingListRepository.save(book); counterService.increment("books.saved"); gaugeService.submit("books.last.saved", System.currentTimeMillis()); return "redirect:/"; } } 儘管CounterService和GaugeService用起來很簡單,但還是有一些度量值很難通過增加計數器或記錄指標值來捕獲。對於那些情況,我們可以實現PublicMetrics介面,提供自己需要的度量資訊。該介面定義了一個metrics()方法,返回一個Metric物件的集合:為了解PublicMetrics的使用方法,這裡假設我們想報告一些源自Spring應用程式上下文的度量值——應用程式上下文啟動的時間、 Bean及Bean定義的數量,這些都包含進來會很有意思。順便再報告一下添加了@Controller註解的Bean的數量 。 @Component public class ApplicationContextMetrics implements PublicMetrics { private ApplicationContext context; @Autowired public ApplicationContextMetrics(ApplicationContext context) { this.context = context; } @Override public Collection<Metric<?>> metrics() { List<Metric<?>> metrics = new ArrayList<Metric<?>>(); metrics.add(new Metric<Long>("spring.context.startup-date", context.getStartupDate())); metrics.add(new Metric<Integer>("spring.beans.definitions", context.getBeanDefinitionCount())); metrics.add(new Metric<Integer>("spring.beans", context.getBeanNamesForType(Object.class).length)); metrics.add(new Metric<Integer>("spring.controllers", context.getBeanNamesForAnnotation(Controller.class).length)); return metrics; } } .1.4.建立自定義跟蹤倉庫; 預設情況下, /trace端點報告的跟蹤資訊都儲存在記憶體倉庫裡, 100個條目封頂。一旦倉庫滿了,就開始移除老的條目,給新的條目騰出空間。在開發階段這沒什麼問題,但在生產環境中,大流量會造成跟蹤資訊還沒來得及看就被丟棄 @Service public class MongoTraceRepository implements TraceRepository { private MongoOperations mongoOps; @Autowired public MongoTraceRepository(MongoOperations mongoOps) { this.mongoOps = mongoOps; } @Override public List<Trace> findAll() { return mongoOps.findAll(Trace.class); } @Override public void add(Map<String, Object> traceInfo) { mongoOps.save(new Trace(new Date(), traceInfo)); } } 如果你用的是Maven,則需要如下依賴: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> .1.5.插入自定義健康指示器; Actuator自帶了很多健康指示器,能滿足常見需求,比如報告應用程式使用的資料庫和訊息代理的健康情況。但如果你的應用程式需要和一些沒有健康指示器的系統互動,我們的閱讀列表裡有指向Amazon的圖書連結,可以報告一下Amazon是否可以訪問。當然,Amazon不太可能宕機,但不怕一萬就怕萬一,所以讓我們為Amazon建立一個健康指示器吧。 @Component public class AmazonHealth implements HealthIndicator { @Override public Health health() { try { RestTemplate rest = new RestTemplate(); rest.getForObject("http://www.amazon.com", String.class); return Health.up().build(); } catch (Exception e) { return Health.down().build(); } } } AmazonHealth類並沒有什麼花哨的地方。 health()方法只是使用Spring的RestTemplate,向Amazon首頁發起了一個GET請求。如果請求成功,則返回一個表明Amazon狀態為UP的Health物件。如果請求發生異常,則health()返回一個標明Amazon狀態為DOWN的Health物件,除了簡單的狀態之外,如果你還想向健康記錄裡新增其他附加資訊,可以呼叫Health構造器的withDetail()方法。例如,要新增異常訊息,將其作為健康記錄的reason欄位,可以讓catch塊返回這樣一個Health物件: return Health.down().withDetail("reason", e.getMessage()).build();