跳至主要內容

MicroProfile Health・服務健康嗎?

不曉得大家在開發 REST API 的時候,是否碰到過被反應服務出狀況,但是從 VM 監控上又看不出個所以然來,簡單的寫個 echo API 又不足以代表應用的實際負載程度,怎麼辦?
每個人應該會有不同的實作方法,首先要定義 API,然後實作各種檢查,最後一個一個匯總起來,最後透過 API 來判斷服務是否正常運作。

我相信大家也是這麼做的,這的確是很好的解決方案!但既然已經能自行解決,那麼 MicroProfile Health(後簡稱 MPHealth)是想幫助開發者解決什麼問題呢?
MPHealth 對開發者來說,主要是提供框架讓開發者可以省去定義 API 及開放 API 的困擾,只要專心在實作各種檢查就好。


存取服務健康 REST API

和 MPOpenAPI 一樣,部署應用啟動的同時,MPHealth 的機制已經啟動了,可以透過以下端點存取:

  • /health/ready => 服務是否準備就緒

  • /health/live => 服務是否正常運作

  • /health => 為了相容性而保留的舊版規格,會匯總 ready 和 live 的內容

實際上透過瀏覽器去連結會取得以下的 JSON:

{
  "status": "UP",
  "checks": []
}

因為沒有實作任何檢查,所以預設情況下,取得的資料就是 UP 正常運作的狀態。

實作健康檢查

依照 MPHealth 的定義,健康分為兩種:

  1. Readiness => 服務是否準備就緒,對應回 /health/ready

  2. Liveness => 服務是否正常運作,對應回 /health/live

規格中,並沒有要求或建議各別該實作哪些檢查,而是提供了便利實作這些檢查的 @annotation 和 API。判斷及實作 Readiness/Liveness 該具備哪些檢查邏輯,因應各應用需求會有所不同,這些就是我們開發人員的工作啦!

使用 MPHealth 實作健康檢查很簡單,只要把握以下幾個重點:

  • @Readiness => 用來標註是用作檢查是否準備就緒

  • @Liveness => 用來標註是用作檢查是否正常運作

  • HealthCheck => 用來實作健康檢查邏輯的 interface

  • HealthCheckResponse => 健康檢查的回傳值

接下來,就來寫寫看!

// Java Code
@Readiness
@ApplicationScoped
public class MPHealthReadiness implements HealthCheck {

    @Override
    public HealthCheckResponse call() {
        return HealthCheckResponse.named("Environment")
            .withData("DB", true)
            .withData("DB-Connection", 10)
            .state(true)
            .build();
    }
}

是不是很簡單?
只要實作 HealthCheck,把邏輯填入,然後標註 @Readiness 就會被列入準備就緒檢查。回傳數值中可以透過 withData(key, value) 加入各種資料,依照需求填入對準備就緒檢查有必要的數值。開發者撰寫邏輯來判斷是否要通過檢查並填入 state(up),true 代表通過,若不需要判斷也可以直接使用 up() 或 down() 來代表通過或失敗。

讓我們來看看呼叫 /health/ready 的結果:

{
  "status": "UP",
  "checks": [
    {
      "name": "Environment",
      "status": "UP",
      "data": {
        "DB-Connection": "10",
        "DB": "true"
      }
    }
  ]
}

這次因為有實作檢查,所以有數值了!內容就如同程式碼中所撰寫的呈現在結果之中。

在此說明幾個重點:

  • @Liveness 的用法和 @Readiness 完全相同

  • 所有標註為 @Readiness 或 @Liveness 的檢查,其結果會個別被匯總到對應的 REST API

    • 開發者可以去規劃怎麼管理檢查實作邏輯

  • 不保證檢查被呼叫的順序,所以請確保單一檢查的完整性

一種檢查一個 class,好似沒什麼問題,保有了最佳的彈性,但是一個檢查一個 class 有時在管理上也不是那麼的方便。若是這種情況,MPHealth 也提供了另一種實作方法來達成。

@ApplicationScoped
public class MPHealthPractice {

    @Produces
    @Liveness
    public HealthCheck liveCheck1() {
        return () -> HealthCheckResponse.named("I am lived")
            .state(true)
            .build();
    }

    @Produces
    @Liveness
    public HealthCheck liveCheck2() {
        return new HealthCheck() {
            @Override
            public HealthCheckResponse call() {
                return HealthCheckResponse.named("I am also lived")
                    .state(true).build();
            }
        };
    }
}

用這種寫法就可以方便統一管理同一類型的數個檢查,實際上還是實作了 HealthCheck 再透過 CDI 的 @Produces 提供給 MPHealth 框架。
至於要採用 lambda 或 anonymous inner class 來撰寫,就端看個人。

REST API Status Code

在這要建議大家若要使用 MPHealth,請務必參照其中的 Response Codes and status mappings。

幫忙大家做個簡單的總結,若 HTTP Status 是:

  1. 200 => UP 正常,包含 payload

  2. 503 => DOWN 異常,包含 payload

  3. 500 => 無法判斷的異常,無 payload

若要自己透過 REST API 來確認伺服器狀態,最簡單的判斷方式就是 200 才是正常情況,接下來才考慮各數值的狀態。


文末,做個簡單的結語,

MPHealth 提供了一個極容易使用的機制讓開發者實作服務的健康檢查,同時 REST API 的包裝也被包含在此機制之中。若有監控服務的需求,可以考慮採用此框架簡化開發邏輯。由於是公開規格,若廠商支援也可以順利自動整合。為了更穩健的提供服務,有何道理不採用呢?

by Arren Ping

回到頂端 ↑