4. 水位数据采集:从 Prometheus、Datadog、Grafana 等监控系统采集水位数据的标准化方法

水位数据是变更门禁与回滚判断的量化基础。Backstage 服务目录中的每个实体(Service、Component、API)都需要关联实时的资源水位与健康指标。本章定义从主流监控系统采集水位数据的标准化方法,包括数据模型、采集协议、适配器模式与异常处理策略。

4.1 水位数据模型标准化

无论后端监控系统是什么,Backstage 插件层应统一消费以下水位模型。该模型直接映射到服务目录实体的 spec.watermark 扩展字段。

字段 类型 说明 示例
entityRef string Backstage 实体引用(component:default/my-svc) component:default/payment-svc
metricName string 指标标识符 cpu_usage_percent
value float 当前水位数值 78.5
threshold float 该指标的门禁阈值 90.0
unit string 单位 %, MB, req/s
timestamp int64 采集时间戳(Unix 毫秒) 1712563200000
source string 数据来源系统 prometheus, datadog
status string 水位状态:ok, warning, critical warning
标准化原则:所有采集适配器必须输出上述模型。Backstage 门禁插件只依赖 value 与 threshold 的比较结果,不关心底层查询语言差异。

4.2 采集架构与适配器模式

采用 Provider 适配器模式 实现多数据源接入。每个监控系统实现一个 WatermarkProvider 接口,Backstage 后端通过依赖注入加载已配置的 Provider 列表。

水位数据采集适配器架构 Backstage 门禁插件 WatermarkProvider 接口 Prometheus 适配器 Datadog 适配器 Grafana 适配器 Prometheus Server Datadog API Grafana / Graphite 统一水位模型 → 门禁判断 每个适配器独立处理查询语法、认证与重试,向上层屏蔽差异

4.3 Prometheus 适配器实现

Prometheus 是最常见的水位数据源。适配器通过 HTTP API 执行即时查询(Instant Query),按服务标签过滤指标。

4.3.1 查询模板

# 查询模板:按 service_name 标签获取 CPU 使用率
GET /api/v1/query
  ?query=avg(rate(container_cpu_usage_seconds_total{service="%s"}[5m])) * 100
  &time=<timestamp>

# 响应示例
{
  "status": "success",
  "data": {
    "resultType": "vector",
    "result": [
      {
        "metric": { "service": "payment-svc" },
        "value": [1712563200, "78.5"]
      }
    ]
  }
}

4.3.2 适配器核心逻辑(TypeScript 伪代码)

// PrometheusWatermarkProvider.ts
import { WatermarkProvider, WatermarkData } from './types';

export class PrometheusWatermarkProvider implements WatermarkProvider {
  constructor(private baseUrl: string, private queryTemplate: string) {}

  async fetchWatermark(entityRef: string, metricName: string): Promise<WatermarkData> {
    const serviceName = entityRef.split(':')[2]; // 从 entityRef 提取服务名
    const promQL = this.queryTemplate.replace('%s', serviceName);
    const url = `${this.baseUrl}/api/v1/query?query=${encodeURIComponent(promQL)}`;

    const response = await fetch(url);
    const json = await response.json();

    if (json.status !== 'success' || json.data.result.length === 0) {
      throw new Error(`Prometheus query returned no data for ${entityRef}`);
    }

    const value = parseFloat(json.data.result[0].value[1]);
    return {
      entityRef,
      metricName,
      value,
      threshold: 90.0, // 从配置读取
      unit: '%',
      timestamp: Date.now(),
      source: 'prometheus',
      status: value >= 90.0 ? 'critical' : value >= 75.0 ? 'warning' : 'ok',
    };
  }
}
关键设计:查询模板通过配置注入,避免硬编码 PromQL。每个服务的水位阈值在 Backstage 服务目录的 spec.watermark.thresholds 中定义,适配器运行时读取。

4.4 Datadog 适配器实现

Datadog 适配器使用 Metrics API v2,通过 + Application Key 认证。查询时间范围固定为最近 5 分钟,聚合方式为 avg。

参数 值 说明
filter[query] avg:system.cpu.user{service:payment-svc} 按服务标签过滤
filter[from] now-5m 最近 5 分钟
filter[to] now 当前时间
options[timezone] UTC 时区统一
// DatadogWatermarkProvider.ts
export class DatadogWatermarkProvider implements WatermarkProvider {
  async fetchWatermark(entityRef: string, metricName: string): Promise<WatermarkData> {
    const serviceName = entityRef.split(':')[2];
    const query = `avg:system.cpu.user{service:${serviceName}}`;
    const url = `https://api.datadoghq.com/api/v2/metrics/${metricName}/data`;

    const response = await fetch(url, {
      headers: {
        'DD-': this.,
        'DD-APPLICATION-KEY': this.appKey,
      },
      body: JSON.stringify({
        filter: { query, from: Date.now() - 300000, to: Date.now() },
        options: { timezone: 'UTC' },
      }),
    });

    const data = await response.json();
    const points = data.data?.attributes?.points || [];
    const avgValue = points.length > 0
      ? points.reduce((sum: number, p: number[]) => sum + p[1], 0) / points.length
      : 0;

    return this.toWatermark(entityRef, metricName, avgValue);
  }
}

4.5 Grafana 适配器(基于 Graphite/InfluxDB)

对于使用 Grafana 作为可视化层、后端为 Graphite 或 InfluxDB 的场景,适配器直接查询 Grafana API 的 /api/ds/query 端点,通过数据源代理获取水位数据。

// GrafanaWatermarkProvider.ts
export class GrafanaWatermarkProvider implements WatermarkProvider {
  async fetchWatermark(entityRef: string, metricName: string): Promise<WatermarkData> {
    const serviceName = entityRef.split(':')[2];
    const grafanaQuery = {
      queries: [{
        refId: 'A',
        datasource: { type: 'prometheus', uid: 'prometheus-uid' },
        expr: `avg(rate(cpu_usage{service="${serviceName}"}[5m])) * 100`,
        instant: true,
      }],
      from: Date.now() - 60000,
      to: Date.now(),
    };

    const response = await fetch(`${this.baseUrl}/api/ds/query`, {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${this.apiToken}` },
      body: JSON.stringify(grafanaQuery),
    });

    const result = await response.json();
    const frame = result.results?.A?.frames?.[0];
    const value = frame?.data?.values?.[1]?.[0] ?? 0;

    return this.toWatermark(entityRef, metricName, value);
  }
}
注意:Grafana 代理模式会增加一层网络跳转和认证开销。生产环境建议优先直连 Prometheus 或 Datadog API,仅在网络隔离场景下使用 Grafana 代理。

4.6 采集异常处理与降级策略

水位数据采集必须考虑监控系统不可用、超时、数据缺失等异常情况。标准化异常处理流程如下:

  1. 超时控制:每个 Provider 的 HTTP 请求设置 5 秒超时,超时后触发降级。
  2. 重试机制:指数退避重试最多 2 次(间隔 1s、3s),仅对 5xx 和网络错误重试。
  3. 数据缺失处理:如果返回空结果,使用最近一次缓存的水位数据(TTL 60 秒)。
  4. 熔断:连续 5 次失败后,该 Provider 熔断 30 秒,期间返回 status: unknown,门禁插件跳过该指标判断。
// 异常处理中间件示例
async function withRetryAndFallback(
  provider: WatermarkProvider,
  entityRef: string,
  metricName: string
): Promise<WatermarkData> {
  const cacheKey = `${entityRef}:${metricName}`;
  const cached = cache.get(cacheKey);

  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      const data = await provider.fetchWatermark(entityRef, metricName);
      cache.set(cacheKey, data, 60_000); // 缓存 60 秒
      return data;
    } catch (err) {
      if (attempt === 2) break;
      await sleep(1000 * Math.pow(3, attempt)); // 1s, 3s
    }
  }

  // 降级:返回缓存或 unknown 状态
  if (cached) return { ...cached, timestamp: Date.now(), source: 'cache' };
  return {
    entityRef, metricName, value: 0, threshold: 0,
    unit: '', timestamp: Date.now(), source: 'fallback',
    status: 'unknown',
  };
}

4.7 采集配置声明(Backstage Catalog 扩展)

水位采集配置通过 Backstage 服务目录的 catalog-info.yaml 声明,实现服务维度的水位策略绑定。

# catalog-info.yaml 水位采集配置示例
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: payment-svc
  annotations:
    watermark.io/provider: prometheus
    watermark.io/prometheus-host: http://prometheus.internal:9090
    watermark.io/metrics: |
      - name: cpu_usage
        query: 'avg(rate(container_cpu_usage_seconds_total{service="payment-svc"}[5m])) * 100'
        threshold: 90
        unit: '%'
      - name: memory_usage
        query: 'container_memory_usage_bytes{service="payment-svc"} / 1048576'
        threshold: 2048
        unit: 'MB'
spec:
  type: service
  lifecycle: production
  owner: team-payment
最佳实践:将水位采集配置与实体元数据绑定,而非硬编码在插件代码中。这样不同环境(staging / production)可以复用同一套适配器,仅通过 Catalog 配置差异化阈值和查询语句。

4.8 多数据源聚合策略

当同一个服务同时配置了 Prometheus 和 Datadog 两个数据源时,门禁插件需要聚合判断。标准化聚合规则如下:

聚合策略 行为 适用场景
any 任一数据源水位达到 critical 即阻断 安全敏感指标(错误率、延迟)
all 所有数据源均达到 critical 才阻断 资源冗余场景(多监控系统互为备份)
majority 超过半数数据源达到 critical 时阻断 多区域部署,防止单区域误报
weighted 按数据源权重计算综合水位分数 混合精度场景(Prometheus 权重 0.7,Datadog 0.3)
// 聚合判断逻辑
function evaluateAggregatedWatermark(
  results: WatermarkData[],
  strategy: 'any' | 'all' | 'majority' | 'weighted'
): 'ok' | 'warning' | 'critical' {
  const criticalCount = results.filter(r => r.status === 'critical').length;
  const total = results.length;

  switch (strategy) {
    case 'any':
      return criticalCount > 0 ? 'critical' : 'ok';
    case 'all':
      return criticalCount === total ? 'critical' : 'ok';
    case 'majority':
      return criticalCount > total / 2 ? 'critical' : 'ok';
    case 'weighted':
      const score = results.reduce((sum, r) => {
        const weight = r.source === 'prometheus' ? 0.7 : 0.3;
        return sum + (r.value / r.threshold) * weight;
      }, 0);
      return score >= 1.0 ? 'critical' : score >= 0.8 ? 'warning' : 'ok';
    default:
      return 'ok';
  }
}

通过上述标准化方法,Backstage 门禁插件可以统一、可靠地从 Prometheus、Datadog、Grafana 等系统采集水位数据,为后续的变更门禁判断和回滚决策提供实时、准确的数据基础。