3. 可观测性数据模型与存储选型
可观测性平台的能力上限,往往在数据模型和存储选型阶段就已经被决定。采集端再完善,如果模型设计无法表达真实查询需求,或者存储引擎与访问模式不匹配,最终都会表现为“数据都在,但查不出来”或“查得出来,但成本失控”。本节围绕四类核心数据模型——时序、日志、追踪、事件——讨论设计要点,并给出主流存储引擎在生产场景下的对比与选型判断。
四类数据模型的设计要点
时序模型的核心是“指标名 + 标签集 + 时间戳 + 数值”。设计时最关键的是标签基数控制:标签是索引维度,不是描述字段。例如 http_requests_total{service="order", method="POST", status="500"} 中,service、method、status 适合作为标签,而 user_id、request_id 这类高基数维度一旦进入标签,会迅速膨胀索引并拖垮写入与查询。生产经验是:单指标的标签组合数控制在十万级以内,超过则改用日志或追踪承载明细。此外,指标应遵循“预聚合 + 降采样”策略,原始精度保留 15 天,之后按 5 分钟、1 小时粒度归档,以控制长期存储成本。
日志模型的设计要点在于“结构化程度”与“检索字段”的平衡。纯文本日志写入便宜但查询昂贵;全字段结构化写入昂贵但查询高效。生产上通常采用折中方案:保留原始消息体,同时抽取 5~10 个高频检索字段(如 level、service、trace_id、error_code)建立倒排索引,其余字段仅存储不索引。这样既保证 trace_id 关联查询的秒级响应,又避免索引膨胀。
追踪模型以 Span 为基本单元,通过 trace_id 串联、parent_span_id 构建调用树。设计要点是采样策略与属性裁剪:头部采样(Head-based)在入口决定是否记录,实现简单但可能丢失慢请求;尾部采样(Tail-based)在链路结束后根据耗时、错误状态决定保留,能精准捕获异常链路,但需要缓冲全部 Span,对内存和延迟有要求。属性方面,每个 Span 建议只保留 10~20 个关键属性,避免把整个请求体塞入 Span。
事件模型用于表达部署、扩缩容、告警、配置变更等离散动作,核心字段是 event_type、timestamp、source、payload 和关联的资源标识。事件模型的价值在于“因果关联”:当指标异常时,能快速判断是否由某次发布或配置变更触发。设计上应保证事件与指标、追踪共享同一套资源标识(如 service、instance、cluster),否则关联分析会退化为人工比对。
存储引擎的生产对比
下表给出四类模型在典型生产规模下的引擎对比。需要说明的是,表中的吞吐与延迟为合理假设的示例区间,用于建立量级判断,实际数值受硬件、分片、索引策略和查询复杂度影响显著。
| 数据模型 | 代表引擎 | 写入吞吐(示例量级) | 查询延迟(示例量级) | 成本特征 |
|---|---|---|---|---|
| 时序 | Prometheus / VictoriaMetrics | 100万~500万 samples/s | P99 50~200ms | 压缩率高,长期存储成本低 |
| 日志 | Elasticsearch / Loki / ClickHouse | 10万~100万 docs/s | P99 200ms~5s | ES 索引成本高,ClickHouse 压缩优 |
| 追踪 | Jaeger / Tempo / ClickHouse | 5万~50万 spans/s | P99 100ms~2s | 采样率直接决定成本 |
| 事件 | Kafka + ClickHouse / PostgreSQL | 1万~20万 events/s | P99 50ms~500ms | 数据量小,成本可控 |
选型判断与落地建议
选型不是“选一个最强的引擎”,而是“让访问模式与存储特性对齐”。如果查询以聚合、降采样、范围扫描为主,列存或时序引擎更合适;如果查询以全文检索、多条件过滤为主,倒排索引引擎更合适;如果查询以 trace_id 点查和调用树重建为主,则需要支持高并发点查和嵌套结构展开的引擎。
一个可落地的组合方案是:时序数据写入 VictoriaMetrics,保留 15 天原始精度,之后降采样到 5 分钟粒度保留 1 年;日志写入 ClickHouse,按天分区,trace_id 建跳数索引,30 天后转对象存储;追踪采用尾部采样,仅保留错误链路和 P99 以上慢链路,写入 ClickHouse;事件写入 Kafka 后落 ClickHouse,与指标、追踪共享 service 和 instance 标识。这样在写入吞吐、查询延迟和成本之间取得平衡,也便于后续做跨模型的关联诊断。