PLFM_RADAR:构建主动发现异常的监控雷达系统 PLFM_RADAR 是我最近在内部推进的一个监控项目的代号PLFM 取的是 Platform 的缩写RADAR 则是整套路线的灵魂——它不追求把每个平台的日志和指标搬到一个大而全的仓库里而是像雷达一样持续扫描各个业务系统的运行状态把异常主动暴露出来。这套项目解决的是很多团队都遇到过的老问题监控工具装了一大堆大盘几十个可每次线上出事反而要翻半天图表才能定位到是哪条链路出了问题。如果你正在搭监控体系或者对自己维护的平台心里没底、总觉得“好像该盯点什么但不知道从哪看起”这篇内容很适合你。我会把 PLFM_RADAR 从设计思路、组件选型、核心配置到踩坑记录完整拆开讲全部基于我实际跑过的方案不是什么概念堆砌。你照着搭一套最小可用版本大概一个晚上就能跑起来。1. 项目定位与整体设计1.1 为什么叫“雷达”而不叫“监控平台”起这个名字不是图好听而是为了锚定一个核心观念监控平台的职责不是“把数据存下来给需要的人查”而是“主动发现问题并让人快速做出判断”。传统监控体系最常见的失败模式就是数据都有了但人还是不知道当前系统到底健不健康。我见过太多团队把 Prometheus 搭起来、Grafana 面板配了几十个然后就没有然后了。真出故障的时候告警要么没触发要么一口气刷几百条值班的人直接选择屏蔽群消息。PLFM_RADAR 在设计的第一天就把目标定成三句话每个平台至少有一套能表达“是否健康”的核心指标而不是一堆不知道该看哪个的杂散指标异常必须通过告警主动触达负责人而不是等用户投诉之后才去翻图值班界面必须能在 30 秒内回答出“现在到底有没有事、事在哪里、趋势是变好还是变坏”所以 RADAR 在这里不是指某一个单一工具而是一整套从采集、存储、告警到呈现的闭环。它的核心是一套统一的指标口径和告警收敛策略工具本身没有用新东西都是大家熟知的 Prometheus、Alertmanager、Grafana 这套栈但“怎么把雷达扫描的逻辑落到配置里”跟普通监控搭法的差别非常大。1.2 整体架构选型还是熟悉的开源栈但分层逻辑很关键PLFM_RADAR 的架构我保持了足够的克制没有引入过重的组件。这背后的考虑很实际能跑在 Docker 里的东西就不要先上 Kubernetes一个 Prometheus 能拉的指标就不要为了“微服务化”拆成三个服务。架构不是越复杂越显得专业而是越简单越容易活下来。整体分四层采集层以 Prometheus 的 pull 模式为主各类 exporter 负责吐出指标中间件平台通过自定义 exporter 或接入 PushGateway 上报业务指标。为什么优先 pull因为 pull 模式让 Prometheus 主动控制采集节奏能准确感知“目标挂了”这件事这对雷达扫描来说是基础能力。存储层Prometheus 自带的 TSDB 作为近期数据存储默认保留 15 天每天做一次快照备份。超过保留周期的历史数据用 Thanos 的 sidecar 模式把数据归档到对象存储用来做月级趋势对比。这套组合的好处是接入成本低后期扩展不推翻重来。告警层Alertmanager 负责所有告警的路由、分组、抑制和静默。雷达的“主动”就体现在这里没有告警的监控只能叫录像机。展示层Grafana 提供统一视图我在上面做了三套核心面板全局雷达总览、单平台状态详情、告警事件时间线。这套架构跑下来单机 Prometheus 扛住了几十个目标、十几万时间序列的常态负载查询响应都挺稳。如果你的平台数量比这大一个数量级再考虑 Prometheus 联邦或者 Thanos 的 Receive 模式但绝大多数团队真用不到那一步。2. 核心模块拆解与实现要点2.1 指标设计黄金信号是底座但做了两处改造PLFM_RADAR 每个平台统一关注四类指标延迟、流量、错误、饱和度也就是 Google SRE 那套著名的黄金信号。四类信号放在一起基本能把一个服务“目前到底行不行”描述清楚。我对这套框架做了两处定制。第一处是给每个平台额外加了一个“业务成功度”指标。比如登录服务的 4xx/5xx 比例、订单系统的支付成功率。纯技术指标能告诉你服务线程池有没有满但只有业务指标能告诉你用户真正在意的事是不是正在坏掉。很多站在技术和业务交界处的故障纯靠黄金信号看不出来。第二处是给所有平台定了一个统一的“健康分”计算规则。每个平台按权重汇总四类信号的偏离程度输出一个 0 到 100 的分数低于 80 就触发预警低于 60 直接告警。这个分数不是拍脑袋算的而是把每个指标跟它的历史基线做对比偏离越大扣分越多。这样值班的人不需要看懂每个图先看数字就够了。2.2 告警收敛没有收敛机制的告警系统等于没有告警告警收敛是 PLFM_RADAR 里我最看重的部分也是大部分团队最容易翻车的地方。你想象一下一个核心服务出了故障如果告警规则写得粗放瞬间会有二三十条告警同时涌出来每一条看起来都很急结果就是值班人神经麻痹真正致命的告警混在里面没人重视。Alertmanager 提供三个收敛手段我全部用上了分组把同一平台、同一时间窗口内、属于同一类别的告警合并成一条通知。比如订单服务挂掉所有下游依赖产生的告警会被归到同一个分组里通知里列出受影响的目标列表而不是刷屏。抑制当一条更高级别的告警比如服务完全不可用触发时自动抑制同一来源的低级别告警比如某个接口延迟升高。否则高等级告警反而会被自己的子告警淹没。静默维护窗口期间主动屏蔽已知告警比如发版、运维变更、压测。静默必须设置过期时间谁也不想看到一条两周前的静默规则一直挂在那边。配置收敛规则不是一次性的事每次线上发生告警风暴之后我都会回头审视规则看哪些告警本可以被抑制掉。雷达是要持续校准的不是配一次就一劳永逸。2.3 雷达视图让“看状态”替代“看图表”Grafana 面板不是越多越好每多一块图值班人就要多消耗一分注意力。PLFM_RADAR 的默认视图刻意保持精简就三块全局雷达总览是一张大表每一行对应一个平台核心字段是健康分、当前告警数、昨日可用率、最近一次异常时间。这张表的作用是让值班人进门 30 秒内知道全平台是否平安。哪个平台分数飘红再点进去看详情。单平台状态详情页包含四类黄金信号的趋势图、健康分拆解哪类指标在拉低分数、当前活跃告警列表。因为采集频率是 15 秒延迟类指标都做了 1 分钟、5 分钟、15 分钟三条曲线能区分瞬时抖动和持续劣化。告警事件时间线记录每一次告警的触发、恢复、静默、抑制事件。排查故障时这条时间线比聊天记录靠谱得多。很多疑难杂症都是事后回放时间线才找到因果关系的。3. 实操过程从零搭建一套可用的雷达系统3.1 环境准备一台机器一条 Docker Compose 就能起步我先把最小可用版本的组件列出来全部跑在 Docker 里。这里不会给你堆一个庞大的编排文件而是拆开讲每个组件扮演什么角色。组件镜像作用默认端口Prometheusprom/prometheus:v2.47.0指标采集与存储9090Alertmanagerprom/alertmanager:v0.26.0告警路由与收敛9093Grafanagrafana/grafana:10.1.0可视化大盘3000Node Exporterprom/node-exporter:v1.6.0主机指标采集9100在真正动手之前有一个关键步骤规划采集目标清单。别小看这一步雷达要扫描多少平台、分别暴露哪个端口、由谁负责这些信息如果不在动手前梳理清楚后期就是不断补丁。我会建议你准备一份简单的表格先列出前 10 个最关心的平台及其指标端口而不是在配置里随便写。3.2 Prometheus 配置采集规则和告警规则的写法下面是 prometheus.yml 里最核心的配置片段我加了注释说明为什么这样写。这份配置是纯手写的没有用任何生成器因为你自己要能读懂每一行的含义后面排查问题才不慌。global: scrape_interval: 15s # 默认采集间隔雷达的扫描周期 evaluation_interval: 15s # 告警规则评估周期必须大于等于采集周期 external_labels: cluster: default # 区分集群后面接 Thanos 或联邦时靠它隔离 scrape_configs: - job_name: platform-gateway metrics_path: /metrics static_configs: - targets: [gateway.internal:9090] relabel_configs: - source_labels: [__address__] regex: (.*):.* target_label: instance replacement: $1 - job_name: business-order metrics_path: /prometheus static_configs: - targets: [order-service.internal:8080] - job_name: node-exporter static_configs: - targets: [node1.internal:9100, node2.internal:9100]采集间隔选 15 秒而不是 5 秒是我权衡过的结果。5 秒采集对大多数业务系统过于频繁指标曲线看不出额外信息反而把磁盘 IO 和 Prometheus 自身的 CPU 消耗推高。15 秒在“秒级抖动”和“分钟级趋势”之间取了一个平衡点。如果你的服务有非常强的瞬时流量特征可以在特定 job 上覆盖成 10 秒但全局别低于 10 秒。3.3 告警规则阈值怎么定才不拍脑袋告警规则是整个雷达能否“智能”的关键。我的经验是能用速率/趋势表达的就不要用绝对值能预测的就不要等它真出问题。下面这条是磁盘空间告警规则用的是 predict_linear 预测函数结合过去 6 小时的数据预测未来 24 小时的磁盘使用量。如果预测值超过 85%就触发告警。这样做的好处是在磁盘还没写满之前就给你预留了处理时间而不是真的等磁盘满了才收到“磁盘空间不足”的告警。groups: - name: platform-saturation rules: - alert: DiskWillFillIn24h expr: predict_linear(node_filesystem_avail_bytes{mountpoint/}[6h], 3600*24) / (node_filesystem_size_bytes{mountpoint/} * 0.15) 1 labels: severity: warning annotations: summary: {{ $labels.instance }} 磁盘预计在24小时内写满 description: 当前剩余空间按历史消耗速度预计在 {{ $value | humanizeDuration }} 后耗尽阈值 85% 是我自己偏好的一个值你可以根据自己的磁盘容量和扩容响应速度调整。关键不是 85% 还是 90%而是你用了预测而不是简单比较剩余空间绝对值。这背后的原理是 predict_linear 会考虑磁盘消耗的速率变化把“趋势”纳入告警判断比单点阈值聪明得多。再看一条错误率告警我用的是速率判断并且加了一个最少样本量的条件避免因为数据稀疏造成误告警- alert: HighErrorRate expr: | sum(rate(http_requests_total{status~5..}[5m])) / sum(rate(http_requests_total[5m])) 0.05 and sum(rate(http_requests_total[5m])) 1 labels: severity: critical annotations: summary: {{ $labels.instance }} 5分钟错误率超过5%这里有两个值得注意的细节。一是 5 分钟速率比 1 分钟速率更平滑能过滤掉偶发的单次请求失败。二是我加了一个“请求量必须大于每秒 1 次”的前提条件否则一个几乎没人访问的测试接口偶尔被扫一次就容易出现错误率 100% 的假警报。3.4 Alertmanager 路由配置让告警找到该去的人告警规则负责判断“有没有事”Alertmanager 负责决定“通知谁、怎么通知”。我的路由策略按两个维度拆分平台维度决定通知哪个团队严重级别决定通知方式。warning 级别的告警只发协作群critical 级别的告警额外电话或短信。route: receiver: default group_by: [alertname, instance] group_wait: 30s group_interval: 5m repeat_interval: 4h routes: - match_re: severity: critical receiver: oncall-critical repeat_interval: 1h receivers: - name: default webhook_configs: - url: http://notify.internal/robot/send - name: oncall-critical webhook_configs: - url: http://notify.internal/robot/send-criticalgroup_wait 设 30 秒是个容易忽略但很实用的参数。它的意思是同一个分组里的告警先等 30 秒再发送。这 30 秒里如果有同组的新告警产生就会合并到一起发而不是每条单独通知。你可以理解成雷达扫描到异常后先花半分钟确认一下是不是大面积异常再决定怎么播报。这个设计能省掉大量重复通知。3.5 Grafana 面板健康分和雷达总览的核心查询Grafana 面板我不打算从头手搓一大段详细教程而是讲清楚最核心的那个“健康分”是怎么查询出来的。健康分的计算思路是对每个平台选取延迟、错误率、饱和度、业务成功率四类指标分别跟各自的历史基线比较获得一个 0 到 100 的子分数然后加权求和。我用的不是 PromQL 里现成的函数而是 Grafana 的阈值和数学表达式把多个查询结果按权重叠加。举例来说延迟子分数的查询大约长这样clamp_max(1 - (histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) / 0.3), 1) * 100这里 0.3 秒是我设定的 95 分位延迟红线。当实际延迟等于红线时子分数变成 0远低于红线时无限接近 100。四类指标各占不同权重错误率 40%、延迟 25%、饱和度 25%、业务成功率 10%。权重不是固定的得根据平台特性调。比如支付类平台业务成功率权重可以拉到 25%底层基础设施平台饱和度权重应该更高。你可别小看这个“健康分”它定义了你说的“雷达扫描结果”到底是什么。没有它值班人还是需要自己看图判断那雷达就只是个大号计数器。4. 常见问题与排查技巧实录4.1 指标采集端拉取不到数据、漏点、时间戳不连续Prometheus 拉取数据失败是遇得最多的问题。你可以先在 Targets 页面看谁的采集状态是 DOWN点击进去能看到最后一次抓取错误。我遇到过三种典型情况。一是 exporter 的 /metrics 接口偶发超时Prometheus 默认把超过 10 秒的抓取视为失败导致曲线出现规律的“梳子状”断点。解决方式是给特定 job 设置 scrape_timeout 稍微大一点比如 20 秒同时排查 exporter 自身为什么慢。第二种是 Docker 里部署的 exporter 端口映射只绑定了 127.0.0.1Prometheus 在容器网络里根本访问不到。你看到的报错是 connection refused但本地 curl 一切正常。排查时不要只看 Prometheus 的抓取报错先确认目标端口在哪个网卡上监听。第三种是时间戳不连续。有些业务服务的自定义指标是通过 push 模式上报的上报进程重启后指标时间戳会出现一个大的空档。Prometheus 看的是时间戳而不是接收顺序导致曲线出现奇怪的回退或断档。这里我的排查习惯是先观察一个指标在 Prometheus 里的原始时间戳如果发现相邻两个样本时间戳间隔远大于采集间隔优先怀疑上报方而不是 Prometheus。4.2 告警端误报、重复通知、告警恢复排查误报的比例是判断监控系统是否成熟的核心指标。如果误报太多值班的人会越来越不信任告警等于雷达白做。我处理误报的思路是给规则“加条件”而不是直接删规则。比如前面提到的错误率规则加“请求量下限”、磁盘预测规则加“过去 6 小时必须有有效数据”这些都是最常用的“去误报”手段。重复通知的问题大部分是 repeat_interval 配太短导致的。如果你的场景不是那种需要在几分钟内持续强提醒的故障理论上 repeat_interval 不应该小于 1 小时。我见过有团队把 repeat_interval 设成 5 分钟结果一个持续性的磁盘告警一天给值班人发两百多条消息这已经不是在帮忙而是在制造另一种形式的故障。排障告警不恢复的时候要分清是“问题真的没好”还是“恢复条件没满足”。我最常犯的错是恢复条件跟触发条件写得不对称。比如触发用 predict_linear 预测未来 24 小时磁盘写满但恢复条件还是写“当前使用率低于 85%”结果告警触发后一直到预测窗口滑过去了才恢复。这类问题排查思路很简单把 Alertmanager 里的活跃告警拿出来逐条对比它的触发表达式和恢复表达式看看是否存在不对称。4.3 时间同步与数据精度最容易忽略的两件小事我再说两个跟具体组件无关、但很容易被忽略的细节。第一个是服务器时间同步。如果业务机的时钟比 Prometheus 慢 3 分钟那么所有 CPU、内存、磁盘的历史曲线都会错位。你在排查一个 14:05 发生的故障看到 14:02 的 CPU 曲线突然升高就会判断错时间点。监控系统对时间一致性的要求远比普通应用高。所有参与采集的节点我都建议统一使用 NTP 服务并且定期检查时钟偏移。第二个是容器环境下的指标语义。在容器里看到的 /proc 数据和宿主机上的不一样比如 node exporter 直接跑在容器里看到的内存总量可能是宿主机全量内存而不是这个容器的限额。PLFM_RADAR 在采集容器指标时会优先用 eg 这类带 cgroup 语义的工具或者在指标上打上容器标签。这个问题在混部场景特别重要你要是没处理过很可能在某个深夜被一例“容器 CPU 持续 100% 但宿主机很闲”的现象搞到怀疑人生。5. 一点亲身踩坑后的复盘PLFM_RADAR 上线之后我并没有一次性把告警配置“完美”收尾。真正的调试高峰是在上线后的一周内每天都有新的误报、漏报、重复报冒出来。我会每天截图当天的告警记录归类哪些是有效告警、哪些是配置问题、哪些是系统此前就存在但没人发现的隐患。三类各自占比大概五三二这个复盘习惯让我很快把规则从“能用”打磨到“好用”。如果你现在也要做这么一套雷达系统我个人的建议是把预算时间拆成三份一份给采集部署和指标梳理一份给告警规则的反复试错还有一份留给团队磨合。最后这份特别容易忽略告警通知是会打扰人的你的值班团队需要时间去适应“雷达开始说话了”这件事也需要明确反馈“哪些告警看了想摔手机”的意见渠道。监控系统的价值不是看它接入了多少平台而是看在真实故障发生时它能不能让一个人冷静地说出一句“现在有 X 个问题第一个是 Y我马上去看 Z”。做到这一点PLFM_RADAR 就算真正跑通了。