2. Loki 基础回顾:架构、LogQL 与标签流

在深入告警降噪之前,必须统一团队对 Loki 核心概念的认知。本章从架构、查询语言、标签与流三个维度,为后续标签优化策略打下坚实的技术基础。

2.1 Loki 整体架构

Loki 采用微服务架构,核心组件包括 Distributor、Ingester、Querier 和 Compactor。与 Prometheus 不同,Loki 不进行全文索引,而是通过标签索引日志流,大幅降低存储成本。

Loki 核心架构图 Loki 核心架构图 日志客户端 Distributor Ingester 对象存储 Querier Compactor 关键设计理念: • 标签索引:仅对日志流标签建立索引,日志内容不索引,大幅降低存储与查询成本。 • 无状态组件:Distributor 与 Querier 无状态,支持水平扩展,适合弹性伸缩场景。 • 对象存储后端:S3/GCS/MinIO 等,存储成本仅为 Elasticsearch 的 1/10 至 1/5。
架构启示:在弹性伸缩场景中,Distributor 的标签哈希分发机制决定了日志流的分布。标签基数过高会导致 Distributor 内存压力增大,这是后续优化的重要切入点。

2.2 LogQL 查询语言

LogQL 是 Loki 的查询语言,语法与 PromQL 高度兼容。它分为两个核心部分:日志流选择器和日志管道。

2.2.1 日志流选择器

流选择器通过标签匹配过滤日志流,语法与 Prometheus 标签匹配器一致:

{app="nginx", environment="production"}
{job=~"api-server.*", namespace="default"}
{cluster="prod-us-east", container!="sidecar"}
匹配器类型 语法 说明 示例
精确匹配 = 标签值完全相等 app="nginx"
正则匹配 =~ 标签值匹配正则表达式 job=~"api-.*"
反向匹配 != 标签值不相等 container!="sidecar"
反向正则 !~ 标签值不匹配正则 level!~"debug|trace"

2.2.2 日志管道操作

管道操作符对匹配到的日志行进行二次处理,常用操作包括:

  • line_format:重新格式化日志行输出
  • label_format:修改或添加标签
  • unwrap:从日志内容中提取数值用于指标计算
  • rate/count_over_time:计算日志速率或时间窗口内的计数
{app="nginx"} |= "error" | json | line_format "{{.message}}"
{job="api-server"} | logfmt | duration > 1.5 | rate($__interval)
性能陷阱:管道操作中的正则表达式和 JSON 解析会消耗 CPU 资源。在弹性伸缩场景中,应避免在查询时做复杂解析,优先在采集端完成结构化。

2.3 标签(Label)与流(Stream)

标签是 Loki 的核心抽象,决定了日志的存储、索引和查询效率。理解标签与流的关系,是告警降噪的前提。

2.3.1 标签的定义与作用

标签是键值对,用于标识日志的来源和属性。每个日志行在写入时都附带一组标签,Loki 根据标签组合将日志组织成不同的流(Stream)。

标签类型 示例 基数建议 说明
固定标签 cluster, namespace 低(< 100) 环境、集群等不变属性
动态标签 pod, instance 中(< 10,000) Pod 名称、实例 ID 等
高基数标签 request_id, user_id 极高(> 100,000) ⚠️ 应避免作为标签

2.3.2 流(Stream)的概念

流是具有相同标签组合的日志序列。例如,标签组合 {app="nginx", pod="nginx-abc123"} 定义了一个唯一的流。Loki 将流作为存储和索引的基本单位。

标签组合与流的关系 标签组合 → 流(Stream) 标签组合 A app="nginx" pod="nginx-abc" 标签组合 B app="nginx" pod="nginx-def" 标签组合 C app="api-server" pod="api-xyz" Stream A Stream B Stream C 核心规则: 1. 每个唯一标签组合 对应一个流。 2. 流数量 = 标签组合 的笛卡尔积。 3. 高基数标签会导致 流数量爆炸。 4. 每个流在 Ingester 中占用独立内存。 5. 弹性伸缩时,流数 量直接影响扩缩容 的稳定性和速度。

2.3.3 标签基数与性能的关系

标签基数是影响 Loki 性能的最关键因素。在弹性伸缩场景中,Pod 频繁创建和销毁会导致标签基数剧烈波动,进而引发以下问题:

  • Ingester 内存飙升:每个新流都需要在内存中创建新的 chunk,大量短生命周期流会导致内存碎片。
  • Distributor 哈希冲突:高基数标签导致哈希环分布不均,部分节点负载过高。
  • 查询性能下降:流选择器需要扫描更多索引条目,查询延迟增加。
  • 告警抖动:流频繁创建/删除导致指标出现毛刺,触发误告警。
工程经验:在 Kubernetes 弹性伸缩场景中,建议将 Pod 名称等动态标识从标签中移除,改用 __pod_name__ 内部标签或日志内容字段。目标是将流数量控制在 10,000 以内,这是 Loki 官方推荐的单集群最佳实践上限。

2.4 本章小结