跳转至

Loki

Loki 是 Grafana Labs 推出的日志聚合系统,常和 Grafana、Grafana Alloy、Fluent Bit 或 Vector 一起组成日志观测方案。它的设计目标不是全文索引所有日志内容,而是通过 label 索引日志流,再按时间范围读取日志内容。

loki

Abstract

Loki 的核心定位是“像 Prometheus 一样处理日志”:用 label 定位日志流,用查询语言 LogQL 检索和聚合日志。

实践中需要重点关注:

  • Loki 只索引 label,不默认索引完整日志内容
  • label 应该低基数,避免把 request id、user id、trace id 等高基数字段放进 label
  • 日志采集通常由 Grafana Alloy、Fluent Bit 或 Vector 完成;Promtail 已 EOL,不建议新部署
  • Grafana 负责查询、展示和告警
  • 生产环境要关注日志保留周期、存储后端、限流、查询性能和 label 设计

背景

传统日志系统常见做法是对日志内容建立全文索引,查询灵活但存储和索引成本较高。Loki 选择了另一条路线:

  • 只对 label 建立索引
  • 日志正文按时间切分后写入对象存储或本地文件系统
  • 查询时先通过 label 找到日志流,再扫描对应时间范围内的日志内容

Loki 的核心思路

  • 用 label 定位服务、实例、环境、命名空间等维度
  • 用日志正文保存具体事件内容
  • 用 LogQL 做过滤、解析和聚合
  • 用 Grafana 提供可视化查询和告警

核心组件

一个完整的 Loki 日志方案通常由日志采集、日志存储、查询语言和可视化入口组成:

  • Loki:接收、存储和查询日志
  • Alloy / Fluent Bit / Vector:采集日志并推送到 Loki
  • Grafana:查询、展示和告警
  • Object Storage:存储日志块,如 S3、GCS、MinIO
  • LogQL:Loki 的查询语言,用于过滤、解析和聚合日志

Promtail 与 Alloy

Promtail 是 Loki 早期常用的日志采集 Agent,但它已在 2026-03-02 进入 EOL,不再提供后续支持或更新。新系统应优先使用 Grafana Alloy、Fluent Bit 或 Vector;已有 Promtail 部署也应规划迁移到 Alloy 或其他受支持的采集器。


基本架构

flowchart LR
    App[Application Logs] --> Agent[Alloy / Fluent Bit / Vector]
    Agent -->|Push logs| Loki[Loki]
    Loki <-->|Read / Write chunks| Storage[(Object Storage)]
    User[User] --> Grafana
    Grafana[Grafana] -->|LogQL Query| Loki

一次典型日志链路:

  1. 应用把日志写到 stdout、文件或容器日志目录
  2. Alloy、Fluent Bit 或 Vector 作为采集 Agent 读取日志,并附加 label
  3. Agent 将日志推送到 Loki
  4. Loki 根据 label 和时间组织索引,并将日志块写入存储后端
  5. 用户在 Grafana 中编写 LogQL
  6. Grafana 将 LogQL 查询发送给 Loki,并展示查询结果

Label 模型

Loki 的 label 类似 Prometheus label,用来描述一组日志流。

常见 label:

  • job:采集任务或服务名
  • app:应用名称
  • env:环境,如 devstagingprod
  • namespace:Kubernetes namespace
  • pod:Kubernetes Pod 名称
  • container:容器名称
  • level:日志级别,如 infowarnerror

控制 label 基数

不要把高基数字段放进 label,例如:

  • request_id
  • trace_id
  • user_id
  • order_id
  • 完整 URL
  • 错误堆栈

高基数 label 会导致日志流数量爆炸,增加索引、写入和查询压力。此类字段应该留在日志正文中,在查询时通过 LogQL 过滤或解析。


LogQL

LogQL 是 Loki 的查询语言,语法风格接近 PromQL,但面向日志流。

基础查询

查询某个应用的所有日志:

{app="api"}

查询生产环境中 api 应用的错误日志:

{env="prod", app="api"} |= "error"

排除健康检查日志:

{app="api"} != "/health"

JSON 解析

如果日志是 JSON 格式,可以用 json 解析字段:

{app="api"} | json | level="error"

按字段过滤:

{app="api"} | json | status >= 500

聚合查询

统计 5 分钟内错误日志数量:

count_over_time({app="api"} |= "error" [5m])

按应用统计错误日志数量:

sum by (app) (
  count_over_time({env="prod"} |= "error" [5m])
)

Kubernetes 采集

在 Kubernetes 中,应用通常把日志写到容器标准输出。容器运行时会把 stdout / stderr 写入节点上的容器日志文件,采集 Agent 再以 DaemonSet 形式运行在每个节点上读取这些文件,并附加 namespacepodcontainer 等 label。

常见采集链路:

flowchart LR
    Pod[Pod stdout / stderr] --> File[Node container log file]
    File --> Agent[Alloy / Fluent Bit / Vector]
    Agent -->|Push logs with labels| Loki[Loki]
    Loki <-->|Read / Write chunks| Storage[(Object Storage)]
    Grafana[Grafana] -->|LogQL Query| Loki

常见 label 有 clusternamespaceapppodcontainernode

Kubernetes 中的 label 设计

Kubernetes 元数据很多,但不应该全部变成 Loki label。一般只保留稳定、低基数、查询时经常使用的字段,例如 clusternamespaceappcontainer。Pod 名称可用于定位问题,但在高规模集群中也需要关注基数。


Loki vs Elasticsearch

对比项 Loki Elasticsearch
索引方式 主要索引 label 可全文索引日志内容
存储成本 通常较低 通常较高
查询方式 先按 label 定位日志流,再过滤正文 可直接全文检索
适用场景 云原生日志、服务日志、Kubernetes 日志 复杂全文搜索、日志分析、审计检索
运维复杂度 相对较低 集群和索引管理复杂度较高

选择建议:

  • 如果日志主要按服务、环境、namespace、pod 等维度查询,Loki 很合适
  • 如果需要大量全文搜索、复杂字段索引和审计检索,Elasticsearch 更合适
  • Loki 更适合和 Prometheus / Grafana 观测体系集成

生产实践清单

  • Label 设计:只把低基数、常用查询维度放进 label
  • 日志格式:应用日志优先使用 JSON,便于 LogQL 解析字段
  • 日志级别:统一 debuginfowarnerror 等级
  • 保留周期:根据成本和排障需求设置 retention
  • 存储后端:生产环境优先使用对象存储
  • 限流保护:配置写入速率、查询长度、返回行数等限制
  • 多租户:需要隔离时启用 tenant,并规划认证方式
  • 告警规则:基于错误日志数量、关键字和服务维度配置告警
  • 日志脱敏:避免写入密码、Token、身份证、手机号等敏感信息
  • Trace 关联:日志正文中保留 trace_id,但不要放进 label

常见排障方向

查不到日志

  • Agent 是否正常运行
  • Agent 是否有权限读取日志文件
  • Loki URL 是否配置正确
  • label 选择器是否过窄
  • 查询时间范围是否正确

日志延迟较高

  • Agent 是否有发送积压
  • Loki ingester 是否过载
  • 对象存储写入是否变慢
  • 是否存在突发大流量日志
  • 限流配置是否过低

查询很慢

  • 查询时间范围是否过大
  • label 选择器是否太宽
  • 是否在大量日志正文上做复杂过滤
  • 是否缺少常用低基数 label
  • Loki 查询并发和资源是否不足

写入被拒绝

  • 是否超过 ingestion rate limit
  • 日志时间戳是否太旧
  • 单行日志是否过大
  • label 数量或 label value 是否超过限制
  • tenant 配置是否正确

存储增长过快

  • 日志级别是否过低,例如生产大量 debug
  • 是否有异常循环打印日志
  • retention 是否过长
  • 是否采集了不必要的 namespace 或容器
  • 是否需要在 Agent 侧丢弃无价值日志