2. Loki 核心概念详解
在深入使用 Loki 之前,必须理解其三大核心抽象:日志流(Log Stream)、标签(Label) 和 块(Chunk)。这三个概念构成了 Loki 的存储与查询基石,也是它与传统 ELK 架构最根本的差异所在。
2.1 日志流(Log Stream)
日志流是 Loki 中最基本的日志组织单元。它代表一组具有完全相同标签集合的日志条目,按时间顺序排列。每个日志流在 Loki 内部都有一个唯一的 Stream ID(由所有标签的键值对哈希生成)。
- 流标识:由标签组合唯一确定,例如
{job="nginx", env="prod", host="web-01"}构成一个流。 - 写入单元:Promtail 或其他采集器将日志行追加到对应的流中。
- 查询范围:LogQL 查询时,通过标签匹配器选择目标流,再在流内进行时间范围过滤或内容搜索。
关键理解:在 ELK 中,日志是独立的文档(Document),每个文档可以有不同的字段结构;而在 Loki 中,日志是流内的连续行,所有行共享相同的标签元数据。这种设计大幅降低了索引开销。
2.2 标签(Label)
标签是 Loki 的元数据索引,每个标签是一个键值对(Key-Value Pair)。Loki 只对标签建立倒排索引,不对日志内容建立全文索引。标签的设计直接影响查询性能和存储成本。
| 标签特性 | 说明 | 最佳实践 |
|---|---|---|
| 基数(Cardinality) | 标签值可能的取值数量 | 保持低基数(< 10000),避免使用用户ID、请求ID等高基数字段 |
| 命名规范 | 推荐使用小写字母、下划线 | job、instance、level、service |
| 常见标签 | 环境、服务名、主机、日志级别 | env="prod"、service="gateway" |
| 动态标签 | 从日志行中提取的临时标签 | 使用 | label_format 或 | line_format 在查询时派生 |
高基数陷阱:如果将每次请求的 TraceID 或 UserID 设为标签,会导致标签基数爆炸(数百万级别),Loki 的倒排索引将急剧膨胀,写入性能下降,存储成本飙升。正确的做法是将高基数信息保留在日志行内容中,通过 LogQL 的
|~ 正则表达式进行搜索。
2.3 块(Chunk)
块是 Loki 的实际数据存储单元。每个块包含一段时间窗口内、属于同一个日志流的连续日志行,经过压缩后存储到对象存储(如 S3、GCS、MinIO)中。
- 块生命周期:采集器推送日志 → Ingester 在内存中构建块 → 块达到大小或时间阈值 → 刷新到对象存储 → 长期保存。
- 块压缩:默认使用 gzip 或 snappy 压缩,压缩比通常可达 5:1 ~ 10:1。
- 块元数据:每个块记录其所属流、时间范围、行数、原始大小、校验和等信息,存储在 Index 中用于快速定位。
性能特征:查询时,Loki 先通过标签索引找到匹配的流,再根据时间范围定位到对应的块,最后从对象存储中读取并解压块内容。块的大小(默认 1.5MB 未压缩)和压缩算法直接影响查询延迟。
2.4 与传统 ELK 的对比
ELK(Elasticsearch + Logstash + Kibana)与 Loki 代表了两种截然不同的日志处理哲学:索引优先 vs. 标签优先。以下从多个维度进行对比:
| 对比维度 | ELK(Elasticsearch) | Loki |
|---|---|---|
| 索引策略 | 对日志所有字段建立倒排索引(全文索引) | 仅对标签建立倒排索引,日志内容不索引 |
| 存储模型 | 文档(Document)→ 分片(Shard)→ 索引(Index) | 日志行 → 日志流(Log Stream)→ 块(Chunk) |
| 写入成本 | 高:分词、索引、写入副本,CPU/内存开销大 | 低:仅压缩、写入对象存储,无索引开销 |
| 存储成本 | 高:索引数据通常占原始日志的 50%~100% | 低:仅存储压缩后的日志,通常为原始大小的 10%~20% |
| 查询方式 | 全文搜索 + 聚合分析(DSL) | 标签过滤 + 内容搜索(LogQL) |
| 查询延迟 | 毫秒级(索引命中) | 秒级(需扫描块内容) |
| 适用场景 | 复杂搜索、聚合分析、业务洞察 | 实时监控、故障排查、Kubernetes 日志 |
| 运维复杂度 | 高:需要管理集群、分片、索引生命周期 | 低:无状态组件 + 对象存储,易于扩展 |
架构哲学差异:ELK 追求“搜索一切”,通过索引换取查询速度;Loki 追求“成本优先”,通过标签过滤缩小扫描范围,用计算(扫描块)换存储。在发布监控场景中,我们通常只需要按服务名、环境、时间范围快速查看日志,Loki 的模型天然匹配。
2.5 核心概念在发布监控中的映射
在发布工程自助门户场景中,Loki 的核心概念与业务需求直接对应:
- 日志流:每个发布单元(如一个微服务实例)的日志构成一个独立的流,通过
{service="order-svc", version="v2.1.0", instance="pod-abc"}唯一标识。 - 标签:
service(服务名)、version(发布版本)、env(环境)、level(日志级别)作为核心标签,用于快速筛选特定发布的日志。 - 块:发布期间的日志被压缩存储,查询时只需扫描该时间窗口内的块,无需全量扫描。
发布监控最佳实践:在 Promtail 配置中,将
service、version、env 作为固定标签,将 level、instance 作为可选标签。避免将 trace_id、user_id 等高基数字段设为标签,应保留在日志行内容中,通过 LogQL 的 |~ 进行搜索。
2.6 小结
理解日志流、标签、块三者的关系,是掌握 Loki 的关键:标签决定了查询的筛选能力,日志流决定了数据的组织方式,块决定了存储与查询的效率。与 ELK 相比,Loki 牺牲了部分查询灵活性(不支持全文索引),换来了极低的存储成本和运维复杂度,使其成为发布监控、Kubernetes 日志等场景的理想选择。