AWS 可观测性、性能监控与 AI 辅助排障
# AWS 可观测性、性能监控与 AI 辅助排障
监控告诉你哪里异常,可观测性帮助你解释为什么异常,业务回读证明用户是否真的获得结果。
CloudWatch 的日志、指标、告警与追踪介绍复用 原有 CloudWatch 笔记。本篇整理原项目性能监控和只读 AI Ops 的完整链路。
# 日志、指标与 Trace 怎样配合
指标用于发现趋势,例如错误率和队列积压;日志保存一次处理的具体事实;Trace 关联跨服务调用。每次请求和任务应携带可追踪的 requestId/eventId,再记录部署版本、服务名和错误类别。
日志不要记录完整 Token、签名、密码、个人资料或模型输入。指标维度也不宜直接放每个用户或请求 ID,否则会产生大量时间序列并增加成本;这些明细更适合受控日志。
日志按服务分组并设置保留期,避免无限积累数据和费用。Alarm 配置统计窗口及连续满足条件的次数,平衡短暂尖峰误报与发现故障的及时性;告警必须能送达负责人并附带处置步骤。
# CloudWatch 与 CloudTrail 的区别
CloudWatch 观察应用和资源怎样运行,例如日志、延迟、错误率和告警;CloudTrail (opens new window) 记录 AWS API 活动,用于追查谁在什么时候操作了什么资源。例如签名异常时,用 CloudWatch 查业务错误,用 CloudTrail 查 KMS 调用身份与记录,二者互补。
# 哪些告警真正值得看
| 层 | 重点信号 | 为什么不能只看 CPU |
|---|---|---|
| API | 成功率、P95/P99、限流与上游失败 | CPU 很低也可能因数据库或第三方超时而不可用 |
| Lambda/ECS | 错误、timeout、重启、throttling、健康实例 | 进程存在不等于请求完成 |
| SQS | 最老消息年龄、积压、处理中数量、DLQ | 新请求入队成功时,消费者可能已经停了 |
| 数据库 | 连接数、锁等待、慢查询、空间 | 无限制扩容 API 会放大数据库压力 |
| Web3 | 扫描落后区块、重组、确认耗时、RPC 错误 | HTTP 200 不代表链上结果已确认 |
| AI | 模型超时、限流、任务成功率、单任务成本 | 返回文字不等于业务目标完成 |
SLI 是服务表现的测量指标,SLO 是希望达到的目标。例如 “统计窗口内 99.9% 的有效请求成功” 需要定义分母、排除项和时间窗口。阈值应来自业务目标,不机械复制别人的数值。
# 主动巡检与真实用户监控不同
Synthetics 主动定期访问页面或 API,没用户时也能发现故障。RUM(Real User Monitoring)来自真实浏览器,反映设备、网络和交互体验。两者互补;一个固定机房的 health 请求快,不代表所有用户页面都快。
Core Web Vitals 主要关注 LCP、INP、CLS;FCP 和 TTFB 是有用的辅助性能指标,不应把收集到的五项都称为当前 Core Web Vitals。
# 性能 SDK 的实际数据路径
浏览器采集并限量发送
→ 公开 API 校验体积、协议、速率
→ SQS
→ ECS Processor 再校验、脱敏、去重
→ PostgreSQL 清洗样本
→ 统计 API → 看板
2
3
4
5
6
浏览器不持有 AWS 凭据,也不直接写 CloudWatch 或数据库。Processor 是后台清洗程序;ECS 只是运行它的平台。CloudWatch Logs 用于排障,不必成为页面每次查询统计的数据库。
事件保存发生时间、采集版本、路由和稳定 eventId;路由删除 query/fragment 等敏感部分。SPA 页面切换不会重新执行入口文件,需要监听真实路由完成事件,并避免首访重复计数。
监控代码自身必须限制包体、缓存量、重试次数和网络开销;失败应降级,不能让监控拖垮被监控的应用。
# P95 是什么,为什么不能平均
P95 表示约 95% 样本不超过该值。例如多数请求几十毫秒、少量请求数秒,平均值可能掩盖尾部体验。不同批次的 P95 不能通过平均得到总体 P95,因为丢失了样本分布。
下面是可直接在 PostgreSQL 执行的样本:
-- 使用完整样本计算百分位数;单位在这里约定为毫秒。
WITH durations(ms) AS (
VALUES (10::double precision), (20), (30), (40), (1000)
)
SELECT
count(*) AS samples,
avg(ms) AS average_ms,
percentile_cont(0.50) WITHIN GROUP (ORDER BY ms) AS p50_ms,
percentile_cont(0.95) WITHIN GROUP (ORDER BY ms) AS p95_ms
FROM durations;
2
3
4
5
6
7
8
9
10
percentile_cont 在相邻样本间插值,因此结果不一定等于某一条真实请求。样本很少时,应同时显示样本数,不把单点画成不存在的趋势。规模增长后可使用直方图或可合并的分布摘要,而不是保存几个裸百分位数再平均。
# 从一个慢请求找到具体责任段
假设用户说生成报告花了 20 秒。按同一个 taskId 记录:API 接收用 0.1 秒、队列等待 12 秒、Worker 处理 5 秒、索引与页面刷新约 2.9 秒。此时优化 API 的 100 毫秒收益很小,应优先查队列消费容量和刷新间隔。数字用于说明定位方法,不是原项目测量结果。
跨异步链路时,不要假设原 HTTP Trace 会自然延续。消息携带受控追踪上下文或关联 ID,消费者建立新的处理 span 并关联来源;一次业务事件可重试多次,因此同时记录 eventId 与本次 attempt,才能看出是处理慢还是反复失败。
同一个请求失败了三次后成功,需要分别统计尝试次数和最终业务结果。只统计最后一次成功会隐藏重试开销;把每次尝试都当独立用户任务,又会错误放大失败率。
# SLO 与告警为什么要从用户结果出发
例如目标是 30 天内 99.9% 的有效 API 请求成功,100 万次有效请求对应最多约 1000 次失败预算。这是按请求数计算,不等同于允许停机 43.2 分钟;后者是按时间可用率推算,统计口径不同。
如果一小时就消耗了大量预算,应比一次孤立失败更早告警。告警还应附带服务、版本、时间范围和排查入口,而不是只发送 CPU 高。指标缺失也不能自动当作零错误,要区分没有流量、采集故障与服务不可用。
P95 汇总应保留原始样本或可合并的直方图桶。桶越粗,百分位估计越粗;多实例桶边界不一致就不能随意相加。高基数 requestId 留在日志和 Trace,指标只保留受控的服务、版本、状态类别等维度。
# 低成本与准实时的取舍
Worker 容量为 0 时,不会自己处理消息;从队列触发扩容,还要等待指标、启动和连接准备。页面看到新结果的总延迟包含采集、入队、启动、处理、查询和刷新,不能只用 “SDK 每五秒发送” 承诺五秒可见。
准实时需求可以保留常驻 Worker,并让可见页面后台刷新;低频任务可接受缩到 0 的等待。先定义体验目标,再决定容量与刷新策略。
# AI Ops 怎样参与而不越权
原项目让模型只做受控调查:告警或人工问题 → 队列 → Investigator → 读取指定日志、告警、Stack 事件和队列属性 → 校验结论 → 页面展示。
工具只接收服务枚举,由服务端映射资源,不接受任意 ARN、Shell 或查询文本。日志先脱敏,结论引用真实 evidenceId;证据不足时 rootCause 可以为空。运行角色没有生产修复权限,建议不能自动变成写操作。
这复用了 Agent 可观测性 与 Agent 安全 的原则,但不把运维模型当成状态权威。原项目文档中的历史验收结果不代表当前云资源仍然在线。
# 面试时可以这样回答
接口都返回成功,用户却说任务没完成,怎么查?参考答案
我先区分接口成功表示已接收还是已完成,再用任务 ID 串起队列、消费者、数据库和页面回读。重点查消息年龄、消费者失败、幂等冲突和查询缓存,而不是只看 API 的 200。最终以业务结果可回读为准,并把缺失的阶段指标补上。
P95 变差时,你会怎么定位?参考答案
先确认样本数、时间窗口和版本,排除统计口径变化,再沿 Trace 分解排队、数据库和外部调用。比如慢在队列等待,就查消费者容量与失败重试,不先优化页面代码。总体 P95 也不能通过平均各实例 P95 得到,要基于样本或可合并分布重新计算。
为什么 AI 排障只给建议,不直接修复?参考答案
日志可能不完整,也可能含不可信内容,模型给出的原因只是待验证判断。我会让它使用限定范围的只读工具,结论关联真实证据,缺证据就明确未知。生产写操作需要单独权限、审批和回滚方案,不能让模型读到一条日志就执行删除或扩容。
# 复用来源
整理自原项目 performance-observability 与 ai-ops-agent 文档,保留了分层采集、真实百分位数、凭据隔离与只读调查的设计。