PLFM_RADAR:我用开源组件自建的平台"雷达系统",如何做到秒级感知异常并及时止损
做平台的人都有一个共同的痛点:自己的系统在用户那边跑得好不好,很多时候是用户先发现的,而不是自己。用户报障之前,页面已经卡了好几分钟、接口已经超时了十几轮,而你完全不知道。等到群消息炸了、电话响了,你才开始到处翻日志,速度还很慢——明明监控大盘上绿油油一片,实际业务早已千疮百孔。
我自建了一套名为 PLFM_RADAR 的平台监控感知系统,把它当作平台的"雷达"来用——实时探测、全量扫描、异常识别、自动止损。上线三个月,线上隐患平均发现时间从原来的小时级压缩到了分钟级,有好几次在用户报障之前就完成了告警和处置。这篇文章就把这套系统的设计思路、核心组件、实操过程和踩坑记录完整拆开,希望对正在折腾自建监控的你有点用。
标题里的 PLFM_RADAR,说白了就是 Platform Radar——给运行中平台做全方位感知的一套监控告警体系。它能做什么?简单说三件事:一是把平台内部散落各处的日志、指标、链路数据统一收拢起来;二是通过一组规则和模型实时判断当前到底有没有异常;三是有异常时自动通知并触发预先配置的止血动作。适合正在做自建监控、想要摆脱"用户报障才知道故障"这种被动局面的开发和运维同学参考。
1. 内容整体设计与思路拆解
1.1 为什么叫"雷达"而不是"监控"
监控这个词在国内技术圈已经被用烂了,一提到监控,很多人脑子里还是那套老三样:CPU 多少、内存多少、磁盘多少。这些指标当然要看,但对于一个复杂平台来说,它们只是最底层的生理指标,类似一个人的体温和血压。真正常见的是:某个核心交易接口的 P99 延迟从 200ms 突然飙到 5s,数据库连接池被打满前的连接等待时间在悄悄爬升,某个服务的错误率已经连续 15 分钟超过阈值——这些都发生在应用层和业务层,传统的"基础监控四件套"根本看不出来。
所以我特意把它命名为 RADAR,就是想强调它的核心定位:主动探测、实时扫描、持续感知。雷达不是静静地看仪表盘,而是不停向周围发出探测波,检测反射回来的异常回波。平台也一样,不能等用户来报告,而要主动、持续地向自己各个边界发探测信号,一有异常回波立即告警,并尽量自动处置。
定位不同,设计思路就完全不同。
1.2 整体架构:三大子系统、两层防线
PLFM_RADAR 的架构整体分为三大块:
- 数据采集层(感知层):采集日志、指标、链路追踪数据,并主动发起周期性探测请求。
- 分析识别层(判断层):把采集到的数据做清洗、聚合、计算,通过规则引擎和单维度统计模型判断当前是否异常。
- 通知处置层(行动层):负责将异常事件发送到群聊、短信、电话等渠道,并触发预设的自动化止血脚本。
这三大块构成第一层防线——发现问题并通知合适的人。第二层防线则是基于"健康分数"的趋势预测——某些异常不是突然发生的,而是慢慢恶化的,比如磁盘占用的线性增长、慢查询次数的阶梯上升。靠人盯告警永远盯不过来,让系统在恶化到临界点之前就预警,才是最舒服的体验。
我实际落地的时候,把数据采集层分成了两条路。一条是被动采集,用轻量级采集器把服务和数据库的日志、性能指标全量收上来;另一条是主动探测,每 30 秒从外部视角对核心接口发一次模拟请求,确认整个链路从入口到出口是否真的通了。这两条路合到一起,才勉强算一个立体雷达。
1.3 为什么选择自建而不是上商业产品
说实话,市面上成熟的监控产品我基本都摸过,商业版的确实有些做得挺好,开箱即用、告警组件齐全。但我最后还是选择自建,主要原因有三个:
- 成本控制考虑。我们平台的核心接口数量有几百个,加上内部服务之间的调用链关系,如果按"节点数"走商业授权,一年的费用相当可观,而且这还只是基础设施监控,日志分析、链路追踪往往还要单独加钱。
- 深度定制需求。我想要的很多探测逻辑和识别规则是业务相关的,商业产品要么做不了,要么做得很浅。比如结算系统的异常特征,和内容推荐系统的异常特征完全不同,需要专用的识别逻辑。
- 数据主权问题。平台内部的一些数据不适合长期存放在第三方平台,自己建一套,从采集到存储到展示全链路可控,心里踏实。
自建不等于野路子。我用的核心组件都是业界成熟的:采集端用轻量代理,存储用时序数据库和日志检索引擎,告警编排用现成的规则引擎,自己写的部分主要集中在探测逻辑、特征规则和自动化处置脚本上。这样既保证了稳定性和可维护性,又保留了足够的定制空间。
2. 核心细节解析与实操要点
2.1 采集层的关键细节:全量 vs 采样,必须想清楚
采集层是雷达的"天线",天线出了问题,后面计算再精准都是空谈。我在这一层踩过的最大坑是"贪心"——一开始什么都想全量采集,结果数据量大到存储差点爆掉,查询速度慢成幻灯片。
后来我的取法是"分层配置":
- 核心业务日志:全部采集,一条不漏。这是审计和排障的第一手证据。
- 核心接口调用链数据:全部采样,但采样率保持 100%,因为核心接口的量级本身可控。
- 内部服务的系统指标:全部采集,频率 15 秒一个点。
- 业务日志和调试日志:按比例采样,默认 10%,需要排查时再临时调高。
日志采集器的配置里有个参数特别关键:flush_interval,默认写的是 5 秒。实际压测下来,对高并发服务如果采用 5 秒刷新一次,很容易造成日志积压和采集器内存飙升;调到 1 秒并配合批量压缩后,内存占用直接降了三分之一多。具体产品差异还挺大的,建议在自己的环境里多跑几轮压测再确定,不要把默认值当真。
2.2 主动探测的具体实现逻辑
主动探测是 RADAR 区别于传统监控的核心。它本质上是在平台外部部署一组"探针",模拟用户请求从外网入口进入,横穿整个服务链路,最后验证出口和响应内容的正确性。
我在探针里做的不只是"请求成功/失败"这么简单。每次探测会带一个唯一标识,顺着网关、后端服务、数据库一路传下去,最终把整条链路的耗时和状态记录下来。这个标识还能和后端的链路追踪系统关联上,一旦探测失败,能立刻定位到具体是哪个环节拖慢了速度。
探针的请求频率也不要一刀切。对核心交易接口,我设置 10 秒一次;对普通查询接口,30 秒一次;对一些内部异步任务的状态查询接口,甚至 5 分钟一次就够了。主动探测是有成本的,频率越高对系统和网络压力越大,要找到一个大家都能接受的平衡点。
2.3 识别层的规则引擎:从静态阈值到动态基线
识别层是判断"有没有异常"的大脑。最开始我用的是静态阈值:比如 CPU 超过 90% 就告警,接口耗时超过 1 秒就告警。但很快就发现一个问题:不同服务、不同时间段的正常波动范围差异巨大。有些低峰期接口耗时只要 300ms,高峰期可能稳定在 800ms,这两者都是正常的。如果你把阈值固定为 500ms,就会早上没事、晚上疯狂误报。
后来我引入动态基线。系统自动学习过去 14 天同时间段(比如工作日上午 10:00-10:05)的指标分布,算出均值和标准差,当实时值偏离均值超过三倍标准差时才触发告警。这一改动把误报率降了至少 60%。
基线也不是万能的。新上线的服务没有历史数据,刚开始的动态基线会产生较多的误报漏报。我做了个"冷启动"豁免策略:新服务的规则引擎在头 24 小时内只记录不告警,攒够了数据再正式参与判断。这段时间足够它积累出一个相对靠谱的历史基线。
2.4 告警通知的分级策略
没有分级的告警等于没有告警。我刚上线 RADAR 的时候,把所有异常都往同一个群推,结果核心群一天刷几千条消息,真正重要的事件反而被淹没。后来我按 Severity 分成了三个等级:
- P0 级:核心业务完全不可用、数据丢失风险,必须立即处理。通知途径包括电话、短信、群消息同时触达。
- P1 级:核心接口性能明显劣化但不完全不可用,主要单条业务受影响。通知至相关技术群,@值班同学跟进。
- P2 级:边缘接口轻微异常、资源使用率趋势性上升,只需要在工作时段推送至技术群,记录跟踪即可。
分级规则不是一成不变的,每隔一两周就要根据实际告警效果调整一次。分级的目的不是分而不管,而是保证每个等级的事件都由匹配等级的人力和响应速度去处理。
3. 实操过程与核心环节实现
3.1 环境准备与基础组件选型
整个 RADAR 系统,我的基础技术栈如下:
- 时序数据库:用于存储监控指标数据(CPU、内存、请求数、延迟分布等),支持高并发写入和聚合查询。
- 日志检索引擎:用于集中存储日志数据,支持全文检索和复杂过滤。
- 采集器:部署在每个服务和宿主机上的轻量级代理,负责采集指标和日志并上报。
- 链路追踪组件:负责收集跨服务调用链数据,识别性能瓶颈和异常节点。
- 规则引擎:负责对时序数据和日志数据执行告警规则判断,生成告警事件。
- 可视化面板:用于将指标、日志、链路数据统一展示在一张大屏上。
需要说明的是,这些组件不是非某一家不可。技术上,Prometheus 搭配时序存储、ELK/EFK 做日志搜索,再配合一些轻量级的规则引擎来自定义告警逻辑,已经是非常成熟的组合。重要的是把链路打通:采集器把数据送到时序数据库,规则引擎按时序数据库的接口拿数据做计算,计算结果触发告警分发,分发之后再调用自定义的处置脚本。
3.2 关键参数的计算与配置过程
动态基线相关的几个阈值参数我直接给出来参考,这是我们经过多轮调优后稳定使用的:
- 基线周期:14 天。太短扛不住周期性波动,太长对近期趋势变化不敏感。
- 检测窗口:5 分钟。实时数据以 5 分钟为粒度做聚合,再和同时段的基线对比。
- 触发倍数:3 倍标准差。低于 2 倍误报太多,高于 4 倍漏报太多,3 倍是很多领域的常用选择。
- 持续确认周期:连续 3 个检测窗口都在基线外,才认为是真异常,规避瞬时抖动的影响。
- 冷启动时长:24 小时。此期间内只积累基线,不触发任何对该服务的告警。
关于 P0 级别的电话告警,这里分享一个细节:电话只有在连续触发 3 次(中间相隔 1 分钟)后才会真正拨打,而且 10 分钟内同一个事件只拨打一轮,不能一个事件反复震铃。我见过有团队被同一事件的电话告警连续轰炸,大半夜把三个人的手机都打没电了,这种体验太差了,处理问题的人反而被噪音折磨。
3.3 核心逻辑的落地实现方式
规则引擎是整个 RADAR 的核心计算单元。在落地时,我把规则划分为三类,每一类的处理逻辑都不同:
第一类是阈值规则,简单直接:比如"错误率大于 5% 持续 2 分钟就告警",这类规则只需要将实时计算值和既定阈值做比较,适合记录和运算量都相对较小的场景。
第二类是趋势规则,用于发现慢变问题不可替代:比如"磁盘使用率在 7 天内的日增量超过 2 个百分点",或者"内存增长速度持续 24 小时为正"。这类规则不是判断当前值是否超标,而是判断指标变化的斜率是否异常。趋势规则的实现方式通常是对历史序列做线性回归,看系数大小和符号。
第三类是上下文规则,把多个指标的异常组合起来判断:比如"接口延迟升高 + 而同时间段内错误码数量显著增加 + 数据库活跃连接数上升",这三个信号同时出现,基本可以判定数据库侧存在问题。上下文规则能大幅减少误报,而且能给出初步根因方向。
规则不只能通过配置文件静态下发,我还提供了动态下发的能力——在可视化面板上临时启用某个服务的高频采样或临时调整某个规则的触发阈值,专门用于排查问题时的灵活操作。实测下来这一点很实用,不用重新部署规则引擎就能立刻调整探测强度。
3.4 自动止血脚本的执行链路
RADAR 第一版只做通知,不做事。告警发到群里,人来了才开始手动排查。后来发现真正致命的问题往往在半夜,等值班的人被电话叫醒、打开电脑、登录系统,业务已经挂了十几分钟。所以第二版加了自动止血能力。
自动止血不是自动驾驶,它只做有限范围内的预定义动作,而且有一个原则:宁可少做,不可做错。实际中我配置了几类脚本:
- 服务自动重启:当服务进程假死超过 1 分钟且无法自行恢复时,自动拉起新进程并摘除问题节点。
- 限流降级:当核心入口的流量超过预估承载上限的 80% 时,自动开启限流,优先保护关键用户和核心链路。
- 缓存/连接池自动清理:当检测到连接池耗尽前的异常增长,自动触发连接池重建,避免雪崩。
- 备份自动扩容:当存储空间剩余低于 15% 时,自动清理已经归档的临时文件和超期日志。
每个自动动作执行后,都会生成一条审计记录,且可以在 5 秒内一键回滚。自动处置不是代替人来决策,而是把等待决策期间的损失降到最低,把最终决策权始终留给人。
4. 常见问题与排查技巧实录
4.1 告警风暴:一小时内收到几百条告警
第一次真正体会到"告警风暴"是在一个核心数据库节点抖动的时候。某一个节点的不稳定,导致依赖它的所有服务都开始报错,每个服务的错误率都触发了一条告警,一个人在一个小时内收到了三百多条告警消息,基本等于废了。
后来我针对告警风暴做了三件事:
- 告警聚合:同类告警(同服务、同错误码)在 30 分钟内只发一条,状态持续更新,不再重复轰炸。
- 依赖抑制:当根因告警(例如数据库集群故障)已触发时,其引发的下游派生告警自动降级为“静默记录”,控制台可见但不推送给任何人。
- 全局熔断:如果 5 分钟内的告警总量超过 200 条,则自动暂停当前所有非 P0 告警推送,只保留核心告警。
这三板斧下去之后,告警风暴再也没把人淹没。而且依赖抑制还有个额外好处——告警自动携带了"这是根因还是衍生"的标识,值班者打开告警列表,第一眼就知道真正该盯的是哪条。
4.2 动态基线的误报重灾区:版本发布后的数据偏移
动态基线有一个天然的敌人:发布变更。每次上线新版本,服务的各项指标就会产生一段时间的剧烈波动——这其实是正常现象,因为新代码可能优化了性能,也可能引入了新的资源消耗模式。但动态基线不知道这些,它只会机械地认为"和过去 14 天不一样了,异常!"
我的规避方案是"发布豁免期":
- 发布系统在发布完成的瞬间,会自动通知识别层:某服务已发布,请该服务进行基线白名单豁免。
- 豁免时长为发布后 2 小时,这期间该服务产生的指标不参与告警判断,但仍然会完整记录。
- 两个小时后自动恢复告警判断,并以新的数据模式动态调整基线。
这个设计很起作用,把发布导致的误报基本清掉了。而且时间窗口的设定我特意控制在"发布+稳定观察"两小时,不长不短刚刚好。
4.3 慢查询引发的连环故障排查实录
有一次线上出现"系统整体变慢但各项资源指标看着都正常"的问题。CPU 不算高,内存不算满,磁盘 IO 也没到瓶颈,每个服务单独看健康面板都没明显毛病。这个场景正是 RADAR 这类平台感知系统最怕、也最能体现价值的地方——单服务视角看不出来,需要靠链路视角和上下文规则来定位。
这次排查的完整过程是这样:
- 第一信号来自上下文规则:某个核心接口的调用链数据中出现了"数据库调用耗时占比超过全链路时长的 70%",这个信号单看接口延迟指标是发现不了的。
- 顺着链路追踪往下钻取,发现慢的只出现在某一条 SQL 上,其他 SQL 倒是都正常。
- 再去看数据库侧审计,发现这条 SQL 的执行计划和昨天相比产生了变化——统计信息过期后,数据库优化器选了一条错误的执行计划,导致本应走索引的查询变成全表扫描。
定位之后处理起来就快了:手动刷新统计信息并给关键查询加了固定的执行计划绑定。整个过程约 40 分钟,大部分时间花在链路定位上。如果没有 RADAR 的链路追踪和上下文规则,这种问题光靠人肉查日志,少说要半天起步。
4.4 排查技巧和避坑清单
把这段时间整理出的几个核心排查技巧直接列在这里:
- 先看告警的"根因/衍生"标记,永远从根因告警入手排查,不要一上来就被衍生告警带走。
- 主动探测失败时,优先查"入口设备"和"第一个依赖外部组件的服务",大多数链路断裂都发生在边界点。
- 动态基线出现异常时,先确认最近 24 小时内是否有上线动作,再考虑是不是基础设施波动,最后才怀疑代码问题。
- 日志关键词不要死盯"error""exception",很多故障日志是用 warn 甚至 info 级别输出的,配合链路追踪的报错节点来关联日志会更准。
- 任何自动止血脚本上线前,一定要做一轮完整的演练,并且要有快速回滚通道,不能没有退路就上自动处置。
4.5 存储与查询性能的优化经验
随着采集的数据量增加,时序数据库和日志存储的查询性能会遇到瓶颈。我的体感是,超过一定规模后,所有监控系统的瓶颈都会从功能转向性能。
- 指标采样:对超过 30 天的历史指标自动降采样,例如 15 秒粒度保留 30 天,5 分钟粒度保留 180 天,1 小时粒度永久保留。这样可以大幅降低存储开销。
- 日志冷热分离:将 7 天以上的日志数据迁移到低频存储中,日常查询入口不对冷数据走全文检索,只支持按标识精确检索。
- 核心服务高基数字段的处理:对调用链数据的标签字段做白名单机制,有些字段基数太高,如果全部入库,会让存储膨胀得非常厉害。
这些操作看着不起眼,但对长期运行的监控系统来说,是保证查询秒级返回的关键。
5. 事后复盘与持续演进
5.1 每一次大故障都要有一次复盘
我对 RADAR 系统有两条铁律:第一,系统本身是工具,该被替代时就要果断换掉;第二,每一次大故障后,必须对 RADAR 本身的探测和识别能力做一次"二次审查"。
"二次审查"要回答三个问题:
- 这次故障,RADAR 在哪个环节发挥了作用,最早的探测信号是什么?
- 这次故障里,哪些指标和规则是盲区,为什么没有在第一时间捕捉到?
- 是否需要调整探测频率、基线的参数,或者新增一条规则来覆盖这次的故障类型?
只要回答完这三个问题,并落实具体的配置变更,这套系统就完成了一次自我进化。故障不可怕,可怕的是每次都在同一个类型的问题上跌倒。
5.2 存活的一个小技巧:模拟故障演练
很多系统一年到头没有真正的大故障,所以大家都不知道 RADAR 到底管不管用。我的建议是主动制造故障——在预发环境中定期做"混沌实验":随机杀掉一个核心服务进程、随机网络丢包、随机给数据库制造高负载,看看 RADAR 能不能在预期时间内发现,并触发对应的告警。
第一次演练的时候,效果特别真实:服务进程被杀掉后,主动探测大概 30 秒就发现了异常,但通知没有按预期到达,排查后才发现告警分发组件没有注册到主动探测的通道。这个过程比任何文档都直观,演练暴露出来的都是配置层实际存在的问题,而这些问题恰恰是真实故障时最容易拖后腿的。
5.3 健康分:从"有无告警"到"平台整体状态"
最后分享一个正在演进的方向:平台健康分。单一告警只能回答"某个指标现在是否正常",但管理者更想知道"整个平台现在值不值得信任"。所以我在 RADAR 之上加了一个综合健康分——由六类因素加权计算:核心接口可用性、核心接口性能水平、错误率、资源使用度、依赖组件健康度、未处理告警的影响权重。
健康分以 10 分钟为粒度实时刷新,达到阈值时可视化面板上的颜色会动态变化。这个分的作用不是让技术人员盯着看,而是给非技术同事一个直观的感知:平台当前运行状态好不好。我个人的目标是让这个分数成为一个真正有公信力的、所有人都看得懂的数字。
PLFM_RADAR 这个项目对我而言最大的意义在于:它把"被故障推着走"变成了"主动寻找故障"——主动探测、动态识别、自动止血、持续演进。做这套系统最重要的不是技术选型有多酷,而是每一个环节都贴合自己平台的真实状况。如果你也在做类似的自建监控系统,建议从小范围开始,先覆盖一两个最核心的链路,跑通之后再逐步扩大,让系统跟着业务一起成长。