10 KiB
Health Check Development Guide
本文档只定义部署稳定性需要的健康检查能力。健康检查不承载业务判断,不替代监控告警,也不用于修复故障。进程下线和 drain 细节见 docs/优雅停机.md。
Goals
健康检查必须解决三个问题:
- 负载均衡是否可以把新流量打到这个进程。
- 发布或重启时,进程是否可以安全下线。
- 多机部署时,依赖异常是否会被及时摘流,而不是继续接收请求并放大故障。
健康检查不解决这些问题:
- 不判断房间是否存在。
- 不判断用户是否有权限。
- 不扫描全量 MySQL 表。
- 不做 Redis 修复、房间恢复、outbox 补偿。
- 不在检查路径里触发业务写入。
Check Types
所有服务都必须区分 live 和 ready。
| Type | Meaning | Failure Action |
|---|---|---|
live |
进程还活着,事件循环或 gRPC/HTTP runtime 未卡死 | 由容器平台重启进程 |
ready |
当前进程可以接新流量 | 从负载均衡摘流,不一定重启 |
不要把下游短暂不可用放进 live。例如 MySQL 抖动时,room-service 应该 ready=false,而不是 live=false 导致所有副本被重启。
Required Interfaces
HTTP Services
HTTP 服务暴露两个只读接口:
GET /healthz/live
GET /healthz/ready
适用服务:
gateway-service
成功响应:
{
"status": "ok",
"service": "gateway-service",
"node_id": "gateway-node-1",
"time_unix_ms": 1777000000000
}
失败响应:
{
"status": "fail",
"service": "gateway-service",
"node_id": "gateway-node-1",
"time_unix_ms": 1777000000000,
"checks": [
{
"name": "room_grpc",
"status": "fail",
"message": "deadline exceeded"
}
]
}
状态码规则:
live成功返回200。live失败返回500。ready成功返回200。ready失败返回503。
gRPC Services
gRPC 服务必须注册标准 gRPC Health Checking Protocol:
grpc.health.v1.Health
适用服务:
room-servicewallet-serviceuser-serviceactivity-service
服务名使用完整服务边界名:
gateway-service
room-service
wallet-service
user-service
activity-service
状态映射:
| gRPC Health Status | Meaning |
|---|---|
SERVING |
ready |
NOT_SERVING |
not ready |
UNKNOWN |
启动中或检查器未初始化 |
本地 Docker 可以用 grpc-health-probe 或服务内置 HTTP admin 口做容器 healthcheck。线上优先使用云负载均衡、Kubernetes 或服务发现系统原生的 gRPC health check。
Service Readiness Rules
gateway-service
live:
- HTTP server runtime 正常。
- 进程没有进入不可恢复 panic 状态。
ready:
- JWT 配置已加载。
- HTTP listener 已启动。
room-servicegRPC 地址可连接。
gateway-service 启动阶段会连接 public auth rate limit Redis,连接失败时进程不进入服务状态。ready 不持续探测 MySQL、Redis、wallet,也不主动探测腾讯云 IM 外网接口;运行期 auth rate Redis 异常由登录注册入口 fail-closed 返回上游错误。UserSig 配置缺失时由 /api/v1/im/usersig fail-closed,不影响本地房间 HTTP 链路 ready。
room-service
live:
- gRPC server runtime 正常。
- Room manager 主循环未停止。
- Outbox worker 主循环未停止。
ready:
- MySQL
PingContext在超时时间内成功。 - Redis
PING在超时时间内成功。 - 当前节点不处于 draining 状态。
- gRPC listener 已启动。
- Redis lease 操作能力正常,至少能执行一次轻量读写或 Lua 脚本探测。
- 节点启动时必须能写入
room:node:{node_id};运行期心跳失败要记录告警,避免其他 room 节点无法转发到当前 owner。
wallet-service 建议作为 SendGift 链路的强依赖监控,但不要默认作为 room-service 整体 ready 的硬失败条件;否则 wallet 短暂异常会导致房间基础命令也被摘流。
腾讯云 IM 不作为 room-service ready 的硬依赖。PublishRoomEvent 同步失败后由 outbox 补投,不能因为外部 IM 抖动把房间状态服务整体摘掉。
Tencent Cloud IM
腾讯云 IM 是外部托管依赖,不在本仓库提供 live/ready 接口。
本仓库只检查两类内部条件:
gateway-service缺少sdk_app_id或secret_key时,/api/v1/im/usersig必须失败关闭,不能返回假票据。room-service启用腾讯云 IM 桥接时必须加载 REST API 配置;缺少管理员账号或密钥时服务启动失败,避免创建房间后无法建立外部群组。
线上需要独立监控腾讯云 IM REST API 错误率、UserSig 签发失败率和房间系统消息补投积压,不把外网探测塞进每次 readiness。
wallet-service
live:
- gRPC server runtime 正常。
ready:
- gRPC listener 已启动。
- 未来接入账务数据库后,账务数据库连接必须成功。
user-service
live:
- gRPC server runtime 正常。
ready:
- gRPC listener 已启动。
- 未来接入用户数据库后,用户数据库连接必须成功。
activity-service
live:
- gRPC server runtime 正常。
- Consumer 主循环未停止。
ready:
- gRPC listener 已启动。
- 未来接入 MQ/Redis Stream 后,消费位点存储可访问。
- 当前节点不处于 draining 状态。
Timeout Budget
健康检查必须快失败,不能拖垮服务。
| Check | Timeout |
|---|---|
| 本进程状态 | 50ms |
| HTTP/gRPC listener 自检 | 100ms |
Redis PING |
200ms |
MySQL PingContext |
300ms |
| 下游 gRPC health | 300ms |
单次 ready 总耗时建议小于 500ms。如果检查项较多,使用并发检查并设置总 deadline。
Docker Compose
本地 docker-compose.yml 应为每个服务配置 healthcheck。HTTP 服务使用 curl,gRPC 服务使用 grpc-health-probe 或服务提供的 admin health endpoint。
HTTP 示例:
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:13000/healthz/ready"]
interval: 5s
timeout: 3s
retries: 20
start_period: 10s
gRPC 示例:
healthcheck:
test: ["CMD-SHELL", "grpc-health-probe -addr=127.0.0.1:13001 -service=room-service"]
interval: 5s
timeout: 3s
retries: 20
start_period: 10s
depends_on.condition=service_healthy 只用于本地编排启动顺序。线上不能依赖 compose 的启动顺序保证服务稳定,必须依赖负载均衡 readiness 和服务自身重试。
Online Deployment
多机部署时,每个实例必须有唯一 node_id。
推荐变量:
SERVICE_NAME=room-service
NODE_ID=room-prod-az1-001
HEALTH_READY_TIMEOUT=500ms
DRAIN_TIMEOUT=30s
线上接入规则:
- SLB、Kubernetes Service、Nacos、Consul 只把
ready=true的实例放进可用池。 - 发布新版本时先等待新实例
ready=true,再下线旧实例。 - 下线旧实例时先切
ready=false,再进入 drain,最后退出进程。 - 不允许直接
kill -9正常发布中的服务。
Graceful Shutdown
所有服务收到 SIGTERM 后执行相同状态机:
running -> draining -> stopped
draining 要求:
ready立即返回失败。- 停止接收新连接或新请求。
- 等待当前请求完成,超过 deadline 后强制关闭。
- 关闭前写清必要的部署状态日志。
各服务额外要求:
| Service | Drain Requirement |
|---|---|
gateway-service |
停止接新 HTTP 请求,等待已有请求结束 |
room-service |
停止接管新房间,停止或释放 lease,刷 snapshot,暂停 outbox 当前批次后退出 |
wallet-service |
等待当前扣费 RPC 完成,禁止中途截断 |
activity-service |
完成当前消费消息或安全提交失败状态 |
客户端实时连接由腾讯云 IM SDK 承载,本仓库服务下线时不再发送 WebSocket close code。客户端收到腾讯云 SDK 断线事件后,按 SDK 指引重新登录并重新进群。
Room Service Lease Safety
room-service 的健康检查必须和 Redis lease 下线策略配合。
发布或故障时:
- 节点进入 draining。
ready=false,负载均衡不再打新请求。- 节点停止获取新的
room:route:{room_id}lease。 - 已持有 Room Cell 刷 snapshot。
- lease 释放或自然过期。
- 新节点接到请求后通过 snapshot + command log 恢复。
禁止在 ready=false 之后继续接管新房间。否则节点下线期间会持续获得新 room lease,导致退出时间不可控。
Observability Fields
健康检查日志只在状态变化时输出,不能每 5 秒刷一条成功日志。
状态变化日志必须包含:
service
node_id
old_status
new_status
failed_check
reason
duration_ms
建议指标:
health_ready_status
health_live_status
health_check_duration_ms
health_dependency_failures_total
service_draining
service_shutdown_duration_ms
room-service 额外指标:
room_lease_check_failures_total
room_snapshot_flush_failures_total
room_outbox_worker_alive
腾讯云 IM 相关指标不来自本地进程健康检查,单独采集 REST API 调用失败、UserSig 签发失败和 room outbox 补投延迟。
Implementation Checklist
新增或修改服务时,必须检查:
- 是否提供
live。 - 是否提供
ready。 ready是否包含本服务真正的硬依赖。- 下游依赖失败是否只影响
ready,没有误杀live。 - 检查是否有总 timeout。
- 检查路径是否没有业务写入。
SIGTERM后是否立即让ready=false。- Dockerfile 是否包含 healthcheck 所需工具,或服务是否提供可被容器调用的 health endpoint。
docker-compose.yml是否配置 service healthcheck。- 线上部署脚本是否等待新实例 ready 后再切流。
Do Not
- 不要用业务接口当健康检查,例如
CreateRoom、JoinRoom、SendGift。 - 不要在健康检查里创建房间、写 command log、写 outbox。
- 不要把所有下游都塞进每个服务的 ready。
- 不要把 Redis/MySQL 抖动映射成
live=false。 - 不要让健康检查依赖外网。
- 不要把健康检查失败日志刷屏。
- 不要在滚动更新时跳过 drain。