Level 38 / 阅读练习
生产环境日志、监控和告警
理解日志、指标、链路追踪、request_id、P95、慢查询和告警设计。
Progress
阅读中
0/2 步完成 / 阅读后完成练习才算通关
Practice
本关怎么过
- 读完正文后确认完成阅读
- 完成 1 道选择题练习
- 答错时看解释,再回到正文补理解
一句话:日志、监控和告警就是给线上系统装上仪表盘和报警器,让你知道系统现在是不是健康,出问题时能快速找到原因。
本篇学完你会什么:知道线上系统应该看哪些指标、日志怎么打才有用、告警怎么设才不吵,以及一次接口变慢时应该按什么顺序排查。
1. 为什么上线后不能只看“服务还在”
本地开发时,你看到接口能返回,就会觉得它没问题。
上线后不一样。真实用户会同时访问,数据库会变大,网络会抖,第三方服务会超时。
一个服务“还活着”不代表它“好用”:
| 状态 | 用户感受 | 系统可能发生了什么 |
|---|---|---|
| 接口能返回 | 正常 | 服务健康 |
| 接口很慢 | 卡顿 | 数据库慢、外部接口慢、连接池不够 |
| 偶尔 500 | 不稳定 | 某些输入没处理、依赖偶发失败 |
| 大量 401/403 | 不能用 | token 过期、权限配置错 |
| CPU 很高 | 页面转圈 | 死循环、大查询、并发太高 |
所以线上系统至少要有三样东西:
日志:发生了什么事
监控:现在状态怎么样
告警:什么时候需要人处理2. 日志、指标、链路追踪分别是什么
日志
日志像系统日记,记录某一刻发生了什么。
例子:
2026-06-30 10:20:31 INFO user login success user_id=12 request_id=abc123
2026-06-30 10:20:35 ERROR create order failed user_id=12 error=payment timeout request_id=abc123日志适合回答:
刚才发生了什么?
哪个用户触发的?
报错堆栈是什么?
请求 id 是多少?指标
指标像仪表盘,持续显示系统状态。
常见指标:
| 指标 | 含义 |
|---|---|
| QPS | 每秒有多少请求 |
| P95 响应时间 | 95% 的请求在多久内完成 |
| 错误率 | 失败请求占比 |
| CPU / 内存 | 服务器资源是否紧张 |
| 数据库连接数 | 连接池是否快被用完 |
链路追踪
链路追踪用来回答:
一个请求从前端到后端,再到数据库、Redis、第三方接口,中间每一步花了多久?小项目可以先不接复杂 tracing,但至少要有 request_id。它能把同一次请求的多条日志串起来。
3. FastAPI 项目日志怎么打
日志不是越多越好,而是要能帮你排查问题。
建议每次请求都带上:
| 字段 | 作用 |
|---|---|
request_id | 把同一次请求串起来 |
method | GET、POST、PUT、DELETE |
path | 请求路径 |
status_code | 响应状态码 |
duration_ms | 花了多久 |
user_id | 当前用户,没有就为空 |
error | 错误类型和消息 |
一个简单中间件示例:
import time
import uuid
import logging
from fastapi import Request
logger = logging.getLogger("app.request")
async def request_log_middleware(request: Request, call_next):
request_id = request.headers.get("X-Request-Id") or str(uuid.uuid4())
start = time.perf_counter()
try:
response = await call_next(request)
except Exception:
duration_ms = round((time.perf_counter() - start) * 1000, 2)
logger.exception(
"request failed",
extra={
"request_id": request_id,
"method": request.method,
"path": request.url.path,
"duration_ms": duration_ms,
},
)
raise
duration_ms = round((time.perf_counter() - start) * 1000, 2)
logger.info(
"request finished",
extra={
"request_id": request_id,
"method": request.method,
"path": request.url.path,
"status_code": response.status_code,
"duration_ms": duration_ms,
},
)
response.headers["X-Request-Id"] = request_id
return response还要把它注册到 FastAPI 应用里:
app.middleware("http")(request_log_middleware)注意:extra={...} 里的字段不会自动出现在所有日志格式里。真实项目要配合 JSON logger,或者在 logging formatter 里明确输出 request_id、path、duration_ms 这些字段。不然代码写了,日志平台里还是看不到。
大白话:每个请求都给一张小票。以后用户说“刚才失败了”,你可以用小票号找到完整过程。
4. 监控应该先看哪些指标
初学者不要一上来做几十个图。先看最能说明问题的 8 个:
| 指标 | 为什么重要 |
|---|---|
| 请求量 QPS | 判断流量有没有突然变大 |
| P95 响应时间 | 判断大部分用户是否卡 |
| 5xx 错误率 | 判断服务是否异常 |
| 4xx 比例 | 判断参数、鉴权、权限问题是否变多 |
| CPU | 判断计算资源是否紧张 |
| 内存 | 判断是否有泄漏或缓存过大 |
| 数据库慢查询 | 判断瓶颈是否在 SQL |
| Redis 命中率 | 判断缓存是否有效 |
推荐先按页面或接口分组:
/api/v1/auth/login
/api/v1/users
/api/v1/knowledge/search不要只看全站平均值。平均值很容易把某个接口的慢问题藏起来。
5. 告警怎么设才有用
告警的目标不是“声音越大越专业”,而是让人及时处理真正的问题。
好的告警应该有:
| 内容 | 示例 |
|---|---|
| 触发条件 | 5xx 错误率 5 分钟内超过 2% |
| 影响范围 | /api/v1/orders 接口 |
| 当前数值 | 当前错误率 8.5% |
| 排查入口 | 日志查询链接、监控面板链接 |
| 处理建议 | 先看最近发布、数据库、第三方接口 |
不建议这样设:
只要出现一次 500 就告警
CPU 超过 60% 就告警
接口超过 500ms 就告警这些阈值不是一定错,而是太容易脱离业务基线。比如有的后台报表接口 2 秒也能接受,有的登录接口 500ms 就已经偏慢。告警最好先看一段时间正常数据,再定阈值。
更实用的方式:
| 场景 | 告警建议 |
|---|---|
| 服务不可用 | 1-2 分钟连续健康检查失败 |
| 错误率升高 | 5 分钟内 5xx 超过阈值 |
| 响应变慢 | P95 连续 10 分钟超过阈值 |
| 数据库异常 | 连接池耗尽或慢查询明显增多 |
| 磁盘风险 | 磁盘使用率超过 80% |
6. 一次接口变慢怎么排查
假设用户反馈:
用户列表页面今天很慢不要第一反应就改代码。按顺序看:
- 看监控:是不是只有
/users慢,还是所有接口都慢。 - 看流量:请求量有没有突然变大。
- 看错误率:慢的同时有没有 500。
- 看日志:找慢请求的
request_id。 - 看 SQL:有没有慢查询,分页是否失效。
- 看依赖:Redis、数据库、第三方服务是否异常。
- 看发布:最近有没有上线新版本。
常见结论:
| 现象 | 可能原因 | 下一步 |
|---|---|---|
| 只有一个列表接口慢 | SQL、分页、N+1 查询 | 看慢 SQL 和 ORM 加载 |
| 所有接口都慢 | CPU、数据库、网络 | 看机器和依赖 |
| 登录接口慢 | 密码 hash、数据库、限流 | 看 auth 日志 |
| RAG 检索慢 | 向量库、embedding、top_k 太大 | 看检索耗时 |
7. 常见错误
| 错误 | 后果 | 修正 |
|---|---|---|
只打印 print() | 线上难收集、难过滤 | 使用 logging |
| 日志没有 request_id | 多条日志串不起来 | 每次请求生成 request_id |
| 只看平均响应时间 | 慢接口被平均值盖住 | 看 P95/P99 |
| 告警太敏感 | 大家疲劳,不再处理 | 设置持续时间和阈值 |
| 日志里打印密码/token | 安全风险 | 敏感字段脱敏 |
| 没有慢查询记录 | 数据库问题难定位 | 开启慢查询日志或埋点 |
8. 检查清单
[ ] 每个请求有 request_id
[ ] 日志包含 method、path、status_code、duration_ms
[ ] 错误日志包含堆栈
[ ] 日志不打印密码、token、密钥
[ ] 有健康检查
[ ] 有 QPS、响应时间、错误率监控
[ ] 能看到数据库慢查询
[ ] 告警有阈值、持续时间、排查入口9. 小结
| 名词 | 大白话 |
|---|---|
| 日志 | 系统日记 |
| 指标 | 系统仪表盘 |
| 告警 | 系统报警器 |
| request_id | 一次请求的小票号 |
| P95 | 大部分用户真实感受到的速度 |
| 慢查询 | 数据库里拖慢接口的 SQL |
上一篇建议:先看《FastAPI 项目配置、多环境和部署上线》,知道服务怎么上线。
下一篇建议:继续看《CI/CD、发布和回滚》,把上线流程变得可重复。
Checkpoint
读完后做题闯关
先读正文,再用下面的选择题检查自己是否真的理解。答错会出现解释,可以回到正文补一眼再重选。
读完正文后点击“我已读完,进入练习”,题目会变成可答状态。