1. 程式人生 > >SpringBoot實戰(深入Actuator)讀書筆記

SpringBoot實戰(深入Actuator)讀書筆記

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();