LabHub
学习 学习路径 课程

Loki — 不索引日志的日志库

LogQL 由三部分组成

在 LabHub 中继续学习

一句话总结

LogQL 查询由流选择器 → 日志过滤器 → 聚合三部分组成,查询性能几乎完全由第一部分决定。

概念图: 流选择器 → 日志过滤器 → 聚合 · 没有缩小范围 · 1)流选择器 {...} · 2)日志过滤器 |= != | !

为什么需要理解查询范围

绝大多数“Loki 查询很慢”的问题,并不是语法造成的,而是没有缩小范围。如果开头的大括号选中了十万个流,那么后面无论进行什么处理都会很慢。

三个组成部分

sum by (pod) (
  rate({namespace="labhub-prod", app="labhub"} |= "error" | json | status >= 500 [5m])
)
 ^--집계--^        ^------- 스트림 셀렉터 -------^ ^------ 로그 필터 ------^

1)流选择器 {...}——通过已建立索引的标签筛选候选流。至少必须有一个选择条件,而且等号匹配器(=)比正则表达式(=~)便宜得多。

2)日志过滤器 |= != |~ !~——扫描所选流的正文。处理顺序非常重要。

# 나쁨 — 파싱부터 하고 거른다
{app="labhub"} | json | level = "error"

# 좋음 — 문자열로 먼저 줄이고 파싱한다
{app="labhub"} |= "error" | json | level = "error"

|= 只是简单的子字符串检查,成本很低;| json 则需要逐行解析,成本很高。把便宜的操作放在前面,就能大幅减少需要解析的行数。

3)聚合——包括 ratecount_over_timesum by 等操作,日志会在这里转换成指标。

# 초당 오류 수를 파드별로
sum by (pod) (rate({app="labhub"} |= "error" [5m]))

# 오류 메시지 상위 10개
topk(10, sum by (msg) (count_over_time({app="labhub"} | json [1h])))

三种解析器

解析器 何时使用
` json`
` logfmt`
` pattern`
` regexp`

解析后生成的字段没有索引。因此,| status >= 500 执行的是扫描,而不是索引查询。如果某个值经常使用,可以考虑在采集时把它提升为标签,但必须先计算基数。

常见误解

“增加标签会让查询变快。” 每增加一个标签,流的数量就会乘以该标签的取值数量。把 status 设为标签会使流增加到 5 倍(2xx/3xx/4xx/5xx/其他);把 user_id 设为标签,则会按用户数量增加。流越多,所有查询都会变慢。

|~ 正则表达式更方便。”|~ "error|warn" 相比,|= "error" or |= "warn" 便宜得多。正则表达式需要逐行运行引擎。

理解查询执行顺序,就能看见成本

LogQL 是一条流水线,在越靠前的位置缩小数据量,成本永远越低。

{namespace="labhub-prod", app="api"}   ← 1. 색인으로 스트림을 고른다 (거의 공짜)
  |= "timeout"                          ← 2. 원문 문자열 필터 (싸다)
  | json                                ← 3. 파싱 (비싸다)
  | status >= 500                       ← 4. 파싱된 필드로 필터
  | line_format "{{.msg}}"              ← 5. 출력 성형

改变顺序,结果也会改变。如果先运行 | json,再运行 |= "timeout",就等于 解析全部日志行之后才把其中大部分丢弃。尽量把字符串过滤器提前,是优化 LogQL 的第一条规则。

转换为指标——从日志中生成图表

对日志进行计数,就能得到指标。这在尚未加入监控埋点的系统中尤其有用。

# 5분간 5xx 비율
sum(rate({app="api"} |= "HTTP/1.1" 5" [5m]))
  /
sum(rate({app="api"} [5m]))

# 파싱한 필드로 p95 지연
quantile_over_time(0.95,
  {app="api"} | json | unwrap duration_ms [5m]) by (route)

不过,不能把这种查询长期放在仪表盘中。扫描日志的成本远高于查询时间序列。 确认某个值确实有用后,应该在应用程序中加入真正的指标,只在调查时使用 基于日志的查询。日志生成的指标是一种侦察工具,用于判断“是否值得添加指标”。

提前确定保留策略与压缩方式

Loki 会把日志组成数据块后写入对象存储。这里必须做出两个决定。

用于告警的查询应采用较短范围(5~15 分钟),并与调查用的长范围查询分开。 如果每分钟都执行一次覆盖 24 小时的查询,成本会悄无声息地增长。

实际工作中真正重要的事

查询缓慢时,首先应该测量的是选中的流数量

count(count by (pod, container) ({namespace="labhub-prod"}))

Grafana 的查询统计信息(Query inspector)中也会显示 Total bytes processed。如果这个值达到 GB 级,就说明查询范围过大。缩短时间范围或再添加一个标签,通常比调整查询语法更有效。