健康检查终端点的实现
好了好了,今天我们来实现一个像云原生应用一样的健康检查端点吧。
实用仓库/ Go 运营
我们公司虽然没有公开,但我们已经整理了每个应用程序应该实现的各种终端点作为规范。这份规范不仅包括健康检查,还包含了运营所需的一般信息,如指标等。
多亏了这个共同规范,我们能够在团队之间统一运营有用信息的公开方式。
并且还为常用的编程语言提供了相应的库,例如针对Go语言的库 utilitywarehouse/go-operational 已经公开发布。
我們將使用這個程式庫來實現端點。
新的操作处理器函数
我们将实现一个返回http.Handler的方法newOpHandler。
func newOpHandler() http.Handler {
return http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})
}
创建处理器
现在有一个名为NewHandler()的API可以用来创建一个新的控制器,你可以通过参数向其传递想要公开的信息。
想要公开的信息被抽象为*Status的形式,这个指针具有返回自身的API功能,这样可以实现链式调用方法。
首先,我们可以调用NewStatus(),并设置应用程序名称和描述。
func newOpHandler() http.Handler {
return op.NewHandler(op.NewStatus(appName, appDesc))
}
我們將在之前設置虛擬處理程序的地方設置新的處理程序。
- http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintln(w, "Hello, world")
- })
+ http.Handle("/__/", newOpHandler())
我们来看一下关于(/__/about)的端点。
$ ./qiita-advent-calendar-2019
INFO[0000] Hello, world git_hash=c9608991b89e925eaa7f335ceebe39c5342edd46
$ curl localhost:8080/__/about
{
"name": "qiita-advent-calendar-2019",
"description": "The sample micro service app",
"owners": null,
"build-info": {
"revision": ""
}
}
我确认能够获取到设定的信息。
度量衡信息
实际上,在这一时间点上已经公开了指标信息。请尝试调用/__/metrics终点。
$ curl localhost:8080/__/metrics
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
go_gc_duration_seconds{quantile="0.25"} 0
go_gc_duration_seconds{quantile="0.5"} 0
go_gc_duration_seconds{quantile="0.75"} 0
go_gc_duration_seconds{quantile="1"} 0
go_gc_duration_seconds_sum 0
go_gc_duration_seconds_count 0
...
由于Prometheus以Prometheus格式进行发布,因此在使用Prometheus时,请配置它来抓取该端点。
添加健康检查
在添加健康检查时,可以使用AddChecker() API。
将第一个参数作为健康检查项目的名称,并将第二个参数作为用于报告健康结果的函数传递。
在传递给这个函数的参数中,*CheckResponse可以公开Healthy、Degraded和Unhealthy这些方法,根据情况进行调用。这次我们将尝试以健康(Healthy)作为虚拟报告。
func newOpHandler() http.Handler {
return op.NewHandler(op.
NewStatus(appName, appDesc).
AddChecker("dummy health check", func(cr *op.CheckResponse) {
cr.Healthy("I'm healthy!")
}))
}
那么,让我们尝试访问/__/health终点。
$ curl localhost:8080/__/health
{
"name": "qiita-advent-calendar-2019",
"description": "The sample micro service app",
"health": "healthy",
"checks": [
{
"name": "dummy health check",
"health": "healthy",
"output": "I'm healthy!"
}
]
}
我可以确认报告已经按照设定进行。
其他信息的公开
由于go-operational库提供了其他有用的API,所以我将介绍其中一些。
- Readinessチェック
在Ready系列函数中,您可以实现用于准备检查的端点。您可以根据情况选择自定义定义、使用健康检查结果、始终返回Ready等方式。
func newOpHandler() http.Handler {
return op.NewHandler(op.
NewStatus(appName, appDesc).
AddChecker("dummy health check", func(cr *op.CheckResponse) {
cr.Healthy("I'm healthy!")
}).
ReadyUseHealthCheck())
}
$ curl localhost:8080/__/ready
ready
- より詳細なアプリ情報
通过AddOwner()函数添加团队信息和团队所属的Slack频道,并通过SetRevision()函数发布应用的版本信息。
func newOpHandler() http.Handler {
return op.NewHandler(op.
NewStatus(appName, appDesc).
AddOwner("qiita-advent-calendar-team", "#qiita-advent-calendar-2019").
SetRevision(gitHash).
AddChecker("dummy health check", func(cr *op.CheckResponse) {
cr.Healthy("I'm healthy!")
}).
ReadyUseHealthCheck())
}
$ curl localhost:8080/__/about
{
"name": "qiita-advent-calendar-2019",
"description": "The sample micro service app",
"owners": [
{
"name": "qiita-advent-calendar-team",
"slack": "#qiita-advent-calendar-2019"
}
],
"build-info": {
"revision": "67de87c0517ed2d477d2d27a6e2f250b2230ca93"
}
}
- ヘルスチェック結果をメトリクスとして公開
通过 WithInstrumentedChecks() 方法将健康检查的结果作为指标公开。当服务处于不健康状态时,这对于实际查明从何时开始哪个健康检查出现问题非常方便。
func newOpHandler() http.Handler {
return op.NewHandler(op.
NewStatus(appName, appDesc).
AddOwner("qiita-advent-calendar-team", "#qiita-advent-calendar-2019").
SetRevision(gitHash).
AddChecker("dummy health check", func(cr *op.CheckResponse) {
cr.Healthy("I'm healthy!")
}).
ReadyUseHealthCheck().
WithInstrumentedChecks())
}
$ curl localhost:8080/__/metrics | grep health
# HELP healthcheck_status Meters the healthcheck status based for each check and for each result
# TYPE healthcheck_status gauge
healthcheck_status{healthcheck_name="dummy_health_check",healthcheck_result="degraded"} 0
healthcheck_status{healthcheck_name="dummy_health_check",healthcheck_result="healthy"} 1
healthcheck_status{healthcheck_name="dummy_health_check",healthcheck_result="unhealthy"} 0
现在,我试着实现了这样一个健康检查。当然公开也很重要,但结合Kubernetes的健康检查机制和Prometheus一起使用时才能发挥其真正的价值。根据需要进行逐步实现是一个好办法。在这种情况下,请务必参考一下 go-operational 库。
明天开始,我想要实现gRPC功能。渐渐地感觉越来越有趣了哦?笑