在微服務架構中,我們將原本龐大的單體系統拆分成多個提供不同服務的應用。 雖然 各個應用的內部邏輯因分解而得以簡化,但是由於部署應用的數量成倍增長,使得系統的 維護復雜度大大提升。 對於運維人員來說,隨着應用的不斷增多,系統集群中出現故障的 頻率也變得越來 越高,雖然在高可用機制的保護下,個別故障不會影響系統的對外服務, 但是這些頻繁出現的故障需要被及時發現和處理才能長期保證系統處千健康可用狀態。 為 了能對這些成倍增長的應用做到高效運維,傳統的運維方式顯然是不合適的,所以我們需 要實現一套自動化的監控 運維機制,而這套機制的運行基礎就是不間斷地收集各個微服務 應用的各項 指標情況,並根據這些基礎指標信息來制定監控和預警規則,更進一步甚至做 到一些自動化的運維操作等。
為了讓運維系統能夠獲取各個微服務應用的相關指標以及實現一些常規操作控制,我 們需要開發一套專門用於植入各個微服務應用的接口供監控 系統采集信息。 而這些接口往 往有很大一 部分指標都是類似的, 比如環境變量、 垃圾收集信息、 內存信息、 線程池信息 等。 既然這些信息那么通用,難道就沒有一個標准化的實現框架嗎?
當我們決定用Spring Boot來作為微服務框架時,除了它強大的快速開發功能之外,還因 為它在Starter POMs中提供了一個特殊依賴模塊spring-boot-starter-actuator 。引入該模塊能夠自動為 Spring Boot 構建的應用提供 一系列用千監控的端點。 同時, Spring Cloud 在實現各個微服務組件的時候, 進 一步為該模塊做了不少擴展, 比如, 為原生端點 增加了更多的指標和度量信息(比如在整合 Eureka 的時候會為/health 端點增加相關的 信息), 並且根據不同的組件還提供了更多有空的端點(比如, 為 API 網關組件 Zuul 提供 了 /routes 端點來返回路由信息)。
spring-boot-starter-actuator 模塊的實現對千實施微服務的中小團隊來說, 可以有效地省去或大大減少監控系統在采集應用指標時的開發量。 當然, 它也並不是萬能 的, 有時候也需要對其做 一些簡單的擴展來幫助我們實現自身系統個性化的監控需求。 所 以,在本節將詳細介紹一些關於spring-boot-starter-actuator模塊的內容, 包括 原生提供的端點以及一些常用的擴展和配置方式等。
在現有 的 Spring Boot 應用中引入該模塊非常簡單 , 只需要 在 pom.xml 的 dependency 節點中,新增 spring-boot-starter-actua七or 的依賴即可,具體如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
增加該依賴之后,重新啟動應用。此時,我們可以在控制台中看到如下圖所示的輸出:
: Mapped "{[/trace i I /trace.json],methods=(GET),produces=[applicat10n
: Mapped "{[/info 11 /info.json],methods=[GET},produces=[application/j
: Mapped " { [ / env / {name: , •}], methods=[ GET), produces= [ application/json)}
: Mapped "{[/env 11 /env.json],methods=[GET),produces=[application/jso
: Mapped "{[/dump 11 /dump.json],methods=[GET),produces=[application/j, Mapped "([/autoconfig 11 /autoconfig.json],rnethods=[GET),produces=[a
: Mapped "{[/health 11 /health.json],produces=[application/json)}" ont
: Mapped "{[/mappings 11 /mappings.json],methods=(GET],produces=(appli
: Mapped "{[/beans 11 /beans.json],methods=[GET),produces=[application
: Mapped "{[/configprops 11 /configprops.json],methods=[GET),produces=
: Mapped "{[/metrics/{name:. 不}],methods=(GET),produces=[application/js
: Mapped "{[/metrics 11 /metrics.json],methods=[GET),produces=(applica
原生端點
通過在快速入門示例中添加spring-boot-starter-actuator模塊, 我們已經對 它有了 一個初步的認識。接下來,我們詳細介紹一下 spring-boot-starter-actuator模塊中已經實現的一些原生端點。 根據端點的作用, 可以將原生端點分為以下三大類。
• 應用配置類:獲取應用程序中加載的應用配置、 環境變量、 自動化配置報告等與 Spring Boot應用密切相關的配置類信息。
• 度最指標類:獲取應用程序運行過程中用於監控的度量指標, 比如內存信息、 線程 池信息、 HTTP請求統計等。
• 操作控制類:提供了對應用的關閉等操作類功能。
應用配置類->由於SpringBoot為了改善傳統Spring應用繁雜的配置內容,采用了包掃描和自動化配 置的機制來加載原本集中於XML文件中的各項內容。 雖然這樣的做法讓我們的代碼變得 非常簡潔,但是整個應用的實例創建和依賴關系等信息都被離散到了各個配置類的注解上, 這使我們分析整個應用中資源和實例的各種關系變得非常困難。 而這類端點可以幫助我們 輕松獲取一系列關於 Spring 應用配置內容的詳細報告, 比如自動化配置的報告、 Bean創 建的報告、 環境屬性的報告等。
/autoconfig:該端點用來獲取應用的自動化配置報告, 其中包括所有自動化配置的 候選項。 同時還列出了每個候選項是否滿足自動化配置的各個先決條件。 所以, 該 端點可以幫助我們方便地找到一些自動化配置為什么沒有生效的具體原因。 該報告 內容將自動化配置內容分為以下兩部分。
positiveMatches中返回的是條件匹配成功的自動化配置。
negativeMatches中返回的是條件匹配不成功的自動化配置。
/beans:該端點用來獲取應用上下文中創建的所有Bean。
Bean 中都包含了下面這些信息:
• bean: Bean 的名稱。
• scope: Bean 的作用域。
• type: Bean 的 Java 類型。
• resource: class 文件的具體路徑。
• dependencies: 依賴的 Bean 名稱。
/configprops:該端點用來獲取應用中配置的屬性信息報告。 從下面該端點返回示例 的片段中, 我們看到返回了關於該短信的配置信息, prefix 屬性代表了屬性的配 置前綴, properties 代表了各個屬性的名稱和值。 所以, 我們可以通過該報告來 看 到各個屬性的 配 置路 徑, 比如我們要關閉該端點, 就可 以 通過使用 endpoints.configprops.enabled=false 來完成設置。
/env: 該端點與/configprops不同它用來獲取應用所有可用的環境屬性報告。 包括 環境變量、NM屬性、應用的配置屬性、命令行中的參數。 從下面該端點返回的示 例片段中, 可以看到它不僅返回了應用的配置屬性, 還返回了系統屬性、環境變量 等豐富的配置信息, 其中還包括了應用還沒有使用的配置, 所以它可以幫助我們方 便地看到當前應用可以加載的配置信息, 並配合@ConfigurationProperties 注解將它們引入到我們的應用程序中來進行使用。 另外, 為了配置屬性的安全, 對 於一些類似密碼等敏感信息, 該端點都會進行隱私保護, 但是我們需要讓屬性名中 包含password、secret、key這些關鍵詞, 這樣該端點在返回它們的時候會使用*來替代實際的屬性值。
/mappings: 該端點用來返回所有Spring MVC的控制器映射關系報告。 從下面的示 例片段中, 我們可以看到該報告的信息與我們在啟用Spring MVC的Web應用時輸 出的日志信息類似, 其中bean屬性標識了該映射關系的請求處理器, method屬 性標識了該映射關系的具體處理類和處理函數。
/info: 該端點用來返回一些應用自定義的信息。 默認清況下, 該瑞點只會返回 一個 空的JSON內容。我們可以在application.properties配置文件中通過info 前綴來設置一些屬性, 比如下面這樣: info.app.name=spring-boot-hello
info.app.version=vl.0.0
再訪問/info端點我們可以得到下面的返回報告, 其中就包含了上面我們在應用 中自定義的兩個參數。
"app": {
"name": "spring-boot-hello",
"version": "vl.0.0"
}
2、度量指標類-->上面我們所介紹的應用配置類端點所提供的信息報告在應用啟動的時候就已經基本確 定了其返回內容, 可以說是一個靜態報告。 而度量指標類端點提供的報告內容則是動態變 化的,這些端點提供了應用程序在運行過程中的一些快照信息,比如內存使用情況、 HTTP 請求統計、外部資源指標等。這些端點對於我們構建微服務架構中的監控系統非常有幫助, 由於 Spring Boot 應用自身實現了這些端點,所以我們可以很方便地利用它們來收集我們想 要的信息, 以制定出各種自動化策略。
/metrics: 該端點用來返回當前應用的各類重要度量指標,比如內存信息、線程信息、 垃圾回收信息等。
{
"mem":1292717,
"mem.free":703542,
"processors":32,
"instance.uptime":245161086,
"uptime":245165938,
"systemload.average":0,
"heap.committed":1238016,
"heap.init":1026744,
"heap.used":534473,
"heap":14603776,
"nonheap.committed":55232,
"nonheap.init":24000,
"nonheap.used":54701,
"nonheap":133120,
"threads.peak":28,
"threads.daemon":23,
"threads.totalStarted":296,
"threads":26,
"classes":8854,
"classes.loaded":8854,
"classes.unloaded":0,
"gc.ps_scavenge.count":4,
"gc.ps_scavenge.time":163,
"gc.ps_marksweep.count":0,
"gc.ps_marksweep.time":0,
"httpsessions.max":-1,
"httpsessions.active":0,
"counter.status.200.aliPay.createOrderANdAliPayUrl":4,
"counter.status.200.aliPay.notifyUrl":2,
"counter.status.200.atOnceWithhold":12,
"counter.status.200.autoconfig":1,
"counter.status.200.metrics":1,
"counter.status.200.withhold":254,
"counter.status.405.unmapped":2,
"gauge.response.aliPay.createOrderANdAliPayUrl":35,
"gauge.response.aliPay.notifyUrl":481,
"gauge.response.atOnceWithhold":10046,
"gauge.response.autoconfig":35,
"gauge.response.metrics":19,
"gauge.response.unmapped":6,
"gauge.response.withhold":16
}
從上面的示例中, 我們看到有如下這些重要的度量值。
• 系統信息:包括處理器數量processors、運行時間up巨me和instance.uptime、 系統平均負載 systemload.average。
• mem. *: 內存概要信息,包括分配給應用的總內存數量以及當前空閑的內存數量。 這些信息來自java.lang.Runtime。
• heap.* : 堆內存使用情況。 這些信息來自 java.lang.management. MemoryMXBean 接口中 getHeapMemoryUsage 方法獲取的 java.lang. management.MemoryUsage。
• nonheap. *: 非堆內存使用情況。 這些信息來自 java. lang.management. MemoryMXBean接口中getNonHeapMemoryUsage方法獲取的java.lang. managemen.MemoryUsage。
• threads.*: 線程使用情況,包括線程數、守護線程數(daemon)線程峰值(peak) 等, 這些數據均來自java.lang.management.ThreadMXBean。
• classes.*: 應用加載和卸載的類統計。這些數據均來自java.lang.managemen七. ClassLoadingMXBean。
• gc. *: 垃圾收集器的詳細信息,包括垃圾回收次數gc.ps—scavenge.coun七、 垃圾回收消耗時間 gc.ps_scavenge.time、 標記-清除算法的次數 gc.ps marksweep.count、 標記-清除算法的消耗時間gc.ps_marksweep.time。 這些數據均來自java.lang.managemen.GarbageCollectorMXBean。
• httpsessions. * : Tomcat容 器 的會話使用情況。 包 括最大會話 數 httpsessions.max和活躍會話數httpsessions.ac巨ve。 該度量指標信 息僅在引入嵌入式Tomcat作為應用容器的時候才會提供。
• gauge.*: HTTP請求的性能指標之一,它主要用來反映一個絕對數值。 比如上 面示例中的gauge.response.hello: 5, 它表示上 一 次hello請求的延遲 時間為5毫秒。
• counter.*: HTTP 請求的性能指標之一,它主要作為計 數器來使用,記錄了 增加量和減少量。 上述示例中的counter.status.200.hello: 11, 它代表 了 hello請求返回200狀態的次數為11。
/metrics端點可以提供應用運行狀態的完整度量指標報告,這項功能 非常實用,但是 對千監控系 統中的各項監控功能,它們的監控內容、 數據收集頻率都有所不同,如 果每次都通過全量獲取報告的方式來收集,略顯粗暴。 所以,我們還可以通過 /metrics/{name}接口來更細粒度地獲取度量信息 , 比 如可 以通 過訪 問 /metrics/mem.free來獲取當前可用 內存數量。
curl -i http://****:8081/metrics/mem.free
{
"mem.free":1447714
}
/health: 該端點在一開始的示例中 我們已經使用過了,它用來獲取應用的各類 健康 指標信息。在spring-boot-starter-actuator模塊中自帶實現了 一些常用資 源的健康指標檢測器。這些檢測器 都通過Hea巨hindicator接口實現,並且會根 據依賴關系的引入實現自動化裝配,
檢測器 功能
DiskSpaceHealthlndicator 低磁盤空間檢測
DataSourceHealthlndicator 檢測DataSource的連接是否可用
MongoHealthlndicator 檢測Mango數據庫是否可用
RabbitHealthlndicator 檢測Rabbit服務器是否可用
RedisHealthlndicator 檢測Redis服務器是否可用
SolrHealthlndicator 檢測Solr服務器是否可用
/dump: 該端點用來暴露程序運行中的線程信息。它使用 java.lang.managerment.ThreadMXBean 的 durnpAllThreads方法來返回所有含有同步信息的活動線程詳 情。
/trace: 該端點用來返回基本的 HTTP 跟蹤信息。 默認情況下, 跟蹤信息的存儲采用 org.springfrarnework.boo七.ac七uate.trace.InMernoryTraceRepository 實現的內存方式, 始終保留最近的100條請求記錄。 它記錄的內容格式如下所示:
3、操作控制類-->在原生端點中, 只提供了一個用來關閉應用的端點: /shutdown (在后續我們引入了 Eureka之后, 會引入更多控制端點)。 可以通過如下配置開啟它: endpoints.shutdown.enabled=true
在配置了上述屬性之后,只需要訪問該應用的/shutdown端點就能實現關閉該應用的 遠程操作。 由於開放關閉應用的操作 本身是一 件非常危險的事, 所以真正在線上使用的時候,需要對其加入一定的保護機制, 比如定制actuator的端點路徑、整合SpringSecurity進行安全校驗等,稍后講解Spring Cloud Eureka 微服務架構中的服務治理在進行擴展。