自定义MetricStore接入云监控2.0

本文档介绍如何将自定义的 SLS MetricStore(时序库)接入云监控2.0 UModel体系,实现指标数据的统一建模、查询和管理。通过 UModel 的 MetricSet 建模,可以将分散的时序指标数据与业务实体关联,构建完整的可观测数据体系。

  • 统一数据模型:通过 MetricSet 对指标数据进行结构化建模,提供一致的数据访问体验。

  • 实体关联:对现有实体可观测的增强,将指标数据与业务实体关联。

  • 统一查询:支持 SPL 和自定义分析查询,无需关心底层存储细节。

注意事项

  • Domain 命名规范:新增的 UModel domain 配置不建议与内置 domain(如 apmk8sacs 等)一致,避免系统升级后被误删。

  • 权限要求:确保当前用户对 MetricStore 有读取权限,否则查询时会返回权限错误。

  • UModel 唯一:确保新增节点的 <kind, domain, name>在 UModel 全局唯一。

前置要求

  1. SLS MetricStore:已创建 MetricStore,并有指标数据写入。

  2. 指标数据:了解 MetricStore 中的指标名称、标签结构。

操作步骤

步骤一:定义 SLS MetricStore 存储

创建 sls_metricstore.yaml 文件,定义指标数据的物理存储位置:

kind: sls_metricstore
schema:
  url: "umodel.aliyun.com"
  version: "v0.1.0"
metadata:
  name: "custom.metrics.storage"
  display_name:
    zh_cn: "自定义指标存储"
    en_us: "Custom Metrics Storage"
  description:
    zh_cn: "自定义业务指标的物理存储配置"
    en_us: "Physical storage configuration for custom business metrics"
  domain: custom
spec:
  region: "cn-hangzhou"           # SLS Project 所在区域
  project: "my-observability"     # SLS Project 名称
  store: "business-metrics"       # MetricStore 名称

配置参数说明

参数名

类型

必填

描述

示例值

kind

string

存储类型标识

固定值:sls_metricstore

region

string

SLS 服务区域

cn-hangzhou

project

string

SLS Project 名称

my-observability

store

string

MetricStore 名称

business-metrics

步骤二:定义 MetricSet

您可以选择以下两种方式:

  • 关联现有 MetricSet:如果系统中已有合适的 MetricSet 定义,可直接在步骤 3 中将其关联到您的 MetricStore

  • 新建 MetricSet:如果需要自定义指标结构,按以下方式创建metric_set.yaml 文件,定义指标数据的结构、标签和查询方式:

    kind: metric_set
    schema:
      url: "umodel.aliyun.com"
      version: "v0.1.0"
    metadata:
      name: "custom.metric.business"
      display_name:
        zh_cn: "业务监控指标"
        en_us: "Business Monitoring Metrics"
      description:
        zh_cn: "自定义业务监控指标集,包含请求量、响应时间、成功率等核心指标"
        en_us: "Custom business monitoring metrics including request count, response time, success rate"
      domain: custom
    spec:
      query_type: prom             # 查询语法类型:prom(MetricStore 使用 PromQL)
      labels:
        dynamic: true              # 推荐设置为true:动态生成标签
        filter: 'business_request_total'  # 用于动态标签生成的指标名
        keys: # 标签字段列表,定义所有需要的维度字段 
          - name: service_name
            display_name:
              zh_cn: 服务名称
              en_us: Service Name
            type: string
            filterable: true
            analysable: true
            pattern: ".*"
          - name: endpoint
            display_name:
              zh_cn: 接口名称
              en_us: Endpoint
            type: string
            filterable: true
            analysable: true
            pattern: ".*"
          - name: region
            display_name:
              zh_cn: 地域
              en_us: Region
            type: string
            filterable: true
            analysable: true
            pattern: ".*"
      metrics:
        # 请求总数指标
        - name: request_count # 指标名称,唯一标识
          display_name:
            zh_cn: 请求次数
            en_us: Request Count
          description:
            zh_cn: 服务接收到的请求总次数
            en_us: Total number of requests received by the service
          generator: 'sum(increase(business_request_total{}[1m]))' # 定义指标的查询表达式(PromQL)
          aggregator: sum # 定义按维度(Label)聚合时的聚合算子, 聚合方式:sum、avg、max、min等
          data_format: KMB # 数据格式化:KMB、percent、byte、ms、s
          golden_metric: true # 是否为黄金指标(建议 3-5 个)
          interval_us: [60000000] # 采集间隔(微秒)
          type: gauge
    
        # 平均响应时间指标
        - name: avg_response_time
          display_name:
            zh_cn: 平均响应时间
            en_us: Average Response Time
          description:
            zh_cn: 服务请求的平均响应时间
            en_us: Average response time of service requests
          generator: |
            sum(rate(business_response_seconds_sum{}[1m])) / 
            sum(rate(business_response_seconds_count{}[1m]))
          data_format: ms
          unit: 'ms'
          golden_metric: true
          interval_us: [60000000]
          type: gauge
    
        # 成功率指标
        - name: success_rate
          display_name:
            zh_cn: 成功率
            en_us: Success Rate
          description:
            zh_cn: 服务请求的成功率百分比
            en_us: Success rate percentage of service requests
          generator: |
            (sum(increase(business_request_total{status="success"}[1m])) / 
             sum(increase(business_request_total{}[1m]))) * 100
          data_format: percent
          unit: '%'
          golden_metric: true
          interval_us: [60000000]
          type: gauge
    
        # 错误数指标
        - name: error_count
          display_name:
            zh_cn: 错误次数
            en_us: Error Count
          description:
            zh_cn: 服务请求的错误次数
            en_us: Number of failed requests
          generator: 'sum(increase(business_request_total{status="error"}[1m]))'
          aggregator: sum
          data_format: KMB
          golden_metric: false
          interval_us: [60000000]
          type: gauge

    Labels 配置

    属性名

    类型

    说明

    推荐值

    dynamic

    boolean

    是否动态生成标签

    强烈推荐设置为 true

    filter

    string

    用于动态标签生成的指标过滤器

    选择一个有代表性的指标名

    keys

    array

    标签字段列表

    定义所有需要的维度字段

    Metrics 配置

    属性名

    类型

    必填

    说明

    name

    string

    指标名称,唯一标识

    generator

    string

    定义指标的查询表达式, 查询表达式(PromQL)

    aggregator

    string

    定义按维度(Label)聚合时的聚合算子, 聚合方式:sumavgmaxmin

    data_format

    string

    数据格式化:KMBpercentbytemss

    golden_metric

    boolean

    是否为黄金指标(建议 3-5 个)

    interval_us

    array

    采集间隔(微秒)

    更多配置细节,请参考文档:Metrics 建模

步骤三:创建 Storage Link(存储链接)

创建 storage_link.yaml 文件,建立 MetricSet 与 SLS MetricStore 的关联:

kind: storage_link
schema:
  url: "umodel.aliyun.com"
  version: "v0.1.0"
metadata:
  name: "custom.metric.business_storage_link"
  display_name:
    zh_cn: "业务指标存储链接"
    en_us: "Business Metrics Storage Link"
  description:
    zh_cn: "将业务监控指标集链接到 SLS MetricStore"
    en_us: "Link business metrics to SLS MetricStore"
  domain: custom
spec:
  src:
    domain: custom
    kind: metric_set
    name: custom.metric.business
  dest:
    domain: custom
    kind: sls_metricstore
    name: custom.metrics.storage

步骤四:上传配置

将配置文件通过以下方式上传到 UModel 系统:

  1. 登录云监控2.0控制台

  2. 进入目标工作空间,在左侧导航栏选择UModel探索

  3. UModel 探索页面,单击页面右上角image,在弹出框中单击上传 UModel YAML /JSON

  4. 批量上传 UModel的弹窗中,单击image选择文件,或将文件拖拽到上传框中:sls_metricstore.yamlmetric_set.yamlstorage_link.yaml

  5. 文件上传后,单击立即导入

  6. 导入成功后,单击页面右上角提交

  7. 在提交预览页面,检查内容无误后,单击确认内容符合预期,执行变更。在变更情况弹框中,单击确定

  8. UModel探索页面,确认 MetricSet、StorageLinkSLS MetricStore已创建。

步骤五:验证配置

进入实体探索,单击SPL,输入SPL语句验证是否生效:

1. 验证 MetricSet 创建成功

.umodel | where kind = 'metric_set' and json_extract_scalar(metadata, '$.name') = 'custom.metric.business'

2. 验证数据可查询

.metric_set with(domain='custom', name='custom.metric.business') | limit 10

数据查询

MetricStore 接入 UModel 后,支持两种查询方式:SPL 查询,SPL(Search Processing Language)是 SLS 提供的统一查询语言,可以直接查询 MetricSet 中的指标数据。

查询入口:在实体探索页面,单击SPL,在右侧输入框中输入查询语句。

基础查询语法

-- 查询 MetricSet 基础语法
.metric_set with(
    domain='域名', 
    name='数据集名称', 
    source='metrics', 
    metric='指标名', 
    [其他可选参数]
)

示例:

  • 基础查询:查询api_request_duration指标,不做聚合直接返回所有指标,Step使用Auto模式。

    .metric_set with(
        domain='rum', 
        name='rum.metric.api', 
        source='metrics', 
        metric='api_request_duration',
        aggregate=false
    )
  • 聚合查询:查询 request_count 指标,并聚合 service 和 operation 维度,过滤条件为 service_id = “hwx28v3j7p@9949e3dbf79e9a082105c”,查询步长为1分钟。

    .metric_set with(
        domain='apm', 
        name='apm.metric.apm.operation', 
        source='metrics', 
        metric='request_count',
        query_type='range',
        step='1m',
        aggregate=true,
        aggregate_labels=['service', 'operation'],
        query='service_id = "hwx28v3j7p@9949e3dbf79e9a082105c"'
    )
  • 聚合后分析:查询 error_rate 指标,进行统一聚合,并调用异常检测 SPL 进一步分析。

    .metric_set with(
        domain='apm',
        name='apm.metric.apm.service',
        source='metrics',
        metric='error_rate',
        step='1m',
        aggregate='true'
      )
    | extend slice_index = find_first_index(__ts__, x -> x > 1756904640000000000)
    | extend len = cardinality(__ts__)
    | extend ret = series_cnn_anomalies(__value__)
    | extend anomalies_score_series = ret.anomalies_score_series, anomalies_type_series = ret.anomalies_type_series, error_msg = ret.error_msg
    | project __labels__, __name__, __ts__, __value__, anomalies_score_series, anomalies_type_series, error_msg,len,slice_index
    | extend __ts__ = slice(__ts__, slice_index, len - slice_index), __value__ = slice(__value__, slice_index, len - slice_index), anomalies_score_series = slice(anomalies_score_series, slice_index, len - slice_index), anomalies_type_series = slice(anomalies_type_series, slice_index, len - slice_index)
    | extend anomay_cnt = CARDINALITY(FILTER(anomalies_score_series, x -> x > 0.5)), anomaly_sorce = array_sum(FILTER(anomalies_score_series, x -> x > 0.5))
    | extend sort_score = anomaly_sorce / cast(anomay_cnt as double) 
    | sort sort_score desc , anomay_cnt desc
    

面向实体(EntitySet)数据查询

  • 查询 service_id 等于 order-service 的request_count 指标

    .entity_set with(domain='apm', name='apm.service', query='service_id = "order-service"')
    | entity-call get_metric('apm', 'apm.metric.apm.service', 'request_count', 'range', '1m')
  • 查询 request_count 指标,进行统一聚合,并调用异常检测 SPL 进一步分析。

    .entity_set with(domain='apm', name='apm.service', query='service_id = "order-service"')
    | entity-call get_metric('apm', 'apm.metric.apm.service', 'request_count', 'range', '1m')
    | extend slice_index = find_first_index(__ts__, x -> x > 1756904640000000000)
    | extend len = cardinality(__ts__)
    | extend ret = series_cnn_anomalies(__value__)
    | extend anomalies_score_series = ret.anomalies_score_series, anomalies_type_series = ret.anomalies_type_series, error_msg = ret.error_msg
    | project __labels__, __name__, __ts__, __value__, anomalies_score_series, anomalies_type_series, error_msg,len,slice_index
    | extend __ts__ = slice(__ts__, slice_index, len - slice_index), __value__ = slice(__value__, slice_index, len - slice_index), anomalies_score_series = slice(anomalies_score_series, slice_index, len - slice_index), anomalies_type_series = slice(anomalies_type_series, slice_index, len - slice_index)
    | extend anomay_cnt = CARDINALITY(FILTER(anomalies_score_series, x -> x > 0.5)), anomaly_sorce = array_sum(FILTER(anomalies_score_series, x -> x > 0.5))
    | extend sort_score = anomaly_sorce / cast(anomay_cnt as double) 
    | sort sort_score desc , anomay_cnt desc