标签与标签选择器 #

一、标签概述 #

1.1 什么是标签 #

text
标签定义:

┌─────────────────────────────────────────────┐
│ 标签是键值对,用于区分同一指标的不同维度   │
└─────────────────────────────────────────────┘

示例:
http_requests_total{method="GET", status="200", instance="localhost:8080"}

解析:
┌─────────────────────────────────────────────┐
│ 指标名称:http_requests_total               │
├─────────────────────────────────────────────┤
│ 标签:                                      │
│   method="GET"                              │
│   status="200"                              │
│   instance="localhost:8080"                 │
├─────────────────────────────────────────────┤
│ 标签组合唯一标识一个时间序列               │
└─────────────────────────────────────────────┘

不同的标签值 = 不同的时间序列:

http_requests_total{method="GET", status="200"}    # 时间序列1
http_requests_total{method="GET", status="404"}    # 时间序列2
http_requests_total{method="POST", status="200"}   # 时间序列3

1.2 标签类型 #

text
标签分类:

┌─────────────────────────────────────────────┐
│ 1. 应用标签                                 │
├─────────────────────────────────────────────┤
│ • 由应用程序定义                            │
│ • 反映业务逻辑                              │
│ • 示例:method, status, endpoint            │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 2. 目标标签                                 │
├─────────────────────────────────────────────┤
│ • 由Prometheus配置添加                      │
│ • 标识数据来源                              │
│ • 示例:job, instance                       │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 3. 内部标签                                 │
├─────────────────────────────────────────────┤
│ • 以__开头                                  │
│ • 用于内部处理                              │
│ • 不会存储到TSDB                            │
│ • 示例:__address__, __scheme__             │
└─────────────────────────────────────────────┘

1.3 标签命名规范 #

text
标签命名规范:

┌─────────────────────────────────────────────┐
│ 命名规则                                    │
├─────────────────────────────────────────────┤
│ • 键名匹配正则:[a-zA-Z_][a-zA-Z0-9_]*     │
│ • 使用snake_case命名                        │
│ • 应该有明确含义                            │
│ • 避免使用保留名称                          │
└─────────────────────────────────────────────┘

好的命名:
method          # HTTP方法
status          # HTTP状态码
endpoint        # API端点
service         # 服务名称
environment     # 环境

不好的命名:
m               # 太短,含义不清
httpMethod      # 不推荐驼峰
method_1        # 数字后缀无意义
__custom        # 不要使用__前缀

保留名称:
__name__        # 指标名称
__address__     # 目标地址
__scheme__      # 协议方案
__metrics_path__ # 指标路径

二、标签选择器 #

2.1 基本语法 #

text
标签选择器语法:

┌─────────────────────────────────────────────┐
│ 匹配类型                                    │
├─────────────────────────────────────────────┤
│ =   精确匹配                                │
│ !=  不匹配                                  │
│ =~  正则匹配                                │
│ !~  正则不匹配                              │
└─────────────────────────────────────────────┘

示例:

# 精确匹配
http_requests_total{method="GET"}

# 不匹配
http_requests_total{method!="POST"}

# 正则匹配
http_requests_total{method=~"GET|POST"}

# 正则不匹配
http_requests_total{method!~"DELETE|PUT"}

# 多条件组合(AND关系)
http_requests_total{method="GET", status="200"}

# 匹配所有(空选择器)
http_requests_total{}

2.2 精确匹配 #

promql
# 等于匹配
http_requests_total{method="GET"}

# 不等于匹配
http_requests_total{method!="POST"}

# 多标签精确匹配
http_requests_total{method="GET", status="200"}

# 匹配指标名称
{__name__="http_requests_total"}

# 匹配job
http_requests_total{job="api-server"}

2.3 正则匹配 #

promql
# 正则匹配
http_requests_total{method=~"GET|POST|PUT"}

# 正则不匹配
http_requests_total{method!~"DELETE|PATCH"}

# 匹配以/api开头的endpoint
http_requests_total{endpoint=~"/api/.*"}

# 匹配状态码2xx
http_requests_total{status=~"2.."}

# 匹配多个实例
http_requests_total{instance=~"node[1-3]:.*"}

# 组合正则
http_requests_total{method=~"GET|POST", status=~"2.."}

2.4 选择器组合 #

promql
# 多条件AND(逗号分隔)
http_requests_total{method="GET", status="200"}

# 使用集合操作实现OR
# 方法1:使用正则
http_requests_total{method=~"GET|POST"}

# 方法2:使用or操作符
http_requests_total{method="GET"} or http_requests_total{method="POST"}

# 复杂组合
http_requests_total{method="GET", status=~"2.."} or 
http_requests_total{method="POST", status="201"}

# 排除特定标签值
http_requests_total{method="GET", status!="404"}

三、常用标签 #

3.1 目标标签 #

text
目标标签说明:

┌─────────────────────────────────────────────┐
│ job                                         │
├─────────────────────────────────────────────┤
│ • 采集任务名称                              │
│ • 在scrape_configs中定义                    │
│ • 标识数据来源类型                          │
│                                             │
│ 示例:                                      │
│ job="node-exporter"                         │
│ job="prometheus"                            │
│ job="mysql-exporter"                        │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ instance                                    │
├─────────────────────────────────────────────┤
│ • 目标实例地址                              │
│ • 格式:host:port                           │
│ • 标识具体实例                              │
│                                             │
│ 示例:                                      │
│ instance="localhost:9090"                   │
│ instance="192.168.1.100:9100"               │
└─────────────────────────────────────────────┘

3.2 内部标签 #

text
内部标签说明:

┌─────────────────────────────────────────────┐
│ __address__                                 │
├─────────────────────────────────────────────┤
│ • 目标地址                                  │
│ • 格式:host:port                           │
│ • 用于构造请求URL                           │
│ • 可被relabel修改                           │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ __scheme__                                  │
├─────────────────────────────────────────────┤
│ • 协议方案                                  │
│ • 值:http 或 https                         │
│ • 默认:http                                │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ __metrics_path__                            │
├─────────────────────────────────────────────┤
│ • 指标路径                                  │
│ • 默认:/metrics                            │
│ • 可被relabel修改                           │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ __param_<name>                              │
├─────────────────────────────────────────────┤
│ • URL参数                                   │
│ • 用于传递查询参数                          │
│ • 示例:__param_format="prometheus"         │
└─────────────────────────────────────────────┘

四、标签操作 #

4.1 relabel_configs #

yaml
# relabel_configs:采集前的标签处理

scrape_configs:
  - job_name: 'node-exporter'
    kubernetes_sd_configs:
      - role: pod
    
    relabel_configs:
      # 只采集有特定标签的Pod
      - source_labels: [__meta_kubernetes_pod_label_app]
        regex: 'node-exporter'
        action: keep
      
      # 设置instance标签
      - source_labels: [__meta_kubernetes_pod_ip]
        target_label: instance
        replacement: '$1:9100'
      
      # 添加环境标签
      - target_label: environment
        replacement: 'production'
      
      # 删除不需要的标签
      - action: labeldrop
        regex: '__meta_kubernetes_pod_label_.+'

4.2 metric_relabel_configs #

yaml
# metric_relabel_configs:采集后的标签处理

scrape_configs:
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['localhost:9100']
    
    metric_relabel_configs:
      # 只保留特定指标
      - source_labels: [__name__]
        regex: 'node_(cpu|memory|disk|network).*'
        action: keep
      
      # 删除go运行时指标
      - source_labels: [__name__]
        regex: 'go_.*'
        action: drop
      
      # 修改标签值
      - source_labels: [mountpoint]
        regex: '/var/lib/docker/(.+)'
        target_label: docker_volume
        replacement: '$1'
      
      # 提取标签
      - source_labels: [__name__]
        regex: 'node_(.*)_seconds_total'
        target_label: metric_type
        replacement: '$1'

4.3 常用relabel操作 #

yaml
# 常用relabel操作示例

relabel_configs:
  # 1. keep:保留匹配的目标
  - source_labels: [__meta_kubernetes_namespace]
    regex: 'monitoring'
    action: keep

  # 2. drop:丢弃匹配的目标
  - source_labels: [__meta_kubernetes_namespace]
    regex: 'kube-system'
    action: drop

  # 3. replace:替换或添加标签(默认操作)
  - source_labels: [__address__]
    target_label: instance
    replacement: '$1'

  # 4. labelmap:批量重命名标签
  - action: labelmap
    regex: '__meta_kubernetes_pod_label_(.+)'

  # 5. labeldrop:删除标签
  - action: labeldrop
    regex: '__meta_kubernetes_.+'

  # 6. labelkeep:保留标签
  - action: labelkeep
    regex: '(job|instance|environment)'

五、标签最佳实践 #

5.1 标签设计原则 #

text
标签设计原则:

┌─────────────────────────────────────────────┐
│ 1. 基数控制                                 │
├─────────────────────────────────────────────┤
│ • 避免高基数标签                            │
│ • 标签值应该是有限集合                      │
│ • 不要使用用户ID、请求ID等                  │
│                                             │
│ 好的标签:                                  │
│ status="200"           # 有限值             │
│ method="GET"           # 有限值             │
│ environment="prod"     # 有限值             │
│                                             │
│ 不好的标签:                                │
│ user_id="12345"        # 无限值             │
│ request_id="abc123"    # 无限值             │
│ timestamp="1700000000" # 无限值             │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 2. 标签数量控制                             │
├─────────────────────────────────────────────┤
│ • 每个指标的标签数量适中                    │
│ • 通常不超过10个标签                        │
│ • 每个标签组合创建一个时间序列              │
│                                             │
│ 时间序列数量 = 标签值组合数                 │
│                                             │
│ 示例:                                      │
│ method: 5种                                 │
│ status: 10种                                │
│ instance: 3个                               │
│                                             │
│ 时间序列数 = 5 × 10 × 3 = 150               │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 3. 标签一致性                               │
├─────────────────────────────────────────────┤
│ • 相同概念使用相同标签名                    │
│ • 标签值格式统一                            │
│ • 避免同义不同名                            │
│                                             │
│ 好的做法:                                  │
│ service="user-service"                      │
│ service="order-service"                     │
│                                             │
│ 不好的做法:                                │
│ service="user-service"                      │
│ app="order-service"                         │
└─────────────────────────────────────────────┘

5.2 标签使用示例 #

yaml
# 好的标签设计示例

# HTTP请求指标
http_requests_total{
    method="GET",           # HTTP方法
    status="200",           # HTTP状态码
    endpoint="/api/users",  # API端点
    service="user-service", # 服务名称
    environment="prod"      # 环境
}

# 数据库查询指标
db_query_duration_seconds{
    db="mysql",             # 数据库类型
    operation="select",     # 操作类型
    table="users",          # 表名
    service="user-service"  # 服务名称
}

# 缓存指标
cache_operations_total{
    cache="redis",          # 缓存类型
    operation="get",        # 操作类型
    result="hit",           # 结果
    service="user-service"  # 服务名称
}

5.3 高基数问题 #

text
高基数问题分析:

┌─────────────────────────────────────────────┐
│ 什么是高基数                                │
├─────────────────────────────────────────────┤
│ • 标签值数量过多                            │
│ • 导致时间序列数量爆炸                      │
│ • 影响Prometheus性能                        │
└─────────────────────────────────────────────┘

高基数标签示例:

# 用户ID(高基数)
user_id="user_12345"
user_id="user_12346"
user_id="user_12347"
...数百万个不同值

# 请求ID(高基数)
request_id="req_abc123"
request_id="req_abc124"
...无限个不同值

# 时间戳(高基数)
timestamp="1700000000"
timestamp="1700000001"
...无限个不同值

解决方案:

1. 不记录高基数标签
   • 使用日志系统记录详细信息
   • 只记录聚合指标

2. 使用分桶或分组
   • 将连续值分桶
   • 将用户分组(如VIP/普通)

3. 使用采样
   • 只采样部分请求
   • 使用Histogram记录分布

六、标签查询技巧 #

6.1 按标签过滤 #

promql
# 精确匹配
http_requests_total{method="GET"}

# 多标签过滤
http_requests_total{method="GET", status="200"}

# 正则匹配
http_requests_total{method=~"GET|POST"}

# 排除特定值
http_requests_total{status!="404"}

# 正则排除
http_requests_total{method!~"DELETE|PUT"}

6.2 按标签聚合 #

promql
# 按单个标签聚合
sum by (method) (http_requests_total)

# 按多个标签聚合
sum by (method, status) (http_requests_total)

# 保留特定标签
sum by (instance) (http_requests_total)

# 不保留任何标签
sum (http_requests_total)

# 使用without排除标签
sum without (instance) (http_requests_total)

6.3 标签操作函数 #

promql
# label_replace:替换标签值
label_replace(up{job="node-exporter"}, "host", "$1", "instance", "(.*):.*")

# label_join:连接标签值
label_join(up{job="node-exporter"}, "new_label", "-", "job", "instance")

# 获取所有标签名
label_names()

# 获取特定指标的标签名
label_names(http_requests_total)

# 获取标签值
label_values(job)

# 获取特定指标的标签值
label_values(http_requests_total, method)

七、总结 #

标签要点:

概念 说明
标签 键值对,区分时间序列
目标标签 job, instance
内部标签 __前缀,不存储
选择器 =, !=, =~, !~

最佳实践:

原则 说明
控制基数 避免无限值标签
保持一致 相同概念相同命名
适度使用 标签数量适中

下一步,让我们学习命名规范!

最后更新:2026-03-27