面试 · 场景排查型
目标:考察实战排障能力和系统性思维。从真实生产故障和踩坑经验提取场景,每题含排查决策树。 答题框架:现象 → 排查 → 根因 → 修复 → 治理(每题含决策树)。
1. 用户反馈"下单接口很慢"——你的排查步骤是什么?#
参考答案:
决策树:
用户反馈"下单很慢"
│
├─ Step 1: 确认影响范围(对照组破案)
│ ├─ 是所有用户还是部分用户?(部分 → 可能是特定区域/客户端)
│ ├─ 是所有接口还是只有下单?(只有下单 → 下单链路特有问题)
│ ├─ 是持续性的还是偶发的?(偶发 → 可能是容量/抖动)
│ └─ 对照组:找一个"正常"的服务对比,差异处就是根因方向
│
├─ Step 2: 看 Dashboard(黄金信号)
│ ├─ P99 延迟是否确实上升?→ 是,看是哪段时间开始的
│ ├─ 错误率是否也上升?→ 判断是"慢"还是"错"
│ ├─ 流量是否有变化?→ 流量突增也会导致延迟上升
│ └─ 饱和度如何?→ CPU throttle?连接池满?
│
├─ Step 3: Trace 分析(定位哪一跳慢)
│ ├─ 打开 Tempo/Jaeger 看下单请求的完整链路
│ ├─ 找到耗时最长的 span(是数据库查询?下游 RPC?)
│ └─ 用 exemplar 从指标跳到具体慢请求的 trace
│
├─ Step 4: 定位到具体 Span
│ ├─ 如果是 DB 慢 → 查 slow query log + 连接池 + 索引
│ ├─ 如果是下游慢 → 查下游服务的 Dashboard
│ ├─ 如果是网络 → 查丢包/重传/跨区延迟
│ └─ 如果是自身处理慢 → 查 GC/log/CPU throttle
│
├─ Step 5: 关联最近变更
│ ├─ 最近有没有发布?(查部署记录)
│ ├─ 有没有配置变更?(ConfigMap/Secret/HPA)
│ ├─ 有没有流量突增?(营销活动/上游重试)
│ └─ 有没有基础设施变更?(节点轮换/DB 迁移)
│
└─ Step 6: 修复 + 治理
├─ 止损:回滚/切流/扩容
├─ 根因:写 Postmortem
└─ 治理:加告警、加 runbook、加压测关键原则:从广到窄(影响面 → 服务 → 接口 → 具体调用),每层用证据说话。不要在表层打转——用对照组排除错误方向,用证据钉死每一层。
2. 凌晨 3 点告警:order-api p99 > 1s,你被 page。接下来每一步做什么?#
参考答案:
决策树(时序):
T+0 Acknowledge 告警(表示"我看到了")
T+1 打开 Grafana Dashboard,确认:
- 是真的延迟升高还是监控数据抖动?
- 只影响 order-api 还是多个服务?
- 错误率是否也在上升?
- 流量是否有突增?
T+3 如果是真实故障:
- 判断 SEV 级别(影响用户比例 → SEV-2 还是 SEV-3)
- SEV-2 以上 → 拉事故群,任命 IC
T+5 初步诊断:
- 最近有没有发布?(查部署记录)
- 流量有没有突增?
- 先看 Tempo trace 找 slowest span
- 检查下游服务健康度
T+8 如果有明确嫌疑(如新发布的版本):
- 优先回滚而非修复
- IC 确认回滚命令 → 执行 → 观察指标是否回落
T+15 确认恢复 → 进入监控阶段
T+45 指标稳定 30 分钟 → Resolve → 排 Postmortem 时间关键原则:
- 凌晨被叫醒最忌讳"先自己排查一小时"——效率低、业务在挂
- 有回滚先回滚,根因可以明天在 staging 复现
- 不确定严重度时按最严重预估,确认没问题再降级
治理:每次凌晨 page 后 review——这个告警是否真的需要半夜叫醒?如果是误报,调整阈值;如果是真故障,复盘响应速度。
3. ArgoCD sync 一直卡在"Progressing",Pod 显示 Pending。排查步骤?#
参考答案:
决策树:
kubectl describe pod <pending-pod> | grep -A5 Events
Events 可能显示:
├─ "FailedScheduling: 0/5 nodes are available: 5 Insufficient cpu"
│ → 节点资源不足
│ → 检查节点容量 + HPA + Cluster Autoscaler
│ → 验证 Pod 的 resources.requests 是否合理
│
├─ "FailedScheduling: node(s) had untolerated taint"
│ → Pod 缺 toleration
│ → 检查节点 taint + Pod toleration 配置
│ → ★ 排查所有同 nodeSelector 的组件(一个缺陷往往是一类)
│
├─ "FailedScheduling: node(s) didn't match Pod's node affinity"
│ → nodeSelector/affinity 不匹配
│ → 检查是否有可用节点
│ → 检查节点标签是否正确
│
├─ "FailedScheduling: didn't trigger scale-up due to missing matching nodepool"
│ → 自动扩缩器找不到匹配的节点池
│ → 检查 Karpenter/CA 的 Provisioner 配置
│ → 检查节点池是否支持所需的 instance type
│
├─ "FailedMount" 或 PVC 相关
│ → PV/PVC 绑定问题
│ → kubectl describe pvc
│ → 检查 StorageClass 是否有可用 PV
│
└─ ImagePullBackOff
→ 镜像拉不下来
→ 检查 image name 拼写
→ 检查 registry 可达性(跨境源?换 mirror)
→ 检查 imagePullSecretsA 旗舰案例:FailedScheduling: untolerated taint {system-pool=true: NoSchedule} → 发现 istio gateway 绑了 system-pool nodeSelector 但没配 toleration → 平时 NoSchedule 不驱逐运行中的 Pod,节点轮换时才暴露。
治理:发现一个组件缺 toleration,必须排查所有同 nodeSelector 的组件——"一个缺陷往往是一类"。
4. 一个新版本灰度 10% 后,错误率从 0.1% 升到 3%,但还没触发告警。你的决策?#
参考答案:
立即决策:停止灰度,回滚灰度部分。
推理:
- 错误率从 0.1% → 3% = 30 倍增长。这不是正常的灰度波动
- 虽然 3% 的绝对错误率可能还没触发固定阈值的告警(如告警设了 5%),但趋势和对比说明问题严重
- 别把错误率当错误量放大:错误率是比率,不会随流量倍数放大。全量后新版本自身错误率仍是 ~3%(不是 30%),变的是两件事——① 错误的绝对量放大约 10 倍(新版本承接的流量从 10% 扩到 100%);② 受影响面从 10% 用户扩到 100% 用户
- 算一笔账:当前服务整体错误率 ≈ 0.9×0.1% + 0.1×3% = 0.39%;全量后 ≈ 100%×3% = 3%(整体错误率抬升约 7.7 倍,绝对错误量抬升更多)。3% 持续 = SEV 级事故
- 灰度阶段出现这种级别的退化,表明发布有严重质量问题
后续步骤:
- 立即缩小灰度到 0% 或回滚
- 分析灰度期间 3% 错误的具体类型和根因
- 修复后在 staging 验证
- 下次灰度设定更保守的阈值:错误率增长 > 2 倍即暂停
治理:
- 灰度告警应该用"相对基线"而非"绝对阈值"——错误率 > 基线 2x 就该暂停
- 自动回滚触发条件应该包含"灰度期间错误率相对上升"
- 灰度观察期要足够长,慢 SQL 类问题在小流量时看不出来
5. 发布完成后,发现所有新 Pod 都是 CrashLoopBackOff。如何快速止血和排查?#
参考答案:
止损第一:如果有指定回滚版本的机制,先回滚(恢复旧版本保证业务可用)。
排查决策树:
新 Pod CrashLoopBackOff
│
├─ kubectl logs <pod> --previous
│ ├─ 有日志 → 读日志定位错误
│ │ ├─ "connection refused" → DB/Redis/下游连不上
│ │ │ → 检查 Service 名是否正确(不同集群可能不同)
│ │ ├─ "permission denied" → RBAC/安全上下文问题
│ │ ├─ "config error" → ConfigMap/Secret 字段缺失或格式错误
│ │ ├─ "OOMKilled" → 内存超限,调 limits 或查内存泄漏
│ │ └─ "class not found" → 镜像版本不对
│ └─ 无日志 → 容器在启动早期就挂了
│ → 检查镜像是否正确
│ → 检查 entrypoint/command
│
├─ kubectl describe pod <pod>
│ ├─ "Liveness probe failed" → 健康检查配置与新版不兼容
│ ├─ "Readiness probe failed" → 依赖未就绪
│ └─ "Back-off restarting failed container"
│
├─ kubectl get events -n <ns> --sort-by='.lastTimestamp'
│ └─ 看最近事件找线索
│
└─ 确认回滚完成后,分析新版与旧版的差异治理:
- CI/CD 流水线加"镜像启动测试"——发布前在 staging 验证 Pod 能正常启动
- 健康检查配置要和代码版本匹配——liveness probe 不要配得太激进
- 回滚路径必须预演过——不能在事故时才发现回滚也挂
6. 生产环境 Redis 突然 CPU 100%,业务开始超时。排查和止损步骤?#
参考答案:
止损(30 秒内):
1. 如果 Redis 有 replica → 手动 failover 到 replica
2. 如果有读/写分离 → 先把读流量切到 replica
3. 如果没有 HA → 重启 Redis(接受短暂不可用)排查决策树:
redis-cli 连上:
├─ INFO commandstats → 看哪种命令最多(可能是 KEYS * 或大 HGETALL)
├─ SLOWLOG GET 20 → 看最近的慢命令
├─ CLIENT LIST → 看连接数是否异常
├─ INFO memory → 看是否在 evict key
└─ INFO persistence → 看是否在 RDB/AOF 写盘(也会拉高 CPU)
根因可能:
├─ 某服务上线引入了 KEYS *(生产禁用!)
├─ 大 key 被频繁访问(HGETALL 一个 10MB 的 hash)
├─ 连接风暴(某服务快速重连)
├─ 内存满触发 eviction 导致 CPU 飙高
└─ 持久化触发(RDB bgsave 时 fork 大内存进程)A 旗舰案例:混沌工程 GameDay 中 kill Redis master → sentinel failover 后新 master CPU 瞬间拉满 → 发现大量连接在短时间建连,客户端没有连接池限流。
治理:
- Redis 禁用危险命令(KEYS、FLUSHALL)在生产环境
- 大 key 监控告警(超过 10KB 的 key 报警)
- 客户端连接池配置上限
- 持久化策略评估——eviction 时不要触发 RDB
7. Prometheus 查询超时,Grafana Dashboard 一片红。如何排查?#
参考答案:
决策树:
Step 1: 确认 Prometheus 是否活着
kubectl -n monitoring get pod -l app=prometheus
kubectl -n monitoring logs prometheus-0 | tail -20
→ 看是否有 OOM / WAL corruption / disk full
Step 2: 检查查询是否有高基数
└─ 最近有没有新增高基数 label?
如 user_id、request_id 被放进了 label
→ 序列数爆炸 → Prometheus 内存 OOM
→ 查 Prometheus TSDB 状态: curl localhost:9090/api/v1/status/tsdb
Step 3: 检查存储
└─ Prometheus TSDB 保留时间 + 当前 PVC 使用量
磁盘满了 → Write-Ahead Log 写失败 → 整体卡住
Step 4: 检查 Recording Rules
└─ 如果有长时间窗口的 Recording Rule(如 30d)在实时计算
→ 评估太慢 → 阻塞其他查询
→ 看 Prometheus Rules 页面的 evaluation time
Step 5: 紧急止血
└─ 如果确认是查询卡死 → 重启 Prometheus
(丢 2h 内存数据但恢复服务)
└─ 如果是高基数 → 删除违规的指标序列治理:
- 高基数 label 必须在 PR review 时拦截——user_id/request_id 绝不进 label
- Prometheus 资源 limits 要够(建议 ≥ 8Gi 内存)
- 定期检查序列数:
prometheus_tsdb_head_series告警 - 长窗口 Recording Rule 用 30d 时要评估性能影响
8. 用户反馈"A 功能完全正常,B 功能全部 502"。你怎么开始排查?#
参考答案:
关键线索:A 正常 + B 全挂 → 不是整体故障,是 B 功能链路上的特定组件有问题。对照组已经天然存在——A 就是对照组。
决策树:
Step 1: 区分 A 和 B 的调用链差异
├─ B 服务有没有自己的独立后端?
├─ B 服务是否依赖某个 A 不依赖的下游/数据库?
└─ B 服务是否有独立的 Ingress/Gateway 配置?
Step 2: 定位 502 来源
├─ 是 NLB/ALB 返回的 502 → 查 target group health
├─ 是 Ingress/Gateway 返回的 502 → 查 upstream service endpoints
└─ 是应用本身返回的 502 → 查应用日志
Step 3: 常见根因
├─ B 服务的 Pod 全挂了(OOM/deployment 误删)
├─ B 服务的 Service endpoints 为空(selector 不匹配)
├─ B 服务的网络策略阻断了流量
└─ B 服务的 NLB target group health check 失败
Step 4: 对照检查
kubectl get endpoints <B-service> → 是否为空?
kubectl get pod -l app=<B> → Pod 是否 Running?
kubectl describe svc <B-service> → selector 是否正确?A 旗舰案例:passport 全挂但 goalfymax 正常 → 对照发现 passport 直连 NLB,goalfymax 走 CloudFront → 问题在 passport → NLB 链路 → 发现 istio gateway Pod 永久 Pending。
治理:服务依赖图要预先画好,出事时能快速识别"哪些服务共享依赖"。
9. 告警群突然收到 50 条同一个服务的告警。你怎么判断这是"一次发布导致的真故障"还是"监控系统抽风"?#
参考答案:
决策树:
判断逻辑:
├─ 1. 看告警时间分布
│ ├─ 同一秒同时触发 → 更像是监控链路问题
│ └─ 逐步蔓延(先 1 个、30s 后 5 个、1min 后 50 个) → 像真实故障传播
│
├─ 2. 看 Dashboard 数据
│ ├─ 指标是否真的异常?(错误率/延迟真的在升高)
│ └─ 还是只有告警在响但指标正常? → Alertmanager 自身问题
│
├─ 3. 看是否有相关发布
│ ├─ 查部署记录 → 最近 30min 有没有发布?
│ └─ 如果有 → 优先怀疑是发布导致 → 准备回滚
│
├─ 4. 看影响面
│ ├─ 能否在 staging/qa 复现? → 如果能 → 是代码问题
│ └─ 只有 prod 有? → 可能是容量/特定流量模式
│
└─ 5. 看告警是否有 Grouping 异常
└─ Alertmanager 的 group_by 配置是否合理?
一次发布挂 50 个 pod → 应该合并成 1 条告警快速判断:打开 Grafana 看 5 分钟前的真实错误率——如果错误率确实在暴涨,是真故障;如果错误率平稳,是告警系统自身问题。
治理:
- Alertmanager 的 group_by 配置要合理——同 alertname + namespace + cluster 合并
- 一次发布挂 50 个 Pod 应该是 1 条告警,不是 50 条
- 告警数量异常本身就是告警——"5 分钟内告警 > 20 条"应该触发审查
10. 你发现一个服务在过去 2 小时一直在缓慢消耗 Error Budget(burn rate ~2x)。没有告警触发。你怎么处理?#
参考答案:
为什么没告警:P0 告警阈值是 14.4x,P1 是 6x。2x 的燃烧率只触发 P2(Dashboard 级别,不发通知)。
但这种"缓慢泄漏"同样危险:
- 2x 持续一整天 = 消耗了 2 天的 Error Budget
- 如果持续一周没人发现 → 月度 Budget 会超支
处理步骤:
- 先看是什么在消耗:是间歇性 spike 还是持续劣化?
- 拉 Tempo 看 slow traces,定位瓶颈
- 检查是不是有新的部署或流量模式变化
- 如果是低频的间歇性问题 → 降低 P1 告警阈值(6x → 3x),或增加 12h 窗口告警
- 记入 Error Budget 回顾议题:这种"慢烧"场景告警是否覆盖?
治理:
- 不能只配 P0 告警。P1(6x)和 P2(1x)同样重要——P2 是雷达,告诉你"有问题在酝酿"
- P2 告警要有可见的出口——不能只放 Dashboard,配日报或周报邮件
- 每月 Error Budget 回顾要看"慢烧"模式——哪些 Budget 消耗没有触发 P0/P1
11. GitOps 仓库 merge 了一个 HTTPRoute 变更,但集群内路由没更新。排查步骤?#
参考答案:
决策树:
Step 1: 检查 ArgoCD Application 状态
argocd app get <app-name>
→ 看 Sync Status: OutOfSync 还是 Synced?
→ 看 Health Status: Healthy / Degraded?
Step 2: 如果是 OutOfSync 但没自动同步
→ 检查 syncPolicy.automated 是否开启
→ 主力 ArgoCD 常设手动 sync → merge 后需手动触发
→ kubectl patch application -n argocd <app> --type=merge --patch '{"operation":{"sync":{"revision":"HEAD"}}}'
Step 3: 如果是 Synced 但实际路由无效
→ kubectl get httproute -n <ns> <name> -o yaml
→ 检查 field 是否正确(Gateway API vs Istio VS 是两套路由!)
→ HTTPRoute 管南北流量,VirtualService 管东西流量
Step 4: 验证路由是否生效
→ curl -H "Host: xxx" <gateway-ip>
→ 看实际路由到哪个 backend
Step 5: 如果是 ArgoCD AutoSync 卡住
→ 看 Application 的 Conditions
→ ComparisonError / SyncError
→ 可能是 CRD 太大超过 256KB annotation 上限 → 加 ServerSideApply踩坑大全 1.10:K8s Gateway API HTTPRoute 和 Istio VirtualService 是两套独立路由——改 HTTPRoute 可以影响南北流量(外部进来),但不影响东西流量(Pod-to-Pod),反之亦然。设计灰度/AB/PR 隔离方案时必须双轨规划。
治理:非镜像类 gitops 改动(HTTPRoute、Service、ConfigMap)merge 后必须手动触发 sync,不能假设 ArgoCD 会自动同步。
12. 一个服务突然开始报大量的 5xx,但 CPU/内存看起来都正常。怎么排查?#
参考答案:
决策树:
CPU/内存正常 + 5xx 高 → 排除自身过载 → 往下游或网络方向查
排查路径:
├─ 1. 看 5xx 的具体类型
│ ├─ 502 Bad Gateway → 上游从下游收到的响应无效
│ ├─ 503 Service Unavailable → 服务临时过载或维护
│ └─ 504 Gateway Timeout → 下游响应超时
│
├─ 2. 如果是 502/504 → 大概率是下游问题
│ ├─ 查下游服务的 Dashboard
│ ├─ 查 Tempo trace 看失败在哪个 span
│ └─ 查下游的连接池是否耗尽(连接数 vs max)
│
├─ 3. 如果是 503 → 可能是自己过载
│ ├─ 检查线程池队列长度(CPU 正常但队列满 → 阻塞等待而非计算)
│ └─ 检查 Rate Limiting 是否触发
│
├─ 4. 关联变更
│ ├─ 有没有 DNS 变更?
│ ├─ 证书过期?
│ ├─ NetworkPolicy 变更?
│ └─ 下游服务发布?
│
└─ 5. 隐式错误检查
├─ 服务返回 200 但业务结果错?
└─ 检查业务层埋点治理:5xx 告警要区分类型——502/503/504 各有不同的根因方向。告警 annotation 里包含错误类型分布。
13. 一台 K8s node 变成 NotReady。你的排查流程?#
参考答案:
决策树:
kubectl describe node <node-name>
看 Conditions:
├─ MemoryPressure=True → 节点内存不足
├─ DiskPressure=True → 节点磁盘空间不足
├─ PIDPressure=True → 进程数超限
└─ NetworkUnavailable=True → CNI 插件问题
看具体根因:
├─ kubectl get node <node> -o json | jq '.status.conditions'
├─ 登录节点: journalctl -u kubelet --since "10 min ago"
└─ 检查: kubelet 是否活着?CNI 是否正常?磁盘是否满了?
常见根因:
├─ /var/lib/kubelet 磁盘写满(日志/image layers)
├─ CNI 插件 CrashLoop(VPC CNI / Calico / Cilium)
├─ kubelet 证书过期
├─ containerd/docker 挂了
└─ 内核 oom killer 影响了 kubeletA 旗舰案例:新节点全 NotReady → CNI DaemonSet CrashLoop → MissingIAMPermissions → 追查到 CNI 走 IRSA 但 addon 更新中间态导致 IRSA 临时失效 → fallback 到没配 CNI policy 的 node role → 形成自锁死循环。
双层归因:
- 触发因素:addon 更新中间态 + IRSA 短暂失效(偶发)
- 结构性缺陷:node role 没配 CNI policy 兜底(可以根治)
- 真正的 Action Item:给所有 EKS node role 普配 CNI policy 兜底
14. 部署后数据库连接池瞬间打满,所有请求排队等待。排查和止损?#
参考答案:
止损(按优先级):
1. 连接数超限 → 调大 max_connections(临时,快速止血)
2. Kill 长时间 idle 的连接
3. 如果确认是新版本的问题 → 回滚排查根因:
1. 新版本是否有连接泄漏?
→ 在代码里检查:连接是否在 finally 中正确归还
2. 是否有 N+1 查询?
→ Tempo trace 看单次请求发了多少次 DB 查询
3. 连接池配置是否合理?
→ maxPoolSize = ?
→ 等待队列满了之后的行为(fail-fast 还是无限排队?)
4. 新版是否导致更多并发请求打过来?
→ 看 QPS 变化A 旗舰案例:N+1 查询 + 连接池满 → 无慢查询的请求也被阻塞(因为连接池没可用连接) → 整个服务不可用。单次事件消耗月度 Error Budget 的 68%。
治理:
- DB 连接数监控告警(连接数 > 80% 告警)
- PR 流程加 SQL lint 检查(防 N+1)
- staging 复制 prod 1/10 真实流量压测
- 连接池配置 fail-fast(队列满立即拒绝,不无限等待)
15. 你发现 staging 环境的监控告警已经 75 天没有触发过了。这正常吗?怎么排查?#
参考答案:
不正常——即使是 staging 环境,也应该偶尔有真实的告警测试或至少 Watchdog 心跳。
排查步骤:
1. 主动触发一条测试告警
→ 写一条 expr: vector(1) 的规则
→ 看能否在 Alertmanager 和钉钉看到
2. 如果看不到:
├─ 规则是否加载?→ Prometheus Rules API
├─ ruleSelector 是否匹配?→ staging 的 rule label 是否和 selector 一致
├─ Alertmanager 是否可达?→ Prometheus targets 页面
└─ 钉钉 webhook 是否有效?→ token 过期?关键词白名单?
3. 常见根因:
├─ staging 的 ruleSelector 用 release: kube-prometheus → 但规则没打这个 label
├─ staging 的 Alertmanager 整体挂了 → 没死机开关发现
└─ 钉钉群 token 已失效
4. 修复后验证:
└─ 主动制造一次 firing → 确认全链路推送到群A 旗舰教训:sandbox staging 告警因 label 不匹配 ruleSelector 75 天从未生效。发现时才知道"根本没有告警覆盖"。所有告警上线必须主动制造一次 firing 验证。
治理:
- 告警上线 checklist 包含"主动制造一次 firing"
- 每周巡检脚本对账:git 里的规则数 vs Prometheus 加载的规则数
- 每个 Alertmanager 必须有死机开关(Watchdog)
- 告警数量作为团队 KPI——长期 0 触发 = 可能是规则失效
16. 某服务 Error Budget 还剩 60%,但开发想发一个"很重要的新功能"。你的决策?#
参考答案:
决策:可以发,但要走标准灰度流程。
推理:
- Budget 60% 处于"正常发布"区间(>50%)
- "很重要的新功能"不是特殊理由——Budget 机制的目的就是让发布决策数据化
- 但要确认:灰度策略合规、观察指标明确、回滚路径清晰
注意事项:
- 灰度必须分阶段:1% → 10% → 50% → 100%
- 每阶段观察 Error Budget burn rate
- 如果灰度期间 burn rate > 6x,立即停止
- 如果发布后 Budget 掉到 25% 以下,下次发布需要 review
治理:Error Budget 机制的核心是"数据说话"——Budget 充足就放行,不看"功能多重要"。如果开发觉得"重要"就可以绕过规则,Budget 机制就失效了。
反过来问(面试常见追问):如果 Budget 已经耗尽、正在冻结,又来了一个必须上的紧急安全修复怎么办?——见 Q23。关键预告:错误预算政策必须预留紧急豁免例外,冻结冻的是功能发布,不是安全补丁/数据修复/合规这类紧急修复。
17. 用户报告"凌晨 2 点服务不可用",但当时没有任何告警。怎么排查?#
参考答案:
决策树:
Step 1: 确认用户报告是否真实
├─ 查 Grafana 看凌晨 2 点的指标
│ ├─ 错误率有上升?→ 真实故障
│ └─ 指标正常?→ 可能是用户侧问题或监控盲区
└─ 查日志看有没有 ERROR
Step 2: 如果是真故障但没告警
├─ 告警规则是否正确?
│ ├─ ruleSelector 是否匹配?→ 75 天没生效的坑
│ ├─ for 时间太长?→ 故障短于 for 时间
│ └─ 阈值设太高?
├─ 告警链路是否正常?
│ ├─ Prometheus 当时在运行吗?
│ ├─ Alertmanager 当时在运行吗?
│ └─ 钉钉 webhook 当时通吗?
└─ 告警是否被 silence 了?
└─ 查 silence 历史
Step 3: 如果是监控盲区
├─ 凌晨 2 点是否有真实流量?
│ ├─ 有流量 → 真实用户受影响
│ └─ 无流量 → 可能是合成监控盲区
├─ 是否有黑盒监控覆盖?
│ └─ 没有黑盒 → 凌晨无流量时无信号
└─ 死机开关是否在工作?
Step 4: 修复 + 治理
├─ 补告警规则
├─ 加黑盒监控(cuj-prober 7×24 拨测)
├─ 加死机开关
└─ Postmortem:为什么监控盲区存在治理:
- 黑盒监控是真实流量的补充——凌晨无流量时唯一信号
- 死机开关必须有——监控自己挂了要知道
- 每月 review 告警覆盖率——哪些故障应该有告警但没有
18. Pod 频繁重启(每 5 分钟一次),但业务看起来正常。需要处理吗?#
参考答案:
需要处理——频繁重启是隐患,即使业务"看起来正常"。
决策树:
Step 1: 确认重启原因
kubectl describe pod <pod> | grep -A5 "Last State"
├─ OOMKilled → 内存 limit 太低或内存泄漏
├─ Liveness probe failed → 健康检查配错或应用卡顿
├─ Error → 应用代码异常退出
└─ Evicted → 节点资源不足
Step 2: 评估业务影响
├─ 重启时 in-flight 请求会失败吗?
│ └─ 没有 preStop hook → SIGTERM 立即断连
├─ 重启时新请求会路由到这个 Pod 吗?
│ └─ readiness probe 没及时摘除 → 流量丢失
└─ 重启频率高会导致连接池抖动
Step 3: 修复
├─ OOMKilled → 调内存 limit 或查内存泄漏
├─ Liveness probe → 调整超时/间隔
├─ 加 preStop hook → 优雅终止
└─ 加 PDB → 防止同时重启多个治理:
- Pod 重启次数告警(> 3 次/小时)
- preStop hook 是必须的——不配就是 in-flight 请求全挂
- readiness probe 要先于 liveness probe 失败——先摘流量再重启
19. 集群里某个 namespace 的资源使用率突然飙升,影响其他 namespace。怎么处理?#
参考答案:
决策树:
Step 1: 止损——隔离影响
├─ 识别是哪个 namespace
├─ 如果有 NetworkPolicy → 临时限制其网络
├─ 如果有 ResourceQuota → 检查是否生效
└─ 必要时 scale down 该 namespace 的 Pod
Step 2: 定位根因
├─ kubectl top pod -n <ns> → 找出最耗资源的 Pod
├─ 看是否有异常流量(DDoS?循环调用?)
├─ 看是否有新发布引入 bug
└─ 看是否有 OOM 导致频繁重启
Step 3: 长期治理
├─ ResourceQuota:每个 namespace 设 CPU/内存上限
├─ LimitRange:每个 Pod 设默认 requests/limits
├─ NetworkPolicy:限制 namespace 间流量
├─ PriorityClass:核心服务高优先级
└─ 节点池隔离:核心服务用专用节点池A 旗舰案例:某服务内存 HPA 误配,副本从 4 扩到 13,吃掉专用节点池所有资源,导致 maxSurge 的 Pod Pending,发版超时。
治理:每个 namespace 必须配 ResourceQuota + LimitRange。没有资源限制的 namespace 是"定时炸弹"。
20. 数据库主从延迟突然增大,从库 lag > 60s。怎么排查?#
参考答案:
决策树:
Step 1: 确认影响
├─ 从库是否在提供读服务?→ 是 → 用户可能读到旧数据
├─ 从库是否用于故障切换?→ 是 → HA 可能失败
└─ lag 持续增大还是稳定?
Step 2: 定位根因
├─ 主库写入量突增?
│ ├─ 看主库 QPS
│ └─ 看是否有批量写入/DDL
├─ 从库性能问题?
│ ├─ 从库 CPU/IO 是否满
│ ├─ 从库是否有慢查询阻塞复制
│ └─ 从库规格是否低于主库
├─ 网络问题?
│ └─ 主从间网络延迟
└─ 复制配置问题?
├─ 单线程复制 → 大事务会阻塞
└─ 并行复制配置不当
Step 3: 止损
├─ 如果从库用于读 → 临时把读流量切回主库
├─ 如果 lag 持续增大 → 暂停从库的非必要查询
└─ 如果是 DDL 导致 → 等待 DDL 完成
Step 4: 修复
├─ 启用并行复制(MySQL: slave_parallel_workers)
├─ 从库规格升级
├─ 长事务优化
└─ 主库写入分批治理:
- 复制延迟告警:lag > 30s 告警,lag > 60s page
- 从库不承接关键读(除非 lag < 1s)
- DDL 必须在低峰期执行
- 定期演练主从切换
21. 钉钉群里的告警突然不响了,但 Prometheus 和 Alertmanager 都看起来正常。怎么排查?#
参考答案:
决策树:
Step 1: 确认告警是否真的没发
├─ Alertmanager UI 看是否有 firing 告警
│ → 有 firing 但钉钉没收到 → 通知链路问题
│ → 没有 firing → 告警规则问题
└─ Prometheus UI 看告警状态
Step 2: 通知链路排查
├─ webhook-dingtalk 是否活着?
│ kubectl -n monitoring get pod -l app=webhook-dingtalk
├─ 钉钉 webhook URL 是否有效?
│ → token 被管理员删/重建 → 静默失效
│ → curl 测试 webhook
├─ 钉钉群关键词白名单?
│ → firing 含"告警"过关
│ → resolved 只含"恢复"被拒(常见坑!)
└─ Alertmanager 路由配置是否正确?
Step 3: 主动测试
├─ curl webhook-dingtalk 发测试消息
├─ 看钉钉群是否收到
└─ 如果收不到 → 钉钉 API 返回什么错误码
Step 4: 常见根因
├─ 钉钉 token 静默失效(管理员操作)
├─ resolved 通知被关键词拦截
├─ webhook-dingtalk pod 挂了
├─ Alertmanager 配置被覆盖
└─ 钉钉群被解散/机器人被移除A 旗舰教训:resolved 通知黑洞——firing 含"告警"关键词过关,resolved 只含"恢复"被钉钉拒绝,业务方以为告警没了实际从没收到恢复消息。
治理:
- 钉钉群关键词覆盖"告警/运维/恢复"三个全集
- 每周主动发测试告警验证链路
- 死机开关(Watchdog)作为告警链路的持续验证
- 切群/换 adapter 时必须 curl 测试 firing + resolved 两类消息
22. 一个服务最近一周 MTTR 明显上升(从 15 分钟到 45 分钟)。怎么分析原因?#
参考答案:
决策树:
Step 1: 数据分析
├─ MTTR 上升是突然的还是渐进的?
├─ 是所有事故的 MTTR 都上升,还是某几次长事故拉高均值?
└─ 哪类事故的 MTTR 上升最明显?
Step 2: 分解 MTTR
MTTR = TTD(检测时间)+ TTA(响应时间)+ TTM(修复时间)
├─ TTD 上升 → 告警滞后或缺失
├─ TTA 上升 → on-call 响应慢
└─ TTM 上升 → 修复难度增加
Step 3: TTA 上升的原因
├─ on-call 人员不熟悉系统(新人?)
├─ 告警 Runbook 过时或缺失
├─ 升级链不畅(找不到能处理的人)
└─ 告警太多导致疲劳(先观察 5 分钟看是不是误报)
Step 4: TTM 上升的原因
├─ 事故复杂度增加(新架构?新依赖?)
├─ 回滚路径不通畅(镜像被清?配置丢失?)
├─ 排障工具不熟悉(trace 看不懂?日志找不到?)
└─ 跨团队协调耗时
Step 5: 治理
├─ 补 Runbook
├─ 培训 on-call 人员
├─ 简化回滚流程
├─ 混沌工程演练(提升修复熟练度)
└─ Postmortem 分析每次长事故的瓶颈治理:MTTR 是 SRE 的核心 KPI,必须每月 review。MTTR 上升是组织能力退化的信号,不能等闲视之。
23. Error Budget 已耗尽、发布正在冻结中,此时来了一个必须马上上线的紧急安全修复(比如正在被利用的 0day)。你怎么决策?#
参考答案:
这是错误预算政策成熟度的分水岭题——考的不是"敢不敢破例",而是"政策本身有没有为破例预留合法通道"。
决策:上。但走紧急变更通道——不是绕过流程,是走另一条更严的流程。
核心认知:冻结冻的是"功能发布",不是"紧急修复"。
- 错误预算耗尽 → 冻结的目的是"停止用新功能继续消耗可靠性、把工程力转向修稳定性"。
- 安全 0day、正在丢数据的 bug、合规红线、缓解正在发生的事故——这些不修的风险远大于发布的风险。用"预算耗尽"挡住安全补丁,是把政策当教条。
- 成熟的错误预算政策必须预写豁免条款:安全补丁 / 数据修复 / 合规变更 / 事故缓解可豁免冻结。豁免不是"谁喊重要谁上",而是事先定义好的类别 + 明确的审批人。
决策树:
紧急上线请求
│
├─ 1. 判定是否属于豁免类别
│ ├─ 安全漏洞正被利用 / 数据正在损坏 / 合规硬要求 / 事故缓解 → 属于,继续
│ └─ "很重要的新功能" → 不属于,冻结照旧(这是 Q16 的场景,不是本题)
│
├─ 2. 走紧急变更审批(比常规更严,不是更松)
│ ├─ 记录:为什么必须现在上、不上的风险、变更范围
│ ├─ 审批人:SRE Lead + 安全/业务 owner 签字背书
│ └─ 最小化变更面:只带这个修复,绝不夹带其他功能("搭便车"是大忌)
│
├─ 3. 更严的灰度 + 回滚预案(预算已耗尽,容错为零)
│ ├─ 灰度更慢更细:1% → 观察更久 → 逐级放
│ ├─ 回滚路径预先验证过(不能事故时才发现回滚也挂)
│ ├─ 专人盯 burn rate,任何异常立即回滚
│ └─ Feature flag 兜底:能秒级关闭最好
│
└─ 4. 事后
├─ 这次紧急消耗计入 Budget,但单独标记(区分"功能挥霍"和"安全必需")
├─ Postmortem:为什么预算会耗尽到"连安全修复都要挣扎"的地步
└─ 复盘豁免流程本身是否顺畅反模式:
- ❌ 教条冻结:拿"预算耗尽"当免死金牌拒绝安全补丁 → 组织被 0day 打穿,政策本身成了风险源。
- ❌ 借豁免夹带私货:以"紧急"为名把攒着的功能一起发 → 豁免通道被滥用,下次没人信。
- ❌ 紧急就跳过灰度直接全量:预算已为零,一旦这个"修复"本身有 bug,直接 SEV-1。越紧急越要小步。
治理:错误预算政策文档里必须写清三件事——① 豁免类别清单;② 每类的审批人;③ 紧急通道的强制约束(最小变更面 + 强制灰度 + 回滚预案预验证)。没有预写豁免的冻结政策,第一次遇到 0day 就会被现场推翻,政策公信力归零。
答题技巧:场景排查题的关键是结构化决策树。不要"先做 X 再做 Y"的线性思维,要"如果 A 则 X,如果 B 则 Y"的分支思维。每一步都用证据说话,不猜。框架:现象 → 排查(决策树)→ 根因 → 修复 → 治理。