2. 可观测性三大支柱:指标、日志、链路追踪的核心原理与数据模型

可观测性(Observability)的工程实践通常围绕三大数据支柱展开:指标(Metrics)、日志(Logs)和链路追踪(Traces)。这三者并非相互替代,而是从不同维度描述系统状态,共同构成完整的可观测性拼图。理解每种支柱的核心原理与数据模型,是设计租户隔离架构的前提。

2.1 三大支柱概述与对比

下表从数据本质、采集方式、存储模型和典型用途四个维度,对三大支柱进行横向对比:

维度 指标(Metrics) 日志(Logs) 链路追踪(Traces)
数据本质 聚合的数值时间序列 离散的、带时间戳的文本/结构化事件 请求在分布式系统中的完整执行路径
采集方式 定期拉取(Pull)或推送(Push) 事件触发写入(Push) 请求上下文传播 + 采样(Push)
存储模型 时序数据库(如 Prometheus TSDB) 倒排索引 + 全文搜索(如 Elasticsearch) Span 树 + 关联存储(如 Jaeger/ Tempo)
典型用途 告警、趋势分析、容量规划 故障排查、审计、详细事件分析 性能瓶颈定位、依赖关系分析
关键认知:三大支柱在租户隔离场景下,隔离策略的侧重点不同。指标关注标签(Label)隔离,日志关注索引(Index)隔离,链路追踪关注 Trace ID 与租户 ID 的绑定。

2.2 指标(Metrics)核心原理与数据模型

指标是系统状态的“快照”,以数值形式周期性记录。其核心优势在于低存储成本和高查询效率,适合用于告警和趋势分析。

2.2.1 数据模型:时间序列

指标的核心数据模型是时间序列(Time Series),由以下三要素唯一标识:

  • 指标名称(Metric Name):描述被测量对象,如 http_requests_total。
  • 标签(Labels):键值对,用于维度描述,如 {method="GET", endpoint="/api/v1/users", tenant="acme"}。
  • 时间戳与值(Timestamp & Value):一个时间点对应的数值。

一个典型的时间序列标识如下:

http_requests_total{method="POST", status="200", tenant="tenant_a"} @ 1700000000 = 1024

2.2.2 指标类型

Prometheus 定义了四种核心指标类型,每种类型对应不同的聚合语义:

类型 说明 典型场景
Counter(计数器) 只增不减的累计值 请求总数、错误总数
Gauge(仪表盘) 可增可减的瞬时值 CPU 使用率、内存占用、并发连接数
Histogram(直方图) 对观测值进行分桶统计 请求延迟分布(如 p50/p99)
Summary(摘要) 类似 Histogram,但计算分位数 服务端预计算的分位延迟
租户隔离注意点:在多租户场景下,tenant 标签是隔离的关键。必须确保所有指标都携带租户标签,否则不同租户的数据会混在一起,导致告警误报或数据泄露。
指标数据模型与采集流程 应用实例 /metrics 端点 指标数据模型 Metric Name + Labels + Timestamp 例: http_requests_total{tenant="a", status="200"} @ 1700000000 = 1024 时序数据库 Prometheus TSDB Pull / Push 写入 租户隔离关键:标签(Label) 通过 tenant 标签区分不同租户数据

2.3 日志(Logs)核心原理与数据模型

日志是系统产生的离散事件记录,提供最详细的上下文信息。在故障排查和安全审计中,日志是不可或缺的证据链。

2.3.1 数据模型:结构化日志

现代可观测性平台普遍采用结构化日志(Structured Logging),而非纯文本日志。结构化日志将事件拆分为多个字段,便于索引和查询。

一个典型的结构化日志条目(JSON 格式)如下:

{
  "timestamp": "2024-01-01T12:00:00Z",
  "level": "ERROR",
  "logger": "com.example.payment.PaymentService",
  "message": "Payment processing failed",
  "tenant_id": "tenant_b",
  "trace_id": "abc123def456",
  "user_id": "user_789",
  "amount": 99.99,
  "error_code": "INSUFFICIENT_FUNDS"
}

2.3.2 日志级别与分类

日志级别用于区分事件的严重程度,常见的级别体系如下:

  • TRACE / DEBUG:细粒度调试信息,通常只在开发环境开启。
  • INFO:正常业务流程记录,如请求开始、结束。
  • WARN:潜在问题,但不影响当前功能,如重试、降级。
  • ERROR:功能异常,需要人工介入,如数据库连接失败。
  • FATAL:严重错误,导致系统不可用。
租户隔离实践:在日志采集端,必须将 tenant_id 作为必填字段注入到每条日志中。在存储端(如 Elasticsearch),使用 tenant_id 作为索引路由(Routing)或索引前缀,实现物理或逻辑隔离。
日志结构化与租户隔离模型 应用服务 产生日志事件 结构化日志 timestamp: 2024-01-01T12:00:00Z level: ERROR tenant_id: tenant_b message: Payment failed 日志存储 Elasticsearch 结构化输出 写入 租户隔离策略 1. 索引隔离: logs-tenant-a-2024.01.01 2. 字段隔离: 通过 tenant_id 字段过滤 3. 路由隔离: 按 tenant_id 路由到不同分片

2.4 链路追踪(Traces)核心原理与数据模型

链路追踪用于追踪一个请求在分布式系统中的完整执行路径。它通过上下文传播(Context Propagation)将跨服务的调用串联起来,形成一棵 Span 树。

2.4.1 核心概念:Trace 与 Span

  • Trace(追踪):代表一个完整的请求或事务,由多个 Span 组成,通过全局唯一的 Trace ID 标识。
  • Span(跨度):代表 Trace 中的一个工作单元,记录一个服务或组件处理该请求的起止时间、状态和元数据。每个 Span 有唯一的 Span ID,并通过 Parent Span ID 关联父 Span。

2.4.2 数据模型:Span 树

一个 Trace 的数据模型本质上是一棵有向无环图(DAG),根 Span 代表入口请求,子 Span 代表下游调用。一个 Span 的核心字段包括:

字段 说明 示例
trace_id 全局唯一追踪 ID abc123def456
span_id 当前 Span 的唯一 ID span_001
parent_span_id 父 Span 的 ID(根 Span 为空) span_000
service_name 产生该 Span 的服务名 payment-service
operation_name 操作名称 POST /api/payments
start_time / duration 开始时间与持续时长 1700000000 / 150ms
tags 键值对元数据 tenant_id: tenant_c

2.4.3 上下文传播机制

链路追踪的核心在于上下文传播。当服务 A 调用服务 B 时,必须将当前的 Trace ID 和 Span ID 通过 HTTP Header(如 traceparent)或 RPC 元数据传递给下游服务,下游服务才能将新的 Span 挂接到同一个 Trace 树上。

租户隔离关键:在链路追踪中,租户隔离通常通过 tags 或 baggage 实现。将 tenant_id 作为 Span 的 Tag 或 Baggage 项传播,确保所有 Span 都能关联到正确的租户。在查询时,通过 Trace ID 关联的租户标签进行过滤。
链路追踪 Span 树结构 根 Span: API Gateway Trace ID: abc123 子 Span: User Service Parent: 根 Span 子 Span: Order Service Parent: 根 Span 子 Span: Payment Service Parent: 根 Span 孙 Span: DB Query Parent: Order Service 租户标签传播 tenant_id 通过 Baggage 传递

2.5 三大支柱的关联与融合

在实际的可观测性平台中,三大支柱并非孤立存在,而是通过关联机制形成合力:

  • Trace ID 关联:在日志和指标中注入 trace_id 字段,实现从指标告警 -> 查看相关日志 -> 定位具体 Trace 的快速跳转。
  • 租户 ID 统一:所有数据源统一使用 tenant_id 作为核心标签/字段,确保跨数据源的租户隔离策略一致。
  • 服务名对齐:指标、日志和 Trace 中的 service_name 必须保持一致,避免数据孤岛。
架构设计启示:在设计租户隔离方案时,不能只考虑单一数据源。需要建立统一的元数据标准(如租户 ID、服务名、环境标签),并确保三大支柱的采集、存储和查询层都遵循该标准,才能实现真正的端到端租户隔离。