可观测性不是装仪表盘,而是用有限的指标、日志、链路和剖析信号,低成本地回答你事先没想到的问题。
指标是按时间采样的数值,适合聚合、告警和看趋势;日志是离散事件,保留上下文和异常细节;链路把一次请求拆成跨服务的 span,回答“慢在哪一跳”;剖析(profiling)采样调用栈,回答“CPU 或内存在哪段代码里被消耗”。四类信号不是互相替代的关系,而是粒度与成本不同的证据:指标便宜但丢维度,日志详细但难聚合,链路有拓扑但采样后不完整,剖析精确但只覆盖单一进程。
选择信号时先问要回答什么问题。已知的、可枚举的异常适合指标和告警;未知的、需要上下文的排查适合日志和链路;持续的资源消耗适合剖析。只装仪表盘而不设计信号之间的关联,遇到新问题时仍然只能靠猜。
边界在于:信号只记录系统愿意暴露的部分。埋点缺失、标签设计错误或采样策略不当,会让“有数据”变成“数据回答了错误的问题”。失败时的典型表现是仪表盘全绿但用户已经在报错,或者排障时发现关键维度根本没有采集。
采集方式主要分 pull 和 push:Prometheus 主动抓取 target,agent 或 OTel Collector 也可以推送。抓取配置通过服务发现获得目标,再用 relabel 过滤和改写标签。标签是时序的身份,决定一条曲线如何被区分和聚合;service、env、region、status_code 这类维度让同一个指标可以切片,但每一个标签组合都会生成一条新的序列。
标签设计要同时考虑查询和成本。高价值维度应该稳定、低基数、可枚举;用户 ID、请求 ID、原始 URL 这类高基数维度不应直接进入指标标签,而应放进日志、链路或 exemplar。边界是:标签不是“越多越好”,每增加一个维度,序列数量按乘积增长。
采集失败的常见表现是 target down、样本缺失、时间序列断点,或者标签错位导致曲线对不上。比“没数据”更危险的是“有数据但标签写错了”,因为它会让查询和告警静默地得出错误结论。
时序数据库按“指标名 + 标签集”标识一条序列,写入时建立索引并压缩样本。基数(cardinality)是序列数量,通常由标签组合的数量决定。存储层还要处理保留期、降采样、压缩和分块;查询层则在时间范围内扫描匹配的序列并聚合。
基数爆炸是时序系统最常见的容量故障:一个本应聚合的维度被放进标签,序列数从几百涨到几百万,内存和索引先被撑爆,随后是写入失败和查询超时。边界在于,基数成本不是线性的,索引、倒排和查询时的序列展开都会放大开销。
失败时的表现包括:Prometheus 或 VictoriaMetrics 内存持续上涨、too many series、抓取超时、查询返回部分数据。解决方向通常不是加机器,而是删掉无用的高基数标签、做聚合记录规则,或把明细移到日志和链路系统。
查询语言把原始样本变成可解释的结论。PromQL 中瞬时向量表示当前值,区间向量配合 rate、increase 处理计数器;histogram_quantile 从桶里估算分位数;sum by、avg by 决定保留哪些维度。LogQL 用标签选择器和管道过滤日志,TraceQL 按属性和耗时筛选 span。
histogram_quantile(0.99, sum by (le, service) (rate(http_request_duration_seconds_bucket[5m])))
聚合会丢失维度,也会制造错觉。把延迟按所有实例平均,会掩盖某个可用区的长尾;对 gauge 使用 rate,会得到没有物理意义的斜率;rate 的窗口小于抓取间隔,会产生锯齿和假尖峰。边界是:查询结果的可信度取决于采集间隔、窗口和标签完整性,而不是查询语句本身是否“高级”。
失败时的表现是“数字看起来合理但结论错误”:告警不触发、容量评估偏差、故障定位到错误的实例。排查查询问题时,先看原始序列和采集间隔,再看聚合函数。
告警应该围绕用户可感知的症状,而不是每一个可能的原因。SLO 用 SLI(例如成功率、延迟分位数)定义目标,错误预算量化“可以坏多少”。基于错误预算消耗速率的告警(burn rate)比静态阈值更能平衡灵敏度和噪声:短窗口抓突发,长窗口防误报。
告警链路还包括分组、抑制、静默和路由。分组把同一故障的多个实例合并成一条通知,抑制让根因告警压住衍生告警,路由决定谁在什么时间收到什么级别。边界是:告警规则只能表达你已经理解的模式,未知故障仍需要看板和探索式查询。
失败时的表现是告警风暴、告警疲劳、关键告警被淹没,或者规则阈值与真实用户体验脱节。告警发出后无人行动,说明这条告警要么不重要,要么缺少 runbook。
可观测性成本由四部分构成:指标序列数与保留期、日志摄入量、链路 span 数、剖析采样频率。控制成本的手段包括指标降维与记录规则、日志分级与采样、链路头部或尾部采样、按环境设置不同保留期。尾部采样可以保留错误和慢请求,同时丢弃大量正常流量。
采样会改变你看到的世界。随机采样对总数估计有效,但会丢掉罕见错误和长尾请求;头部采样在请求开始时决定,无法根据结果保留异常;尾部采样需要先在内存中缓冲整条链路。边界是:成本优化不能以失去关键证据为代价,错误、超时和关键业务路径应优先保留。
失败时的表现是账单突然上涨、采集端丢数据、链路断裂无法拼出完整调用,或者事故时发现关键日志正好被采样掉。成本治理应该和信号设计一起做,而不是等到账单来了再删数据。
| 组件 | 读什么 | 写什么 | 失败后的现象 |
|---|---|---|---|
| 应用与 SDK | 请求上下文 | 指标、日志、span、profile | 埋点缺失、维度错误 |
| 采集器 | target、日志流、OTLP | 样本、日志、span | target down、采集延迟 |
| 时序库 | 样本与标签 | 序列、索引、块 | 基数爆炸、查询超时 |
| 日志/链路后端 | 日志流、span | 索引、分块、对象存储 | 摄入积压、数据被丢弃 |
| 查询层 | PromQL、LogQL、TraceQL | 查询结果 | 结果部分缺失、超时 |
| 告警引擎 | 规则、SLO、错误预算 | 告警事件 | 告警风暴、漏报 |
| 看板与值班 | 查询结果 | 判断与行动 | 看板全绿但用户受损 |
一条请求产生的指标、日志和链路通过时间、trace ID、exemplar 和资源标签相互关联;采集层决定数据是否完整,存储层决定能保留多久,查询与告警层决定这些数据能否变成行动。
rate,或把 rate 窗口设得比抓取间隔还短。正确理解:rate 针对计数器,窗口要覆盖足够采样点,否则得到无意义或锯齿结果。合上页面,先回答,再展开对照。