从入门到生产级实践指南
📖 目录导读
- 为什么需要健康检测脚本? —— 故障自愈的第一步
- 健康检测核心设计原则 —— 别让检测本身成为故障
- 三行代码入门版 —— 最简HTTP检测脚本
- 生产级脚本必备要素 —— 超时/重试/告警
- 实战:检测MySQL数据库健康 —— 不止是ping
- 常见问题FAQ —— 你踩过的坑我们都填平了
❓ 问答引入
问题:当服务器宕机时,你是等用户投诉才知道,还是脚本提前30秒报警?
答案:97%的运维事故本可以通过简单的健康检测脚本避免,本文将手把手教你写出能用于生产环境的健康检测脚本,无论你是刚学Python的运维新人,还是需要监控微服务的架构师。
为什么需要健康检测脚本?
微服务架构下,一个节点故障可能引发“雪崩效应”,健康检测脚本的核心价值在于:
- 自动化故障发现:取代人工每分钟刷新监控页面
- 自愈前置条件:为K8s的livenessProbe或自愈系统提供决策依据
- 性能基线记录:通过连续检测数据发现潜在退化(如响应时间逐渐变长)
💡 关键认知:检测脚本本身必须比被检测服务更可靠,否则你会收到“监控挂了”的假警报。
健康检测核心设计原则
| 原则 | 说明 | 违反后果 |
|---|---|---|
| 轻量级 | 脚本启动时间<50ms, 内存占用<10MB | 检测进程成为新的性能瓶颈 |
| 幂等性 | 多次执行结果一致,不产生副作用 | 脚本可能写入脏数据 |
| 可观测 | 执行结果需输出结构化日志 | 故障复盘时无据可查 |
| 容错性 | 网络抖动时自动重试,但需防“惊群效应” | 雪崩式告警淹没值班群 |
三行代码入门版(HTTP健康检测)
import requests
import sys
try:
resp = requests.get("https://yourdomain.com/health", timeout=5)
sys.exit(0 if resp.status_code == 200 else 1)
except Exception:
sys.exit(1)
这个脚本有什么问题?
- 没有重试:一次网络抖动就误报
- 没有详细输出:失败无任何上下文
- 硬编码URL:无法复用
改进版(带重试和日志):
import requests, sys, time, logging
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s")
def check_health(url, retries=3):
session = requests.Session()
retry = Retry(total=retries, backoff_factor=0.5, status_forcelist=[500, 502, 503])
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)
try:
resp = session.get(url, timeout=10)
if resp.status_code == 200:
logging.info(f"Health check passed: {url}")
return True
else:
logging.error(f"Health check failed: {resp.status_code} | {resp.text[:200]}")
return False
except Exception as e:
logging.error(f"Health check exception: {str(e)}")
return False
if __name__ == "__main__":
result = check_health("https://yourdomain.com/health")
sys.exit(0 if result else 1)
生产级脚本必备要素
超时控制
# 总超时 = 连接超时 + 读取超时 timeout = (3.0, 5.0) # (connect_timeout, read_timeout)
自定义健康检查逻辑
有时候HTTP 200不代表服务正常,比如返回一个{"status": "degraded"}:
def parse_health_response(json_data):
required_fields = ["status", "version", "uptime_seconds"]
if all(field in json_data for field in required_fields):
return json_data["status"] == "healthy"
return False
多种检测协议支持
| 服务类型 | 检测方式 | 示例命令 |
|---|---|---|
| HTTP API | GET /health | requests.get() |
| TCP端口 | 端口可达性 | socket.connect() |
| 数据库 | 执行简单查询 | SELECT 1 |
| 进程 | 检查PID文件 | os.path.exists() |
实战:检测MySQL数据库健康
需求
- 每秒新建连接数是否正常
- 复制延迟是否超过阈值
- 关键表是否能正常查询
脚本片段
#!/bin/bash
MYSQL_USER="monitor"
MYSQL_PASS="yourpassword"
MYSQL_HOST="127.0.0.1"
# 1. 基础连接检测
mysqladmin -u$MYSQL_USER -p$MYSQL_PASS -h$MYSQL_HOST ping > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "CRITICAL: MySQL is not responding to ping"
exit 2
fi
# 2. 复制延迟检查 (假设是Slave)
SLAVE_STATUS=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW SLAVE STATUS\G" 2>/dev/null)
SECONDS_BEHIND=$(echo "$SLAVE_STATUS" | grep "Seconds_Behind_Master" | awk '{print $2}')
if [ "$SECONDS_BEHIND" -gt 60 ]; then
echo "WARNING: Replication lag is $SECONDS_BEHIND seconds"
exit 1
fi
# 3. 业务健康检查
QUERY_RESULT=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SELECT count(*) FROM orders WHERE status='pending' LIMIT 1" 2>/dev/null)
echo "OK: MySQL healthy, pending orders: $QUERY_RESULT"
exit 0
注意:生产环境不要硬编码密码,应使用~/.my.cnf或密钥管理服务。
常见问题FAQ
Q1: 检测脚本应该用什么语言写?
A: 首选Python,其次是Shell(简单场景)和Go(高并发场景),不推荐使用Perl或Ruby,维护成本高。
Q2: 健康检测频率多少合适?
A:
- 对时间敏感的服务(如支付): 每10秒一次
- 普通Web服务: 每30秒一次
- 后台批处理: 每5分钟一次
原则:检测频率不能超过服务处理一次检测请求的耗时。
Q3: 检测脚本应该放在哪里执行?
A:
- 分布式监控:部署在独立的监控节点(如Prometheus的probe节点)
- 本地监控:作为cron job运行在被监控机器上(需注意自保问题)
Q4: 为什么我的脚本偶尔会挂起?
A: 最常见原因是DNS解析阻塞或防火墙丢包,解决方案:
- 使用IP直连代替域名
- 设置严格的socket超时
- 用
select.poll()实现非阻塞IO
Q5: 检测结果如何告警?
A: 推荐与监控系统集成:
# 集成Prometheus PushGateway
from prometheus_client import CollectorRegistry, Gauge, push_to_gateway
registry = CollectorRegistry()
g = Gauge('service_health', '1=healthy, 0=unhealthy', ['service_name'], registry=registry)
g.labels(service_name='api_gateway').set(1 if result else 0)
push_to_gateway('pushgateway.example.com:9091', job='health_check', registry=registry)
编写健康检测脚本的黄金三步
- 先理清检测目标:是检测“服务活着”还是“服务正常工作”?后者需要业务层探针。
- 从最小代码开始:先用最简单的方式运行起来,再逐步加入重试、超时、日志。
- 加入可观测性:每个检测结果必须包含时间戳、状态码、响应时间和错误详情。
最后送一句运维老兵的忠告:
“不要信任任何一个你无法解释其失败原因的健康检测脚本。” —— 你的监控系统应该比你更了解系统的弱点。
结合了Google SRE手册、Prometheus官方文档及多家一线互联网公司运维实践,经过重组优化以确保符合当前搜索引擎对原创深度内容的质量要求。*
