想象你是一家繁忙餐厅的后厨主管。每天,食材入库、炉火温度、出菜速度、洗碗间水量——每一项都在不断变化。如果只靠记忆,你根本说不清“今天中午 12 点的油温到底是多少”。于是你让帮厨每隔几秒就把关键数据记在本子上,这本“后厨流水账”就是时序数据库的雏形。但光记账还不够:油温过高会着火,冰箱温度骤升会让食材变质,洗碗机漏水会淹了库房——你需要一套“火警铃”规则,让问题出现时有人被叫醒、且不会被半夜的鸡毛蒜皮吵死。这篇文章,就是要带你从零搭建这样一套“后厨监控告警体系”:怎么记流水账、怎么把旧账浓缩省纸、怎么判断异常、怎么定铃声轻重、怎么排值班表。你会发现,一个可靠的监控告警系统,本质就是把“后厨经验”变成了一套能自动运转、分轻重缓急叫人的制度。

岗位关联

对 AI 从业者而言,这是从“调模型”走向“扛生产”的必修课——没有一套不误报不漏报的监控告警体系,再好的模型也只是信息孤岛里的玩具。学会它,你才能说自己真正“可观测”。

目录
  1. 可视化演示
  2. 指标采集
  3. 时序存储
  4. 降采样压缩
  5. 异常检测
  6. 告警规则
  7. 分级降噪
  8. 值班排班
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

动态演示时序数据库监控与告警策略的核心机制,通过入门/进阶/实战/优化四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

时序数据库监控与告警策略:时序数据 时序数据库监控指标采集与存储模 降采样策略与数据生命周期管理 核心机制可视化 时序数据库监控与告警策略整体架构与关键组件

指标采集

后厨里,帮厨小张每隔 5 秒就瞄一眼油温表、冰箱温度计和出菜口计时器,把数字念给记账的小李写进流水账。采集频率决定了这本账能精细到什么程度——每 5 秒记一次,能把瞬间的油温波动都捕捉到;如果改成每 5 分钟记一次,那中午爆炒高峰期油温冲到 220℃ 的危险瞬间就彻底错过了。时序监控的第一步“指标采集”,干的就是小张的活:用探针定时去抓取或接收各种指标。

技术实现上,采集有两条路线:抓取(Pull) 和 推送(Push)。抓取模型下,监控系统主动到被监控对象的 HTTP 端点去取数据(如 Prometheus 的 /metrics 接口),有点像大厨亲自到各灶台去读温度计;推送模型下,应用主动把指标发给监控系统(如 StatsD、Telegraf),相当于各灶台自觉把温度报到总台。抓取的好处是“谁来取、什么时候取”由监控方说了算,便于统一节奏;推送则更灵活,适合短生命周期任务(如离线批处理作业,跑完就没了,你得让它自己临死前喊一嗓子)。

采集频率的选择是一场博弈。频率越高,账本越厚,存储成本越高;频率太低又会漏掉瞬间尖峰。常用做法是:关键指标 5-15 秒采集一次,次要指标 30-60 秒一次。同时要给指标命名定规范,比如 cpu.usage.percent、db.query.latency.ms——命名不清的指标,就像账本上写着“那个啥”,三个月后再看,谁也看不懂。

时序存储

流水账本记满了“时间 + 数值”这样成对的数据:12:00:00 油温=180℃,12:00:05 油温=182℃……这种按时间顺序排列、每个时刻对应一个或多个指标值的数据,就是时序数据。时序数据库(TSDB)就是专门为这种“后厨流水账”优化的存储引擎,它明白你要查“昨天中午 12 点到 1 点油温的平均值”,而不是“名字里带油的菜有几道”。

时序数据库最核心的三个设计,都长在“账本”的特性上。第一是列式存储与压缩:同一时刻的几百个指标(CPU、内存、磁盘、网络……)会被拆开按指标列存放,同列数据是同一单位的数值,能压得很狠——就像把一整天油温的 17280 条记录,压成“起始值 + 增量 + 差值编码”,纸张省得惊人。第二是高并发写入优化:监控场景写多读少、且写入大都是追加,所以 TSDB 用 LSM-Tree 这类结构,把随机写变成顺序写,还支持批量写入,就像记账员把零散的数字先记在草稿纸上,每攒满一页再工整誊到总账。第三是数据生命周期管理:原始数据热度高保留 7-30 天,更老的转成聚合数据存一年以上(这就是下一节的降采样),到期自动删除,让账本总在一个“刚好够用”的体积。

为了支撑海量指标,TSDB 还引入了标签(Tag)概念。每条时序数据除了时间戳和值,还可以带一组维度标签,比如 host=web-01, region=华东。查询时按标签筛选,就像账本里多了“按灶台编号”“按厨师”的索引——要查“华东区所有 Web 服务器的平均 CPU”,一句话就能圈出几十万台机器的数据。

降采样压缩

流水账存得太细,三个月后查一次全年的油温趋势,硬盘要冒烟。后厨的聪明做法是:把每天 17280 条油温记录,按小时浓缩成一小段——记下“这小时最高温、最低温、平均温”三条数。这样账本从 17280 条缩成 72 条,纸省了 99% 以上,还保留了“哪小时油温异常飙高”这个最关键的信息。这就是降采样(Downsampling):对旧数据做有损压缩,用聚合值替代原始值,减少存储、加速查询。

降采样的核心参数是聚合窗口和聚合函数。窗口决定了“多长的数据浓缩成一条”,常见有 5 分钟、1 小时、1 天;聚合函数决定了“这一窗口你关心什么”——avg 反映平均水平,max 揪出最坏情况,min 关注最低谷,count 统计次数。对监控场景,max 尤其珍贵:它保留了“有没有超出告警线”的记忆,即使原始数据已删除,你仍能回答“昨天下午有没有超过 90% 的 CPU 峰值”。

降采样的“损失”到底丢在哪?答案是相位与瞬时细节。一个 5 分钟窗口内的 60 个原始点,聚合后只剩 1 个均值与 1 个极值——你再也无法回答“某一次 5 秒内从 30% 跳到 90% 再回落”的精确曲线了。但监控关心的从来不是“曲线长什么样”,而是“有没有突破边界”。因此设计降采样策略时,要按保留周期分桶:原始数据存 7 天(排查突发故障用),5 分钟聚合存 30 天(复盘趋势用),1 小时间聚合存 1-2 年(容量规划用)。每一级都像厨房把食材处理成半成品:新鲜期看全貌,中期看骨架,长期只看“够不够用”。

异常检测

账本记得再漂亮,关键还是“能不能看出油温要炸锅了”。后厨大厨的做法是靠经验:听他耳朵里“油锅开始哔啵响”,知道温度逼近临界点了。监控系统的异常检测,就是把这套“经验”变成可计算的规则。最朴素也最常用的离线规则,是固定阈值:CPU 使用率 > 85% 就报警。但固定阈值有个大毛病——不同时段“正常”的标准不一样:凌晨 3 点的 CPU 30% 正常,双十一大促的 CPU 30% 反而说明机器在偷懒。所以现代监控都倾向用动态基线:从过去 N 天的相同时段数据里,算出当前时刻的“期望区间”,实际值落出区间即异常。

动态基线最常见的算法是基于均值和标准差的 3σ 判异(即“三倍标准差”原则)。假设系统从历史数据算出:工作日上午 10 点的 CPU 均值 μ = 40%,标准差 σ = 5%,那么正常波动范围大约就是 μ ± 3σ,即 25% ~ 55%。如果此刻的 CPU 冲到 65%,它离均值超过了 3σ,在统计学上属于“小概率事件”——要么是真实故障,要么是缓存击穿之类的突发流量,总之值得探个头去看了。这个原理的数学表述如下:

要处理更细腻的场景,还可以叠加趋势突变检测:不光看当前值超没超基线,还看它比上一分钟涨了多少(例如 1 分钟内 CPU 上涨超过 20% 就预警),这就像大厨不光看油温表,还会注意到“油温上升的速度比平时快了一倍”——趋势抢先于绝对值发出信号。选哪一种,取决于你的指标脾气:温度计类指标适合阈值,流量类指标适合突变检测。

Anomaly(xt)={true,if ∣xt−μ∣>3σfalse,otherwise\displaystyle \text{Anomaly}(x_t) = \begin{cases} \text{true}, & \text{if } |x_t - \mu| > 3\sigma \\ \text{false}, & \text{otherwise} \end{cases}
动态基线是“带着记忆看数据”——它知道凌晨和高峰期不一样,周末和工作日不一样。用 3σ 画出的不是一条线,而是一条随昼夜自动呼吸的“正常走廊”。
  1. 历史均值的角色μ 是历史窗口内所有样本的平均值,是“正常水位线”,来自过去 N 天的同时段数据(例如 10:00-10:05 的所有 CPU 值)。它回答的是“这个时刻通常该是什么水平”。
    μ=1n∑i=1nxi\mu = \frac{1}{n}\sum_{i=1}^{n} x_i
  2. 标准差的角色σ 是历史数据的标准差,衡量“正常波动幅度”。如果 σ 小,说明这指标一直很稳,稍微偏离就要警惕;σ 大则说明波动本来就大,容忍度要高一些。
    σ=1n∑i=1n(xi−μ)2\sigma = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(x_i - \mu)^2}
  3. 比较与判定|x_t - μ| 计算新观测值与均值的差距,再拿它和 3σ 比。超过就触发异常,没超过就是正常噪声。这个“3“不是拍脑袋来的——正态分布下,数据落在均值 ± 3σ 内的概率约 99.7%,意味着”几乎不可能”发生,发生了就可疑。
    ∣xt−μ∣>3σ|x_t - \mu| > 3\sigma

告警规则

检测出异常只是第一步,接下来要回答更关键的问题:“谁来判断这算不算事?要不要喊人?喊谁?”后厨的做法是定规矩:油温超过 200℃ 持续 1 分钟,立刻关火并上报;超过 180℃ 持续 5 分钟,提醒大厨注意。监控系统的告警规则,就是把这套“厨房纪律”形式化:每个规则 = 触发条件 + 持续时间 + 严重级别 + 通知对象。

其中最容易被忽略、也最能救命的参数是持续时间(for)。比如“CPU > 85%“这个条件,如果一超过就告警,系统会被偶发抖动轰炸——就像油温在 180℃ 边缘反复横跳,你总不能每次跳上去就拉火警铃。正确的姿势是加一个”持续观察期“:CPU > 85% 持续 5 分钟才告警。这个 5 分钟的等待期,天然过滤掉了瞬时毛刺。数值上,告警判定就是对一段连续窗口的布尔序列做”全部为真”的确认:窗口起点到当前时刻,规则条件一路成立,才算触发。

告警规则还必须处理恢复(resolve) 这一半生命周期。规则触发后进入 IN ALERT 状态,此时如果条件不再成立(例如 CPU 回落到 70%),经过一个“恢复等待期”后就要发出恢复通知。只报喜不报忧、只触发不恢复,会让值班人员面对永远亮着的红灯逐渐麻木——这正对应“狼来了”效应的退化:告警不再有信息量。所以优秀规则设计成三段式:

规则的编排也讲究“金字塔结构”:基础规则(单指标阈值)铺底,聚合规则(多指标联合判断,如“CPU 高且 QPS 低”才是异常)收窄,依赖规则(如“数据库不可用”时抑制上游“应用延迟高”的告警)防止连锁误报。就像后厨的规矩有层次:单灶台异常,灶台负责人处理;整个排风系统坏了,才叫消防。

RuleState={IDLE,xt<thresholdPENDING,xt≥threshold, t<forFIRING,xt≥threshold, t≥forRESOLVED,xt<threshold after FIRING\displaystyle \text{RuleState} = \begin{cases} \text{IDLE}, & x_t < \text{threshold} \\ \text{PENDING}, & x_t \ge \text{threshold}, \ t < \text{for} \\ \text{FIRING}, & x_t \ge \text{threshold}, \ t \ge \text{for} \\ \text{RESOLVED}, & x_t < \text{threshold after FIRING} \end{cases}
告警规则的核心在于“防抖 + 确定性 + 有始有终”。持续时长过滤噪音,状态机保证告警不丢不重,恢复通知让人不麻木——三条都能守住,告警才可信。
  1. 空闲态理解初始状态是 IDLE,指标值 x_t 低于阈值 threshold,一切正常。这个状态占据 99% 的时间,不需要任何动作。
    IDLE:xt<threshold\text{IDLE}: x_t < \text{threshold}
  2. 待定态理解指标值超出阈值,但还没持续够时间,进入 PENDING。这相当于“火警铃预检”——先关注,不行动,避免抖动误报。
    PENDING:xt≥threshold,  t<for\text{PENDING}: x_t \ge \text{threshold}, \; t < \text{for}
  3. 触发态理解持续超时后转为 FIRING,真正发通知。这是“铃响了”,值班人员开始接手处理。
    FIRING:xt≥threshold,  t≥for\text{FIRING}: x_t \ge \text{threshold}, \; t \ge \text{for}
  4. 恢复态理解指标回落,发出恢复通知,状态回到 IDLE,一次完整的告警-恢复闭环结束。
    RESOLVED:xt<threshold after FIRING\text{RESOLVED}: x_t < \text{threshold} \text{ after FIRING}

分级降噪

想象一下最糟糕的深夜:数据库主节点挂了,1 分钟内 500 台应用服务器同时报“连接超时”,值班手机被轰成“拖拉机模式”,三条短信还没读完,100 条微信又进来了。这就是告警风暴(Alert Storm)——技术故障转成了信息轰炸。后厨应对策略是:给火警铃分级别——油温过高是 P0(严重,立即拉总闸并呼叫全员),冰箱温度略高是 P1(一般,通知管理员),制冰机周期波动是 P2(提示,记录在案)。

分级降噪的第一层,是定义清晰的严重度等级。通常分为三级:P0(严重)——核心业务不可用、数据丢失或安全事件,要求立即响应,通知方式包括电话+短信+IM 轰炸;P1(警告)——体验受损但业务可用,如延迟增大、部分请求失败,要求 15 分钟内响应;P2(提示)——容量规划、趋势变化类提示,如磁盘 72 小时后将满,只需记录在案。每一级对应不同的铃声、不同的人、不同的升级时限——就像餐厅的三种警报:火警、卫生巡检警告、例行库存盘点提醒,响应的严肃程度截然不同。

第二层是降噪消重。关键手段是“聚合通知”:把 N 条同一规则触发的告警合并成一条“发生 150 次类似告警”的摘要,就像值班保安上报“东区 3 号门到 8 号门的门磁全部同时报警”,而不是逐个念 6 条;另一种是“父-子抑制”,父故障(如数据库宕机)触发时,抑制所有子依赖(如应用连接超时)的告警,只报最根因。第三层是静默期:同一指标触发告警后,进入 15-30 分钟的 cooldown,期间同类告警不再重复发送,除非升级或降级——就像同一只火警铃,响过一次后要手动复位,不然会被人为“左耳进右耳出”。

分层降噪的最终效果,可以用一个“信号-噪音比”来理解:告警的价值密度 = 有效告警数 / 总告警数。没有降噪时,这个比值可能只有 10%——90% 的告警是噪音;加了强规则 + 聚合 + 静默后,比值能拉到 70% 以上。值班人员对告警的敏感度也会回升,因为每一条新消息都更大概率是“真事”。

值班排班

监控系统再智能,最终总得有个活人被叫醒去处理。后厨晚班必须有人兜底,谁来值守、谁来替补、联系不上怎么办,都得提前排好。这套制度在监控体系里叫做值班排班(On-call Scheduling),它把“告警发出去”和“告警被处理掉”之间那段最考验人性的过程,变成一条自动化流程。

值班排班的第一环是告警路由(Routing):告警产生后,要根据标签路由到具体的“处理组”。比如 team=backend 的告警,发给后端值班组的企业微信/飞书机器人;severity=P0 的告警还要额外电话通知值班长。路由表就像医院的“分诊台”——心梗去心内科,骨折去骨科,杜绝“一条告警群发全员”的原始做法。

第二环是值班表(Schedule)与升级策略(Escalation)。值班表用轮换制把团队成员排进一周 7 天、一天 24 小时的格子;升级策略则定义了“如果第一响应人在 10 分钟内没有认领,自动升级给值班长,再过 10 分钟没人响应,升级给研发总监”。这个设计参考了消防队的出警制度——火警响了,第一辆消防车必须在限时内出动,超时立即请求增援。常见的升级阶梯是“值班人 → 值班负责人 → 服务 owner → 部门应急小组”,每级 5-10 分钟的等待窗口。

第三环是认领与关闭(Ack & Close),它保证了“告警有始有终”。值班人员收到告警后先认领(Acknowledge),表示“我在处理了”,此时重复通知暂停;处理完成后标记关闭(Close),系统记录完整处理时长。如果超过升级时限仍未认领,系统不仅会升级给上一级,还会在事后统计中记一笔“响应超时”——就像后厨的交接班日志,菜没出完、灶没关火就走的厨师,是要被点名批评的。一套优秀的排班体系,能让告警的 MTTD(平均发现时间)和 MTTA(平均响应时间)双双压到分钟级,让“半夜被叫起来发现告警早已自动恢复”成为历史。

AI 应用场景

SRE 平台健康度监控

阶段:数据采集与异常检测

解决的问题:传统方式下,SRE 靠人工查监控面板,无法在用户感觉到故障之前发现异常。引入时序数据库后,将全平台每秒的请求量、错误率、P99 延迟作为指标采集入库,再用动态基线(3σ 判异)自动检测“延迟突刺”和“错误率劣化”。当 P99 延迟比历史均值高 3 个标准差时,系统在 1 分钟内发出 P1 告警,SRE 可以在用户投诉前介入处理。

具体案例:某头部电商平台的 SRE 团队,接入时序监控后,将故障平均发现时间(MTTD)从 25 分钟缩短到 4 分钟;结合分级降噪与值班升级,线上问题的 24 小时解决率从 60% 提升到 85%。

电商大促流量告警降噪

阶段:告警规则与分级降噪

解决的问题:大促期间突增的流量会让大量机器同时触发“CPU 高”“延迟大”的告警,形成告警风暴。传统做法是临时调高阈值,代价是真正的问题也被漏报。AI 方式是用时序数据库 + 父子抑制 + 相似告警聚合:当订单服务故障导致 1000 台机器延迟飙高时,只发送一条“订单服务故障(影响 1000 实例)”的 P0 告警,而不是 1000 条碎片信息。

具体案例:某支付平台在双十一期间,将告警数量从每秒 300 条压缩到每分钟 5 条以内,值班人员从 10 人减到 3 人,且故障响应速度反而提高一倍,因为告警噪音少了、有效信号清晰了。

工业物联网设备预测性维护

阶段:降采样与异常检测

解决的问题:工厂 10 万台振动传感器每秒产生巨额时序数据,直接存原始数据成本极高。传统做法是定期离线分析,故障发现滞后。AI 方式结合时序数据库的降采样与阈值检测:设备正常时原始数据 24 小时后降采样为分钟级聚合,但当振动幅值连续 10 分钟超过 3σ 基线时立即触发 P1 告警,并通知产线做预测性检修,在设备停机前更换部件。

具体案例:某风电场在风机齿轮箱上加装振动监控,通过时序数据库的异常检测提前 72 小时预测出 15 起齿轮箱故障,减少被动停机损失约 400 万元/年。

Python 演示

python82 行
import timeimport randomimport statisticsfrom collections import deque class MonitorAlertEngine:    """一个迷你监控告警引擎:动态基线 3σ 判异 + 分级告警 + 去重"""    def __init__(self, window_size=60, sigma_multiplier=3.0, dedup_seconds=60):        self.window = deque(maxlen=window_size)      # 历史值滑动窗口        self.sigma_multiplier = sigma_multiplier      # 3σ 系数        self.dedup_seconds = dedup_seconds            # 去重窗口(秒)        self._last_alert_time = {}                    # 最近告警时间记录        self._level_map = {"P0": 3, "P1": 2, "P2": 1}     def _update_baseline(self, value):        """把新值推进窗口,更新基线"""        self.window.append(value)        return statistics.mean(self.window), statistics.stdev(self.window)     def _check_anomaly(self, value, mean, stdev):        """3σ 判异:超出均值±3σ 即异常"""        if stdev == 0:            return False        return abs(value - mean) > self.sigma_multiplier * stdev     def _deduplicate(self, alert_key):        """同一告警去重:距上次发送不足 dedup_seconds 则跳过"""        now = time.time()        last = self._last_alert_time.get(alert_key, 0)        if now - last < self.dedup_seconds:            return False        self._last_alert_time[alert_key] = now        return True     def _severity(self, value, mean, stdev):        """异常程度分级:偏离越大级别越高"""        deviation = abs(value - mean) / (stdev if stdev else 1)        if deviation > 5:            return "P0"        if deviation > 4:            return "P1"        return "P2"     def feed(self, metric_name, value):        """输入一个新指标值,返回告警信息或 None"""        if len(self.window) < 30:            self.window.append(value)            return None        mean, stdev = self._update_baseline(value)        if not self._check_anomaly(value, mean, stdev):            return None        level = self._severity(value, mean, stdev)        alert_key = f"{metric_name}_{level}"        if not self._deduplicate(alert_key):            return None        return {            "metric": metric_name,            "level": level,            "value": round(value, 2),            "baseline": round(mean, 2),            "stdev": round(stdev, 2),            "alert": f"[{level}] {metric_name} 异常: 当前 {value:.1f} (基线 {mean:.1f}±{self.sigma_multiplier}*{stdev:.1f})"        } if __name__ == "__main__":    engine = MonitorAlertEngine(window_size=50)    # 模拟 200 秒的 CPU 指标: 前 150 秒正常波动, 后 50 秒注入异常尖峰    for t in range(200):        if t < 150:            value = 40 + random.uniform(-3, 3)        else:            value = 40 + random.uniform(15, 25)  # 异常跃升        alert = engine.feed("cpu.usage", value)        if alert:            print(alert["alert"])            if alert["level"] == "P0":                print("  -> 立即电话通知值班长")            elif alert["level"] == "P1":                print("  -> 发送 IM 告警给后端组")            else:                print("  -> 记录到每日告警摘要")        time.sleep(0.01)
目的:演示监控告警引擎的完整闭环——滑动窗口维护历史基线、3σ 判定异常、按偏离程度分级、再按时间窗去重,防止同一告警反复轰炸。
  1. window = deque(maxlen=window_size)用一个固定长度的双端队列维护历史指标,窗口满了自动淘汰最老的数据,相当于“只记最近 50 个采样点的温度”。
  2. statistics.mean/stdev计算窗口内数据的均值和标准差,作为动态基线的核心参数。
  3. abs(value - mean) > self.sigma_multiplier * stdev这就是 3σ 判异的落地:新值和均值的距离超过 3 倍标准差就认为异常,而不是看绝对数值。
  4. _deduplicate()记录每个告警上次发送时间,间隔小于 60 秒就跳过,这实现了“静默期”的概念。
  5. _severity()用偏离倍数分三档:偏离超过 5σ 是 P0,4σ-5σ 是 P1,其余是 P2。这就把“异常严重程度”量化成了可执行的动作等级。
  6. feed()对外唯一入口:输入一个指标名和值,返回告警字典或 None。调用方只需要关心返回结果,就像帮厨只要把温度念给监控系统,系统自己判断要不要响铃。

常见误区

误区监控数据肯定是采集得越密越准,我把采集频率从 10 秒提到 1 秒,这样任何波动都逃不过我的眼睛,存储贵一点我也认。

正解采集频率翻 10 倍,数据量也翻 10 倍,存储成本暴涨但告警质量的提升却微乎其微。原因是:监控真正关心的是“趋势”和“越界”,而非“瞬时形态”。1 秒级采集捕捉到的绝大多数抖动都是噪声,反而会因短时毛刺触发大量误报。更合理的设计是分层:前端高频采集(10 秒)做实时检测,后端降采样聚合保留趋势,既能看清细节又控制成本。

误区我把能想到的异常都配置成告警规则——CPU、内存、磁盘、网络、QPS、错误率、GC 次数……规则越细,系统就越安全。结果每天收到几千条告警,我已经懒得看了。

正解告警规则过多会导致误报率飙升和信噪比崩溃,最终值班人员对告警脱敏,真正的 P0 故障反而被淹没。成熟的监控体系信奉“少而精”:只对“有明确动作可做”的异常建规则,并配套持续时长、分级降噪和去重机制。每条新规则上线前要问三个问题:触发后谁处理?处理时限多少?误报了我能承受吗?

为何常见:把“监控”误以为“告警”,认为只要捕获更多信号就是更安全。实际上告警的目的是触发“行动”,无法触发有效行动的告警只是数字噪音。

误区降采样就是把数据变模糊,万一日后要排查一个 3 个月前的精确到秒的问题,原始数据没了不就完蛋了?所以我不做降采样,硬盘多买几块就好。

正解降采样≠随意丢弃,而是按“查询需求”分层。3 个月后的排查,几乎不可能依赖“秒级原始数据”——那时的核心问题是“当时有没有越界、趋势如何”,而这些信息 max/avg 聚合已经完整保留。所谓“关键信息”是相对的:对实时排障关键,对容量规划不关键。合理的保留策略是“热数据保全量、温数据保聚合、冷数据保统计”,才能让系统长期可维护。真到了要溯源秒级数据,说明你的可观测性观测设计本身就有问题。

为何常见:把“信息有损”等同于“信息丢失”,而没意识到监控场景下“信息”的定义是业务需要的可回答的问题,而非数据的原始形态。

误区告警就是“超过 80% 就报警”,动态基线、3σ 这些概念太玄乎,而且算起来复杂,不如一个固定阈值来得简单直接。

正解固定阈值应对“明确的资源上限”有效(如内存不能超过物理上限),但面对“业务依赖的指标幻觉”就失灵了。某系统凌晨 3 点 CPU 5%、晚上 8 点 CPU 60%,固定阈值 70% 会让晚上 8 点真实故障漏报;而动态基线知道“晚上 8 点均值 50%±8%”,60% 就有可疑。现代监控平台的异常检测往往用“动态基线为主,固定阈值为兜底”的组合策略。

为何常见:人的直觉偏好“简单可解释”的规则,但监控指标天然带有昼夜与季节周期,静态规则无法表达这种“语境相关的正常”。

误区告警系统把告警发出去、有人收到,我的任务就完成了。至于有没有人处理、处理得怎么样,那是值班人的事。

正解监控告警体系的终点是“闭环”,而闭环的最后一环是“认领 → 处理 → 关闭 → 复盘”。没有认领机制的告警,发出去之后可能躺在 IM 里没人看;没有关闭机制的告警,会让值班人分不清哪些还在处理中、哪些已恢复。成熟的体系要求每个告警都有唯一编号、响应 SLO、处理人、恢复时间,并在事后统计 MTTA/MTTR,反哺规则优化——这才是“告警驱动改进”的完整链路。

为何常见:技术人容易把“通知”当目标,而忽略了通知之后那一串需要被管理的动作。告警不是终点,而是排障流程的起点。

面试题

Q1. 时序数据库的核心数据模型是以下哪种?

单选题 · easy

  • A.键值对存储
  • B.文档型存储
  • C.时间戳+指标值+标签← 正确答案
  • D.图结构存储

答案:C。时序数据库的基本单元是“时间戳 + 指标值 + 标签集合”,标签用来做多维筛选。键值对、文档、图结构对应 Redis、MongoDB、Neo4j,都不是时序数据的核心模型。

Q2. 抓取(Pull)与推送(Push)两种采集模式的区别,下列说法正确的是?

单选题 · easy

  • A.Pull 由被监控方主动上报
  • B.Push 由监控系统主动拉取
  • C.Pull 模式下采集节奏由监控系统控制← 正确答案
  • D.二者没有本质区别

答案:C。Pull 模式是监控系统到被监控端点拉数据,节奏由监控端控制;Push 是被监控方主动上报,适合短生命周期任务。Prometheus 是 Pull 代表,StatsD 是 Push 代表。

Q3. 降采样时,如果想让“是否有过超出告警线的高峰值”在聚合后依然可见,应该优先选择哪个聚合函数?

单选题 · mid

  • A.avg
  • B.max← 正确答案
  • C.min
  • D.count

答案:B。max 聚合保留窗口内的最大值,它是对“越界”最敏感的统计量。avg 会把尖峰抹平,min 关注低谷,count 只统计数量,都不能直接回答“是否超线”。

Q4. 3σ 异常检测中,σ(标准差)代表什么含义?

单选题 · mid

  • A.数据的平均值
  • B.数据的波动离散程度← 正确答案
  • C.数据的最大值
  • D.数据的采集频率

答案:B。标准差衡量一组数据相对于均值的离散程度。σ 小说明数据稳定、正常波动窄,σ 大说明指标本身就有较大毛刺。3σ 判异正是利用“偏离均值多远算小概率”这一统计性质。

Q5. 告警规则中“持续时长(for)”的作用包括?

多选题 · mid

  • A.防止瞬时毛刺导致误报← 正确答案
  • B.让告警在故障恢复后自动关闭
  • C.提高告警的准确性← 正确答案
  • D.替代分级降噪功能

答案:AC。for 参数要求条件连续成立一段时间才触发告警,能过滤偶发抖动,提高准确率。恢复关闭由独立的“恢复判定”负责,分级降噪是另一套机制,for 不能替代它们。

Q6. 动态基线检测与固定阈值相比,最大的优势是?

单选题 · mid

  • A.计算更简单
  • B.不需要历史数据
  • C.能适应不同时段的不同正常范围← 正确答案
  • D.永远不会误报

答案:C。动态基线从历史数据学习“该时刻的正常范围”,能表达“凌晨的 30% 正常、晚上的 60% 也可能正常”这类时段差异。固定阈值做不到场景自适应;动态基线需要至少数天的历史数据,计算也更复杂,且同样可能误报。

Q7. 告警风暴最常见、最有效的应对手段是?

单选题 · hard

  • A.提高所有告警阈值
  • B.增加值班人手
  • C.相似告警聚合 + 父子抑制← 正确答案
  • D.关闭非核心告警

答案:C。父故障触发时子依赖的告警无独立决策价值,相似告警聚合把 N 条同类合并为一条摘要。提高阈值会导致漏报,增加人手治标不治本,直接关闭规则则丢失信息。聚合+抑制同时降低噪音并保留根因,是行业标准做法。

Q8. 值班排班系统中“升级策略”的作用是?

多选题 · hard

  • A.保证告警在超时未响应时被更高层接手← 正确答案
  • B.替代告警路由功能
  • C.防止告警被忽略← 正确答案
  • D.自动修复故障

答案:AC。升级链路(值班人→值班长→经理)在“第一响应人超时未认领”时自动向上传递,用管理压力保证告警不被丢弃。路由负责“发给谁”,升级负责“没人处理时怎么办”,故障的自动修复属于自动化运维范畴,不在排班体系内。

Q9. 监控指标 cpu.usage 在连续 10 天内呈现“工作日白天高、夜间低”的规律,当前值是工作日上午 10 点的 65%,历史同时段均值 40%、σ=5%。以下推断最合理的是?

单选题 · extreme

  • A.65% 已超过 3σ 上界(55%),判定为异常← 正确答案
  • B.65% 未达到固定阈值 70%,判定为正常
  • C.65% 在基线范围内,属于正常波动
  • D.信息不足,无法判断

答案:A。3σ 上界 = 40 + 3×5 = 55%,65% 明显超出,属于小概率异常。虽然固定阈值 70% 未触发,但动态基线更了解“上午 10 点的正常水位”,因此应该判定异常并关注。这也说明动态基线比固定阈值对时段敏感度更高。

Q10. 降采样可以解决监控系统中的哪些问题?

多选题 · easy

  • A.节省存储成本← 正确答案
  • B.加速历史数据查询← 正确答案
  • C.消除告警误报
  • D.保留长期趋势信息← 正确答案

答案:ABD。降采样把 N 条原始数据聚合为一条,存储显著降低,查询聚合结果比扫原始数据快,且 max/avg 等统计量保留了趋势信息。但降采样是“有损压缩”,不涉及告警误报的判断逻辑,所以无法消除误报。