gRPC 健康检查协议

FreeGuideOnline 最新 2026-07-13

protobuf syntax = "proto3";

package grpc.health.v1;

message HealthCheckRequest { string service = 1; }

message HealthCheckResponse { enum ServingStatus { UNKNOWN = 0; SERVING = 1; NOT_SERVING = 2; } ServingStatus status = 1; }

service Health { rpc Check(HealthCheckRequest) returns (HealthCheckResponse); rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); }


#### 两个核心方法

##### Check(单次检查)

客户端发送一个 `HealthCheckRequest`,其中 `service` 字段指定要检查的服务名称。如果服务名称为空字符串,则表示检查**整个 gRPC 服务器**的整体健康状态。服务器返回当前瞬间的状态。

##### Watch(流式监视)

与 `Check` 使用相同的请求参数,但响应是一个**服务器端流**。一旦调用,服务器会持续发送健康状态更新(例如状态从 `SERVING` 变为 `NOT_SERVING` 时立即推送)。这种方法避免了客户端轮询,对负载均衡器和边车代理特别有用。

### ServingStatus 状态码详解

服务端返回的状态包含三种可能,理解它们对正确配置探针至关重要:

- **`UNKNOWN (0)`**:服务状态未知。这通常出现在服务启动初期,尚未完成初始化,或者客户端查询了一个服务器不认识的 `service` 名称。负载均衡器应当将其视为不可用。
- **`SERVING (1)`**:服务正常,可以接受请求。对于空 `service` 参数,表示整个服务器健康;对于特定服务,则表示该已注册的服务就绪。
- **`NOT_SERVING (2)`**:服务明确表示不能处理请求。可能因为正在进行优雅关闭、依赖的下游服务不可用、或服务自身出现不可恢复的错误。收到此状态后,客户端应停止将请求路由至此实例。

### 服务端实现指引

所有主流 gRPC 语言实现都提供了健康检查协议的官方或半官方库,开发者只需创建健康服务实例并注册到现有 gRPC 服务器即可。下面以 Go 和 Java 为例展示典型写法。

#### Go 语言实现

```go
import (
    "google.golang.org/grpc"
    "google.golang.org/grpc/health"
    healthpb "google.golang.org/grpc/health/grpc_health_v1"
)

func main() {
    s := grpc.NewServer()
    
    // 创建健康服务
    hs := health.NewServer()
    
    // 注册健康服务到 gRPC 服务器
    healthpb.RegisterHealthServer(s, hs)
    
    // 对于服务名为空(整体服务器状态),设置为 SERVING
    hs.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
    
    // 对于特定服务 "myapp.EchoService" 设置状态
    hs.SetServingStatus("myapp.EchoService", healthpb.HealthCheckResponse_SERVING)
    
    // 监听并启动...
}

health.NewServer() 返回的对象提供 SetServingStatus(service string, status healthpb.HealthCheckResponse_ServingStatus) 方法,可在服务生命周期的不同阶段动态调用(例如初始化完成后设为 SERVING,开始优雅关闭时设为 NOT_SERVING)。

Java 语言实现

import io.grpc.protobuf.services.HealthStatusManager;
import io.grpc.services.HealthStatusManager.ServingStatus;
import io.grpc.services.HealthCheck;

public class MyGrpcServer {
    public static void main(String[] args) {
        Server server = ServerBuilder.forPort(50051)
            .addService(new MyServiceImpl())
            .build();
        
        HealthStatusManager health = new HealthStatusManager();
        health.setStatus("", ServingStatus.SERVING);
        health.setStatus("myapp.EchoService", ServingStatus.SERVING);
        server.getServices().add(health.getHealthService());
        
        server.start();
        // ...
    }
}

Java 的 HealthStatusManager 使用方式类似,通过 setStatus 更新状态。一些高级框架(如 Spring Boot + gRPC)会自动集成健康检查服务,开发者只需配置即可。

客户端使用与集成场景

作为普通 gRPC 客户端调用

任何 gRPC 客户端都可以直接调用健康检查服务来探测目标服务器。例如,在服务发现时,先执行一次 Check,只将 SERVING 状态的实例加入可用列表。或者使用 Watch 流长期跟踪状态变化,及时摘除不健康的实例。

Kubernetes gRPC 探针

从 Kubernetes 1.24 开始,Pod 的存活和就绪探针原生支持 gRPC。无需额外使用 exec 脚本或 HTTP 端口,只需在 Pod 定义中指定:

apiVersion: v1
kind: Pod
metadata:
  name: my-grpc-app
spec:
  containers:
  - name: server
    image: my-grpc-image
    ports:
    - containerPort: 50051
    startupProbe:
      grpc:
        port: 50051
      failureThreshold: 30
      periodSeconds: 10
    livenessProbe:
      grpc:
        port: 50051
    readinessProbe:
      grpc:
        port: 50051
      initialDelaySeconds: 5