健康检查函数必须显式设置连接与读取超时并捕获底层网络异常,禁用重试和副作用;HTTP 200不等于健康,需按依赖语义解析响应体、执行SELECT 1或ping等轻量验证。

健康检查函数必须显式处理依赖超时和连接拒绝
Python 的健康检查不是简单调用 requests.get() 就完事。默认情况下,requests 不设超时,一旦下游服务卡住或防火墙拦截,整个健康端点会 hang 住,导致负载均衡器误判为宕机。必须给 timeout 参数——且推荐拆分为 connect 和 read 两段:
try:
resp = requests.get("http://auth-service/health", timeout=(1.0, 2.0)) # connect 1s, read 2s
return resp.status_code == 200
except (requests.ConnectionError, requests.Timeout):
return False不设超时、或只设单个数字(如 timeout=3),在 DNS 解析失败或 SYN 包被丢弃时仍可能阻塞数秒甚至更久。
捕获异常类型要覆盖底层网络层和 HTTP 层
依赖服务异常不止是 5xx。常见真实错误包括:
-
ConnectionRefusedError(目标端口未监听) -
socket.timeout(TCP 握手超时) -
requests.ConnectionError(含 DNS 失败、SSL 握手失败等) -
requests.Timeout(明确的 connect/read 超时) -
requests.HTTPError(如 401/403,说明服务活着但鉴权失败,通常应视为 unhealthy)
Exception 会掩盖问题;只 catch requests.RequestException 会漏掉底层 socket 异常。建议按需组合:<code>except (requests.ConnectionError, requests.Timeout, socket.timeout, ConnectionRefusedError):注意:
socket.timeout 是 socket.error 的子类,但在 Python 3.3+ 中已独立,需显式列出。避免在健康检查里做重试或自动恢复逻辑
健康检查的本质是“此刻是否可用”,不是“稍后会不会好”。加重试(比如 for i in range(3))会让响应变慢、掩盖瞬时故障、干扰熔断器判断。以下做法都是错的:
- 在
/health里调用重试装饰器(如@retry) - 对失败的依赖服务发起二次探测
- 尝试 fallback 到本地缓存或降级接口
HTTP 状态码 200 不等于服务健康
很多团队直接检查 resp.status_code == 200,但这是危险的简化。真实场景中:
- 依赖服务可能返回 200 + JSON
{"status": "degraded"}(需解析 body) - 数据库连接池耗尽时,API 仍可返回 200,但 DB 检查已失败
- Redis 连接正常但
INFO命令返回loading:1,此时不应认为健康
SELECT 1;Redis 看 ping 和 info 输出。不要把所有依赖都当成“能连上就 OK”。最易被忽略的一点:健康检查路径本身不该触发任何副作用(如写日志到慢盘、发告警、更新指标),否则高频率探活会反向拖垮服务。所有诊断逻辑必须是只读、轻量、无锁的。
立即学习“Python免费学习笔记(深入)”;


















