通過Spring Boot Actuator匯出metrics到InfluxDB和Prometheus

精選.png
Spring Boot Actuator是Spring Boot 2釋出後最改進的專案之一。它已經通過了主要的改進,旨在簡化定製,包括一些新的功能,例如對其他Web技術的支援,例如新的反應式模組——SpringWebFlux。它還增加了對將度量匯出到influxdb的開箱即用支援,influxdb是一個開源時間序列資料庫,設計用於處理大量時間戳資料。與使用SpringBoot1.5的版本相比,這確實是一個很大的簡化。您可以通過閱讀我以前的文章中的一篇使用grafana和influxdb定製度量視覺化來了解自己的價值。我在這裡描述瞭如何使用@exportmetricswriter bean將Spring引導執行器生成的度量匯出到influxdb。示例Spring引導應用程式可用於分支主伺服器中關於Github儲存庫示例Spring Graphite( https://github.com/piomin/sample-spring-graphite.git )的文章。在當前的文章中,我建立了spring2分支( https://github.com/piomin/sample-spring-graphite/tree/spring2 ),它演示瞭如何使用2.0版的Spring Boot和Spring Boot Actuator實現相同的功能。
此外,我將向您展示如何將相同的度量匯出到另一個流行的監控系統,以有效地儲存時間序列資料-prometheus。infloxdb和prometheus之間的輸出度量模型有一個主要的區別。第一個是基於推的系統,第二個是基於拉的系統。因此,我們的示例應用程式需要主動地將資料傳送到influxdb監控系統,而使用prometheus,它只需要公開將定期獲取資料的端點。讓我們從influxdb開始。
1. Running InfluxDB
第一步對於我的例子來說是典型的——我們將執行帶有influxdb的docker容器。這是在本地計算機上執行influxdb並通過8086埠公開HTTP API的最簡單命令。
$ docker run -d --name influx -p 8086:8086 influxdb
一旦我們啟動了這個容器,您可能會想在那裡登入並執行一些命令。沒什麼簡單的,只要執行下面的命令就可以了。登入後,您應該看到目標Docker容器上執行的influxdb版本。
$ docker exec -it influx influx Connected to http://localhost:8086 version 1.5.2 InfluxDB shell version: 1.5.2
第一步是建立資料庫。正如您可能猜測的那樣,可以使用命令create database來實現TT。然後切換到新建立的資料庫。
$ create database springboot $ use springboot
你對這個語義熟悉嗎?是的,influxdb提供了與SQL非常相似的查詢語言。它被稱為inluxql,允許您定義select語句、group by或into子句等等。但是,在執行這樣的查詢之前,我們應該將資料儲存在資料庫中,對嗎?現在,讓我們繼續下一步,以生成一些測試度量。
2. 整合 Spring Boot 應用和InfluxDB
如果micrometer-registry-influx加入專案的依賴項,將自動啟用到influxdb的匯出。當然,我們還需要包括Spring Boot Actuator。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-influx</artifactId> </dependency>
唯一要做的就是重寫influxdb的預設地址,因為我們正在VM上執行influxdb docker容器。預設情況下,Spring引導資料嘗試連線名為mydb的資料庫。但是,我已經建立了資料庫SpringBoot,所以我也應該覆蓋這個預設值。在SpringBoot的版本2中,所有與 Spring Boot Actuator endpoints相關的配置屬性都已移到Management.*部分。

圖片.png
在啟動SpringBoot應用程式之後,類路徑中包含了actuator,您可能會有點驚訝,因為它預設只公開兩個HTTP端點/actuator/info和/actuator/health。這就是為什麼在最新版本的SpringBoot中,除了/health和/info之外的所有執行器在預設情況下都是禁用的,用於安全目的。要啟用所有執行器enpoint,必須將property management.endpoints.web.exposure.include設定為“*”。
在最新版本的Spring引導中,對HTTP度量的監視得到了顯著的改進。我們可以通過將property management.metrics.web.server.auto-time-requests設定為true來收集所有Spring MVC度量。或者,當它設定為false時,您可以通過用@timed對其進行註釋來為特定的REST控制器啟用度量。您還可以在控制器內註釋單個方法,以僅為特定端點生成度量。

圖片.png
3. 建立Spring Boot
SpringBoot的示例Spring引導應用程式由單個控制器組成,該控制器實現用於操作人員實體、儲存庫bean和實體類的基本CRUD操作。應用程式使用提供CRUD實現的SpringDataJPA儲存庫連線到MySQL資料庫。這是控制器類。
@RestController @Timed public class PersonController { protected Logger logger = Logger.getLogger(PersonController.class.getName()); @Autowired PersonRepository repository; @GetMapping("/persons/pesel/{pesel}") public List findByPesel(@PathVariable("pesel") String pesel) { logger.info(String.format("Person.findByPesel(%s)", pesel)); return repository.findByPesel(pesel); } @GetMapping("/persons/{id}") public Person findById(@PathVariable("id") Integer id) { logger.info(String.format("Person.findById(%d)", id)); return repository.findById(id).get(); } @GetMapping("/persons") public List findAll() { logger.info(String.format("Person.findAll()")); return (List) repository.findAll(); } @PostMapping("/persons") public Person add(@RequestBody Person person) { logger.info(String.format("Person.add(%s)", person)); return repository.save(person); } @PutMapping("/persons") public Person update(@RequestBody Person person) { logger.info(String.format("Person.update(%s)", person)); return repository.save(person); } @DeleteMapping("/persons/{id}") public void remove(@PathVariable("id") Integer id) { logger.info(String.format("Person.remove(%d)", id)); repository.deleteById(id); } }
在執行應用程式之前,我們已經設定了mysql資料庫。最方便的實現方法是通過mysql docker image。下面的命令執行帶有資料庫grafana的容器,定義使用者和密碼,並在Mysql上公開33306埠。
docker run -d --name mysql -e MYSQL_DATABASE=grafana -e MYSQL_USER=grafana -e MYSQL_PASSWORD=grafana -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -p 33306:3306 mysql:5
然後我們需要在應用程式端設定一些資料庫配置屬性。由於將spring.jpa.properties.hibernate.hbm2ddl.auto屬性設定為更新,所有必需的表都將在應用程式啟動時建立。

圖片.png
4。生成metrics
在啟動應用程式和所需的Docker容器之後,唯一需要做的就是生成一些測試統計資訊。我建立了JUnit測試類,它生成一些測試資料,並在迴圈中呼叫應用程式公開的端點。這是那個測試方法的片段。
int ix = new Random().nextInt(100000); Person p = new Person(); p.setFirstName("Jan" + ix); p.setLastName("Testowy" + ix); p.setPesel(new DecimalFormat("0000000").format(ix) + new DecimalFormat("000").format(ix%100)); p.setAge(ix%100); p = template.postForObject("http://localhost:2222/persons", p, Person.class); LOGGER.info("New person: {}", p); p = template.getForObject("http://localhost:2222/persons/{id}", Person.class, p.getId()); p.setAge(ix%100); template.put("http://localhost:2222/persons", p); LOGGER.info("Person updated: {} with age={}", p, ix%100); template.delete("http://localhost:2222/persons/{id}", p.getId());
現在,讓我們回到步驟1。您可能還記得,我已經向您展示瞭如何在influxdb docker容器中執行influx客戶機。工作幾分鐘後,測試單元應該多次呼叫暴露的端點。我們可以檢查儲存在influx上的metric http_server_請求的值。下面的查詢返回在過去3分鐘內收集的測量值列表。

圖片.png
如您所見,所有由Spring引導執行器生成的度量都用以下資訊標記:方法、URI、狀態和異常。由於有了這些標籤,我們可以很容易地對每個簽名端點的度量進行分組,包括失敗和成功百分比。讓我們看看如何在grafana中配置和檢視它。
5.使用Gravana實現度量視覺化
一旦我們成功地將度量匯出到influxdb,現在是時候使用grafana視覺化它們了。首先,讓我們用grafana執行docker container。
$ docker run -d --name grafana -p 3000:3000 grafana/grafana
Grafana為建立流入查詢提供了使用者友好的介面。我們定義了一個圖形,它視覺化每個呼叫端點的請求處理時間和應用程式接收的請求總數。如果我們按方法型別和URI過濾儲存在表http_server_請求中的統計資訊,我們將收集每個端點生成的所有度量。

圖片.png
應為其他端點建立類似的定義。我們將在一個圖表上對它們進行說明。

圖片.png
這是最後的結果。

圖片.png
下面是視覺化傳送到應用程式的請求總數的圖表。

圖片.png
6. 執行Prometheus
在本地執行Prometheus最合適的方法顯然是通過碼頭集裝箱。API暴露在埠9090下。我們還應該傳遞初始配置檔案和Docker網路的名稱。為什麼?您將在本步驟描述的下一部分中找到所有答案。
docker run -d --name prometheus -p 9090:9090 -v /tmp/prometheus.yml:/etc/prometheus/prometheus.yml --network springboot prom/prometheus
與influxdb不同,prometheus從應用程式中提取度量。因此,我們需要啟用為普羅米修斯公開度量的執行器端點,這在預設情況下是禁用的。要啟用它,請將property management.endpoint.prometheus.enabled設定為true,如下面的配置片段所示。

圖片.png
然後我們應該在prometheus配置檔案中設定應用程式公開的執行器端點的地址。scrape_配置部分負責指定一組目標和描述如何與它們連線的引數。預設情況下,prometheus嘗試每分鐘從定義的目標端點收集一次資料。

圖片.png
與整合influxdb類似,我們需要將以下工件包含到專案的依賴項中。
<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>
在我的例子中,Docker在VM上執行,並且在IP 192.168.99.100下可用。如果我希望prometheus能夠連線我的應用程式,它作為docker容器啟動,我也應該作為docker容器啟動它。連線兩個獨立容器最方便的方法是通過Docker網路。如果兩個容器都被分配到同一個網路,它們將能夠使用容器的名稱作為目標地址彼此連線。Dockerfile在示例應用程式原始碼的根目錄中可用。下面可見的第二個命令(docker build)不是必需的,因為我的docker hub儲存庫中提供了必需的image piomin/person服務。
$ docker network create springboot $ docker build -t piomin/person-service . $ docker run -d --name person-service -p 2222:2222 --network springboot piomin/person-service
7.整合prometheus和Grafana
prometheus在地址192.168.99.100:9090下公開了Web控制檯,您可以在其中指定帶有度量的查詢和顯示圖形。但是,我們可以將它與Grafana整合,以利用該工具提供的更好的視覺化效果。首先,您應該建立普羅米修斯資料來源。

圖片.png
然後,我們應該定義從PrometheusAPI收集度量的查詢。Spring Boot Actuator公開了與HTTP流量相關的三個不同指標:http_server_requests_seconds_count、http_server_requests_seconds_sum和http_server_requests_seconds_max。例如,我們可以計算http_server_requests_seconds_sum的每秒平均時間序列增長率,該值返回所花費的總秒數。使用rate()函式處理請求。可以使用內的表示式按方法和URI篩選值。下圖說明了每個端點的rate()函式的配置。

圖片.png
這是圖表。

圖片.png
總結
在SpringBoot的1.5和2.0版本之間,度量生成的改進是顯著的。現在將資料匯出到流行的監控系統(如infloxdb或prometheus)比以前容易得多,不需要任何額外的開發。與HTTP流量相關的度量更加詳細,並且由於標記指示HTTP請求的URI、型別和狀態,它們可能很容易與特定端點關聯。我認為,與以前版本的SpringBoot相比,SpringBoot執行器中的修改可能是將應用程式遷移到最新版本的主要動機之一。