3. Loki 日志采集架构:Promtail 配置、日志流(Stream)概念、标签(Label)与元数据(Metadata)的区别
在构建弹性伸缩健康检查的告警降噪体系时,理解 Loki 的日志采集架构是基础。错误的标签设计会导致日志流膨胀、查询效率低下,进而引发告警风暴。本节将深入剖析 Promtail 的配置核心、日志流(Stream)的构成原理,以及标签(Label)与元数据(Metadata)的本质区别。
3.1 Promtail:日志采集的“守门员”
Promtail 是 Loki 生态中的日志采集代理,负责从目标节点抓取日志、添加标签,并将日志条目推送到 Loki。在弹性伸缩场景中,Promtail 通常以 DaemonSet 形式部署在每个 Kubernetes 节点上,确保每个 Pod 的日志都能被采集。
Promtail 的核心配置包含三个关键阶段:发现目标(scrape_configs)、处理管道(pipeline)、标签注入(relabel_configs)。
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
# 保留原始 Pod 名称作为临时标签
- source_labels: [__meta_kubernetes_pod_name]
target_label: __tmp_pod_name
# 将 namespace 映射为正式标签
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
# 将容器名称映射为正式标签
- source_labels: [__meta_kubernetes_pod_container_name]
target_label: container
# 丢弃高基数的 Pod 名称标签,避免流爆炸
- action: drop
regex: .*
source_labels: [__tmp_pod_name]
pipeline_stages:
- regex:
expression: '^(?P<level>(INFO|WARN|ERROR|DEBUG))\s'
- labels:
level:
- timestamp:
source: time
format: RFC3339
namespace、app、service 等低基数标签。
3.2 日志流(Stream):标签的唯一组合
在 Loki 中,日志流(Stream) 是由一组完全相同的标签(Label)组合唯一标识的日志序列。每个日志条目必须属于且仅属于一个流。流的数量直接决定了 Loki 的索引大小和写入性能。
流的计算公式为:
Stream 数量 = 标签1的基数 × 标签2的基数 × ... × 标签N的基数
例如,如果使用 {namespace, app, pod_name} 三个标签,且 namespace 有 5 个,app 有 10 个,pod_name 有 100 个(弹性伸缩峰值),则最大流数量为 5 × 10 × 100 = 5000 个流。如果去掉 pod_name,流数量骤降至 50 个。
下图展示了从日志采集到流形成的完整链路:
3.3 标签(Label)与元数据(Metadata)的本质区别
这是 Loki 使用中最容易混淆的概念,也是告警降噪的关键决策点。标签和元数据在 Loki 架构中扮演着完全不同的角色:
| 对比维度 | 标签(Label) | 元数据(Metadata) |
|---|---|---|
| 存储位置 | 索引(Index) | 日志内容(Log Entry) |
| 查询方式 | {label="value"} 流选择器 |
|= "keyword" 内容过滤 |
| 基数要求 | 低基数(建议 < 100 个唯一值) | 无限制(可包含高基数数据) |
| 对性能影响 | 影响索引大小和写入吞吐 | 影响查询时的内容扫描 |
| 典型用途 | 环境、服务名、集群、级别 | Pod 名称、请求 ID、错误堆栈 |
| 告警场景 | 用于分组和聚合告警 | 用于告警详情和上下文 |
|~ 或 |= 操作符进行过滤,而不是将其提升为标签。
3.4 标签设计决策树
在配置 Promtail 时,可以使用以下决策树来判断一个字段应该作为标签还是元数据:
- 该字段是否用于告警分组? 是 → 考虑作为标签;否 → 进入下一步。
- 该字段的唯一值数量是否超过 100? 是 → 作为元数据;否 → 进入下一步。
- 该字段是否会在查询中被频繁用作流选择器? 是 → 作为标签;否 → 作为元数据。
- 该字段是否随弹性伸缩动态变化? 是 → 强烈建议作为元数据;否 → 可考虑作为标签。
{namespace, app, container}。如果需要区分不同集群,可增加 cluster 标签。所有 Pod 级别的动态信息(名称、节点、IP)都应通过 Promtail 的 pipeline 阶段提取为元数据,或直接保留在原始日志行中。
通过严格区分标签与元数据,可以有效控制日志流数量,确保 Loki 在弹性伸缩场景下的写入和查询性能,为后续的告警降噪工程奠定坚实的基础。