1. 程式人生 > >如何做實時監控?—— 參考 Spring Boot 實現

如何做實時監控?—— 參考 Spring Boot 實現

隨著 微服務 的流行,相比較以前一個大型應用程式搞定所有需求,我們現在更傾向於把大型應用程式切分成多個微服務,服務之間通過 RPC 呼叫。微服務架構的好處非常多,例如穩定的服務變化較少,不會被非穩定服務所影響;不同的服務更方便交給不同的人管理;釋出、擴容等操作也更加有針對性。不過這也不是沒有代價的,額外的成本最主要的可能就是運維成本。

我們維護的一個產品,由 7 個微服務構成,它們各司其職,承擔上行、下行、同步等各類職責,我非常喜歡這種架構,但也面臨一個小小的煩惱。每次我們釋出其中一個或者多個服務,就需要去驗證服務的健康度,極限情況下,7 個服務 x (國內環境 + 國外環境)x (預釋出環境 + 生產環境),總共需要驗證 28 次!我希望有簡單、標準、自動的方式去驗證這些服務是否健康。當然,驗證健康也不是跑一個完整的迴歸測試,那是在測試環境就需要完成的事情,健康檢查基本只是關注環境是否 OK,最核心的一兩個用例是否 OK。由於部署到預釋出或者線上的程式碼,和線下測試的程式碼是一致的,因此就不需要重複驗證各種功能了,關注點應該在環境上,這一點線上和線下是有明顯區別的。至於環境區別,通常就是磁碟、資料庫、其他分散式服務等等。

此外,我還希望所有服務的健康檢查介面是完全一致的,沒有人希望檢查服務 A 的時候用 url /ok,檢查服務 B 的時候用 url /good。

我曾嘗試定義一個健康檢查協議,讓所有服務都暴露一個HTTP介面http://172.20.10.2/health.json ,返回的內容就包含這個這個服務的基本狀態。

這幾天看 Spring Boot ,發現它已經很好地集成了我想要的功能,而且看起來更簡單,因此我就直接扔掉了自己定義的協議,改而使用 Spring Boot 的方式,Spring Boot 有一個稱之為 endpoint 的概念,每個 endpoint 是一個非常簡單的 HTTP 介面,使用者可以通過 endpoint 監控 Spring Boot 應用,甚至與之互動。這其中,最簡單的 endpoint 就是 health,只要加入必要的 Spring Boot 依賴,使用者就能通過 health 檢視 Spring Boot 應用的基本狀態。

$ curl http://localhost:8080/health
{
    "status":"UP"
}

這裡我們看到服務的狀態是 UP,不過也許這個檢查太簡單了,例如我的服務依賴其他外部服務,其中一個 Tair,一個是 TFS,這兩個都是強依賴,如果它們有問題,我的服務就應該是 DOWN 的狀態,在 Spring Boot 中,可以這麼擴充套件:

@Component
public class MyHealth implements HealthIndicator {
    @Override
    public Health health() {
return new Health.Builder()
.withDetail("tair"
, "timeout") // some logic check tair .withDetail("tfs", "ok") // some logic check tfs .status("500") .down() .build(); } }

只要加入一個 bean 實現 HealthIndicator 就能實現更加全面的檢查,現在訪問 health endpoint 是這樣的:

$ curl http://localhost:8080/health
{
    "status": "DOWN",
    "tair": "timeout",
    "tfs": "ok"
}

只要在每個服務稍微實現一些基本的環境檢查,那我就可以用幾行指令碼快速地完成 7 個服務 x (國內環境 + 國外環境)x (預釋出環境 + 生產環境)的健康檢查,如果有哪個服務出問題了,定位環境問題也是非常方便的。

這種監控是實時的,這一點非常重要。在實際工作中我們其實有非常完善的系統監控平臺,平臺能提供 CPU、記憶體、磁碟、網路IO、JVM 等等各種各樣非常全面的資訊,這種平臺的優勢有歷史趨勢記錄,有彙總,有比較,劣勢就是不夠實時,通常只能看到 5 分鐘前的資料。因此,在釋出服務,擴容的時候,等待這樣的系統監控平臺反饋就不夠了。

除了 health endpoint 之外,Spring Boot 還提供了 其它10多個 endpoint ,它們都是針對運維設計的,例如可以用 shutdown endpoint 來關閉服務、用 beans endpoint 來檢視所有的 Spring Bean,下面我想詳細講一下 metrics 這個 endpoint。

預設訪問 metrics 我們能得到很多資訊,包括 JVM 的執行緒數、記憶體、GC 資料等等……,這些都是系統級別的資料,但其實我們可以通過 metrics 收集實時的業務資料,例如每分鐘使用者登陸數量、每分鐘檔案同步數量、實時的快取命中率……等等。

實現是這樣的:

@Component
public class MyMetric {
private final CounterService counterService;
private final GaugeService gaugeService;
@Autowired
public MyMetric(CounterService counterService, GaugeService gaugeService) {
this.counterService = counterService;
this.gaugeService = gaugeService;
}
public void exampleCounterMethod() {
this.counterService.increment("login.count");
// reset each minute
}
public void exampleGaugeMethod() {
this.gaugeService.submit("cache.hit", 80.0);
}
}

Spring Boot 內建了兩個 Service,CounterService 可以用來做簡單的累加累減,GaugeService 可以用來存放簡單的 double 值,資料都存放在記憶體中。

現在訪問 metrics endpoint 的效果是這樣的:

$ curl http://localhost:8080/metrics
{
"counter.login.count": 42,
"counter.status.200.beans": 1,
"counter.status.200.metrics": 9,
"counter.status.200.root": 4,
"gauge.cache.hit": 80.0,
"gauge.response.beans": 55,
"gauge.response.health": 12,
"gauge.response.metrics": 4,
...
}

Spring Boot 的 metrics endpoint 帶了很多的資訊,這裡我們只關注自定義的資料。

如果所有服務的核心業務資料都通過 metrics 暴露,我們接下來要做的無非就是通過一些資料視覺化的 JavaScript 元件訪問這些資料,做成一個 Dashboard,那我們就能通過這樣一個 Dashboard 檢視系統的實時狀態。

Spring Boot 的 Endpoints 帶著強烈的 DevOps 色彩, “you build it, you run it” ,開發不僅要關心如何實現功能,還需要關心服務在線上執行的狀態,如果缺乏實時監控,維護線上服務必然是一場噩夢。如果基於 Spring Boot 開發服務,那隻需要稍作擴充套件,實時監控就足夠用了,就算不使用 Spring Boot,類似的思路自己實現也並不複雜。

參考連結 http://docs.spring.io/spring-boot/docs/1.1.x/reference/htmlsingle/#production-ready-endpoints