这篇文章,我们不是要讲解怎么使用 gRPC-go,或者使用 gRPC 实现一个服务。而是要讲讲如何在 gRPC-go 中完成心跳检测和健康检查。
gRPC 其实已经对如何实现心跳和健康检查有了说明了,详情见 https://github.com/grpc/grpc/blob/master/doc/health-checking.md 。而且框架已现了基本的 API 且达到基本开箱即用的程度。
原则上来说,应该很简单,只是调用 API 而已。但是,实际上呢,即使努力百度和谷歌,我们还不一定能跑起来。
其中最关键的就是 如何定义心跳服务,如果你只是简单的看文档,会以为要实现一个 protobuf
服务呢。
实际上呢,并不是,我们只要定义一个独一无二的 服务名 即可。
一旦跑起来之后,就发现特别的简单,真的。
只需要以下简单三步。
1. 首先定义心跳和健康检查的服务
这个定义不是要定义一个 protobuf
而是定义一个 字符串常即可。
const HEALTHCHECK_SERVICE = "grpc.health.v1.Health"
常量名无所谓,常量的值也无所谓,至于为啥是 grpc.health.v1.Health
只是一种惯用约定而已。
2. gRPC-go 服务器端引入几个 module 和添加几行代码
import ( "google.golang.org/grpc" "google.golang.org/grpc/health" healthpb "google.golang.org/grpc/health/grpc_health_v1" )
从某些方面说就是多引入了两个包 health
和 grpc_health_v1
同时在 grpc.NewServer()
和 RegisterXXXServiceServer
的之间添加以下几行代码
s := grpc.NewServer() // 要添加的代码 --- healthserver := health.NewServer() healthserver.SetServingStatus(HEALTHCHECK_SERVICE, healthpb.HealthCheckResponse_SERVING) healthpb.RegisterHealthServer(s, healthserver) // --- pb.RegisterHelloServiceServer(s, hello)
其实就是添加了三行代码而已,服务器端的配置到此结束
3. gRPC-go 客户器端引入几个 module 和添加几行代码
import( "google.golang.org/grpc" _ "google.golang.org/grpc/health" )
其实就是多引入了了 health
而已。
同时 grpc.Dial()
方法或者 grpc.DialContext()
方法要改成下面这样的
conn, err := grpc.DialContext(ctx, r.Scheme()+"://author/project/test", grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"HealthCheckConfig": {"ServiceName": "%s"}}`,HEALTHCHECK_SERVICE)))
或
conn, err := grpc.DialContext( r.Scheme()+"://author/project/test", grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"HealthCheckConfig": {"ServiceName": "%s"}}`,HEALTHCHECK_SERVICE)))
比常见的 DialContext()
多加了
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"HealthCheckConfig": {"ServiceName": "%s"}}`,HEALTHCHECK_SERVICE))
如果你还添加了其它参数,可能就是下面这个样子
conn, err := grpc.DialContext(ctx, r.Scheme()+"://author/project/test", grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s","MethodConfig": [{"Name": [{"Service": "%s"}], "RetryPolicy": {"MaxAttempts":2, "InitialBackoff": "0.1s", "MaxBackoff": "1s", "BackoffMultiplier": 2.0, "RetryableStatusCodes": ["UNAVAILABLE", "CANCELLED"]}}], "HealthCheckConfig": {"ServiceName": "%s"}}`, roundrobin.Name, *serv, *serv)), grpc.WithInsecure())
这里面的所有方法和变量我们都遵循惯性来的,一般你都能看懂