# 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 服务暴露两个只读接口: ```text GET /healthz/live GET /healthz/ready ``` 适用服务: - `gateway-service` 成功响应: ```json { "status": "ok", "service": "gateway-service", "node_id": "gateway-node-1", "time_unix_ms": 1777000000000 } ``` 失败响应: ```json { "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: ```protobuf grpc.health.v1.Health ``` 适用服务: - `room-service` - `wallet-service` - `user-service` - `activity-service` 服务名使用完整服务边界名: ```text 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-service` gRPC 地址可连接。 `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 示例: ```yaml healthcheck: test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:13000/healthz/ready"] interval: 5s timeout: 3s retries: 20 start_period: 10s ``` gRPC 示例: ```yaml 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`。 推荐变量: ```text 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` 后执行相同状态机: ```text 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 下线策略配合。 发布或故障时: 1. 节点进入 draining。 2. `ready=false`,负载均衡不再打新请求。 3. 节点停止获取新的 `room:route:{room_id}` lease。 4. 已持有 Room Cell 刷 snapshot。 5. lease 释放或自然过期。 6. 新节点接到请求后通过 snapshot + command log 恢复。 禁止在 `ready=false` 之后继续接管新房间。否则节点下线期间会持续获得新 room lease,导致退出时间不可控。 ## Observability Fields 健康检查日志只在状态变化时输出,不能每 5 秒刷一条成功日志。 状态变化日志必须包含: ```text service node_id old_status new_status failed_check reason duration_ms ``` 建议指标: ```text health_ready_status health_live_status health_check_duration_ms health_dependency_failures_total service_draining service_shutdown_duration_ms ``` `room-service` 额外指标: ```text 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。