Python on-call 手册的编写

1次阅读

on-call手册是故障时可直接执行的checklist,聚焦确认问题、临时止血、找人兜底三件事;每条指令须可复制粘贴、明确上下文、给出具体阈值和操作步骤。

Python on-call 手册的编写

on-call 手册不是文档,是故障时能直接抄起就用的 checklist

它不承载设计思想,也不解释原理——值班工程师凌晨三点被告警叫醒时,只关心三件事:怎么确认问题怎么临时止血找谁兜底。写成“python 服务高可用设计规范”或“django 架构演进史”,等于没写。

实操建议:

  • 每条操作指令必须可复制粘贴:比如 curl -s http://localhost:8000/health | jq '.status',而不是“检查健康接口返回”
  • 所有命令默认假设在目标服务所在机器执行;若需跳转,明确写出 ssh app-prod-03,不写“登录对应实例”
  • 避免出现“视情况而定”“一般建议”——换成具体阈值:比如“若 redis-cli -h cache-prod info memory | grep used_memory_human 输出超过 12G,立即执行 redis-cli -h cache-prod flushdb(并 Slack @infra)”

Python 进程挂了?先别 restart,看 systemctl statusjournalctl

90% 的“服务起不来”其实卡在启动阶段,systemctl restart myapp 只会让失败更快重演。真正要盯的是进程为何没活过初始化。

常见错误现象:

立即学习Python免费学习笔记(深入)”;

  • systemctl status myapp 显示 failed 但没报错细节
  • 手动跑 python manage.py runserver 没问题,但用 systemd 启就退出

实操建议:

  • 立刻查日志:journalctl -u myapp -n 100 --no-pager(加 --since "2 minutes ago" 更准)
  • 重点看最后一行:是 ImportErrorOperationalError: database is locked?还是 Killed(OOM 被杀)?
  • 环境变量差异最常踩坑:systemd 默认不继承 shell 环境,Environment=PYTHONPATH=/opt/myapp/src 必须显式写进 /etc/systemd/system/myapp.service

pip listpip freeze 都不准,on-call 时该信哪个?

pip freeze,但前提是它来自当前运行环境。很多手册写“检查依赖版本”,结果让值班人去开发机上跑 pip freeze——那跟生产环境根本不是一回事。

使用场景:

  • 怀疑是某次部署后出现兼容问题(比如 requests 升级导致下游 API 调用失败)
  • 需要快速比对两台机器是否一致(如 prod-01 vs prod-02)

实操建议:

  • 进入服务运行用户上下文再执行:sudo -u www-data pip freeze > /tmp/prod-deps.txt
  • 不要用 pip list:它显示“最新可安装版本”,不是“当前已安装版本”;pip freeze 才输出实际加载的包和精确版本
  • 如果服务用 venv,务必激活后再跑:source /opt/myapp/venv/bin/activate && pip freeze

告警说 CPU 100%,但 top 里 Python 进程只占 30%?查 strace 和 GIL

Python 线程服务在 CPU 告警时经常表现出“伪低负载”:top 看单个进程不高,但整体系统卡死。本质是 GIL + 阻塞系统调用混在一起,监控没抓到真凶。

性能影响:

  • 纯计算型任务会被 GIL 锁死,top 显示高,但实际是单核满载
  • 大量文件读写、DNS 查询、ssl 握手等系统调用会绕过 GIL,但阻塞线程,表现为 top 低 + load average 高 + 请求超时

实操建议:

  • 先看全局负载:uptime 输出的 load average 若远高于 CPU 核数(如 16 核机器显示 40),大概率是 I/O 阻塞
  • 抓可疑进程系统调用:strace -p $(pgrep -f 'gunicorn.*wsgi') -e trace=open,connect,sendto,recvfrom -s 64 2>&1 | head -50
  • 如果看到大量 connect(…) = -1 EINPROGRESS 或长时间停在 recvfrom(…),基本锁定是下游服务响应慢或 DNS 解析卡住

复杂点在于:Python 进程本身可能很“干净”,问题藏在它调用的 C 扩展、系统库、甚至内核参数里。on-call 手册里必须留一行:“若 strace 显示持续阻塞在某个 syscall,请直接 echo 'net.ipv4.tcp_fin_timeout = 30' >> /etc/sysctl.conf && sysctl -p 并通知 infra”。事情说清了就结束

text=ZqhQzanResources