2. 故障排查方法论:MTTR 模型、日志分层策略、告警分级机制

做实时特征平台这几年,我最大的感触是:故障一定会来,区别只在于你多久能发现、多久能恢复。今天咱们就聊聊故障排查的底层逻辑——MTTR 模型、日志怎么分层、告警怎么分级。这些东西看着是方法论,其实都是血泪换来的。

2.1 MTTR 模型:把故障时间拆开看

MTTR 全称 Mean Time To Repair,平均修复时间。但说实话,我更愿意把它拆成四个阶段:

阶段 英文 说明 我见过的典型耗时
发现 MTTD 从故障发生到有人感知 30秒~5分钟
定位 MTTI 从感知到找到根因 5分钟~2小时
修复 MTTR 从定位到恢复服务 1分钟~30分钟
复盘 MTTA 从恢复到完成复盘 1小时~1天

你看,真正花时间的往往是定位阶段。我记得有一次线上特征延迟,团队花了 3 个小时才找到原因——原来是 Kafka 的一个 broker 磁盘满了。如果日志和告警设计得好,这个时间完全可以压缩到 10 分钟以内。

核心思路:不要试图优化所有阶段,先盯着 MTTI(定位时间)打。定位快了,整体 MTTR 自然就降下来了。

2.2 日志分层策略:别让日志变成噪音

很多人喜欢打日志,恨不得每行代码都打一条。结果呢?故障来了,日志文件几十个 G,根本看不下去。我个人的习惯是按层级管理日志,就像整理衣柜一样——常穿的挂外面,不常用的收起来。

2.2.1 分层模型

我把实时特征平台的日志分成四层:

  • L1 - 业务日志:记录特征计算的核心链路。比如「用户 12345 请求特征 A,耗时 12ms,结果返回成功」。这是排查业务问题的一手资料。
  • L2 - 系统日志:记录组件状态。比如 Kafka 消费延迟、Flink checkpoint 失败、Redis 连接池耗尽。这些是排查基础设施问题的关键。
  • L3 - 调试日志:记录详细参数和中间结果。平时不开,只有定位疑难杂症时才打开。比如某个特征值为什么算出来是 null。
  • L4 - 审计日志:记录操作行为。谁在什么时间改了配置、发布了版本、重启了服务。用于事后追责和合规。

我的建议:L1 和 L2 必须实时采集、实时索引。L3 可以写到本地文件,按需拉取。L4 走单独的存储,不要和业务日志混在一起。

2.2.2 日志格式规范

我曾经踩过一个坑:日志格式不统一,排查时 grep 出来的结果乱七八糟。后来我们定了统一格式:

[时间] [级别] [模块] [请求ID] [关键字段] 消息内容
示例:
[2025-03-15 14:23:11.456] [ERROR] [feature-calc] [req-abc123] [user_id=10086] 特征A计算超时,耗时2500ms

为什么要加请求ID?你想想看,实时特征平台每秒处理几万次请求,没有请求ID,你根本没法把一次请求的日志串起来。

2.3 告警分级机制:别让告警变成狼来了

告警太多,团队会麻木。告警太少,故障漏了。怎么平衡?我的做法是按影响面分级。

2.3.1 四级告警体系

级别 名称 响应要求 举例
P0 紧急 立即响应,5分钟内介入 特征服务全部不可用、数据延迟超过10分钟
P1 严重 15分钟内响应 部分特征不可用、延迟超过3分钟
P2 警告 1小时内响应 单节点故障、CPU超过90%持续5分钟
P3 通知 下一个工作日处理 磁盘使用率超过70%、日志报错率上升

注意:P0 告警必须走电话或短信,不能只发群消息。我见过不止一次,P0 告警发到群里没人看,等发现时已经过去半小时了。

2.3.2 告警去重与抑制

实时特征平台经常出现「告警风暴」——一个底层故障引发几十个上层告警。怎么处理?

  • 依赖关系抑制:如果 Redis 挂了,所有依赖 Redis 的特征计算告警自动降级为通知,不重复报警。
  • 时间窗口聚合:同一类告警在 5 分钟内只发一次,合并展示发生次数。
  • 静默期:人工确认后,同类告警静默 30 分钟,避免干扰修复过程。

2.4 知识体系总览

下面这张图把 MTTR 模型、日志分层和告警分级串在了一起。你可以把它当作故障排查的「作战地图」。

故障排查方法论 · 知识体系 故障排查方法论 MTTR 模型 日志分层策略 告警分级机制 发现 (MTTD) 定位 (MTTI) 修复 (MTTR) 复盘 (MTTA) L1 业务日志 L2 系统日志 L3 调试日志 L4 审计日志 P0 紧急 P1 严重 P2 警告 P3 通知 核心原则 1. 定位时间是 MTTR 的最大瓶颈,优先优化 MTTI 2. 日志按层级管理,L1/L2 实时采集,L3/L4 按需拉取 3. 告警按影响面分级,P0 走电话,P3 走工单 4. 告警必须去重和抑制,避免告警风暴

2.5 实战建议:从理论到落地

说了这么多,怎么落地?我分享几个实操经验:

  1. 先定告警,再写代码:每次上线新特征,先把告警规则写好。别等出问题了再补,那时候手忙脚乱。
  2. 日志必须带上下文:单条日志要有足够的信息独立判断。我曾经见过一条日志只写了「error」,连哪个模块、哪个请求都不知道,这种日志等于没有。
  3. 定期演练:每季度做一次故障演练,模拟 P0 场景。你会发现很多平时想不到的问题——比如告警没发出来、值班电话打不通、操作手册过时了。
  4. 复盘要写改进项:每次故障复盘,必须输出至少一个可执行的改进项。不要只写「加强监控」这种空话,要写「给 Redis 连接池添加告警,阈值设为 80%」这种具体动作。

一个小技巧:我习惯在代码里埋一个「健康检查」接口,返回当前服务的所有关键指标。故障时先调这个接口,能快速判断是哪个环节出了问题。比翻日志快多了。

嗯,以上就是故障排查方法论的三个核心。MTTR 模型帮你拆解时间,日志分层让你快速定位,告警分级确保你不会漏掉真正的故障。这三样东西配合好了,实时特征平台的稳定性就有了基本保障。