2. Loki基础架构:组件、日志流与标签设计原则

2.1 核心组件与职责

Loki采用微服务架构,其核心组件包括Distributor(分发器)、Ingester(写入器)和Querier(查询器)。三者协同工作,实现日志数据的接收、存储与检索。

架构要点: 所有组件均无状态(除Ingester持有短暂内存数据),可通过水平扩展提升吞吐与可用性。
Loki 核心组件架构 日志客户端 Distributor Ingester 对象存储 Querier 查询前端 数据流说明: 写入路径:客户端 → Distributor(校验/分片) → Ingester(内存缓存/预聚合) → 对象存储(持久化) 查询路径:查询前端 → Querier → Ingester(热数据) + 对象存储(冷数据) → 合并返回

2.2 组件职责详解

组件 核心职责 关键特性
Distributor 接收日志写入请求,验证数据合法性,按标签哈希分片转发至对应Ingester 无状态、可水平扩展;支持速率限制与数据校验
Ingester 接收日志流并写入内存,定期将数据刷入对象存储;响应Querier对热数据的查询 持有最近N小时数据(可配置);故障时通过WAL恢复
Querier 接收LogQL查询请求,同时从Ingester(热数据)和对象存储(冷数据)拉取日志,合并去重后返回 无状态;支持并行查询与缓存加速
实践提示: 生产环境中建议将Ingester的内存保留时间设为1-3小时,平衡查询性能与故障恢复成本。

2.3 日志流与标签设计原则

日志流(Log Stream)是Loki中数据组织的基本单元。具有相同标签集合的日志条目属于同一个流。标签设计直接影响查询效率与存储成本。

标签设计核心原则

  • 高基数标签禁止作为主标签: 如 user_id、request_id、ip 等取值过多的字段,应作为日志内容而非标签。
  • 低基数标签优先: 如 job、level、service、environment、cluster。
  • 标签数量控制在5-8个: 过多标签导致流数量爆炸,增加Ingester内存压力。
  • 使用结构化解析替代标签: 通过LogQL的 | json、| logfmt、| regexp 等解析器提取字段,而非全部做成标签。
标签设计:推荐 vs 不推荐 ✅ 推荐设计 • job: "api-server" • level: "error" • service: "payment" • environment: "prod" • cluster: "us-east-1" 基数低,查询快,流数量可控 ❌ 不推荐设计 • user_id: "u12345" • request_id: "req-abc" • ip: "10.0.0.1" • container_id: "c1a2b3" • trace_id: "trace-xyz" 基数爆炸,Ingester内存飙升,查询慢

2.4 Loki与Prometheus的异同

Loki的设计理念深受Prometheus影响,但两者在数据模型、存储目标和查询语言上存在本质差异。

对比维度 Prometheus Loki
数据类型 时序数值(指标) 日志文本(事件)
标签作用 标识时间序列,用于聚合与过滤 标识日志流,用于快速定位日志来源
数据内容 数值点(float64 + 时间戳) 日志行(字符串 + 时间戳 + 元数据)
查询语言 PromQL(聚合、预测、数学运算) LogQL(过滤、解析、标签提取、指标聚合)
存储引擎 TSDB(时序块压缩) 对象存储 + 索引(日志块压缩)
索引策略 基于标签的倒排索引 基于标签的倒排索引 + 日志内容不索引
水平扩展 通过Thanos/Cortex实现 原生微服务架构,天然支持
典型场景 告警、仪表盘、容量规划 故障排查、审计、日志分析
常见误区: 不要试图用Loki替代Prometheus做实时告警(延迟较高),也不要用Prometheus存储日志文本。两者是互补关系,而非替代关系。

2.5 架构设计带来的工程优势

  • 低成本存储: 日志内容不建索引,仅索引标签,存储成本仅为Elasticsearch的1/5-1/10。
  • 原生云原生: 与Kubernetes深度集成,自动发现Pod日志,无需额外采集配置。
  • 查询与写入分离: Distributor和Querier独立扩展,写入高峰不影响查询性能。
  • 热冷分层: Ingester内存数据提供毫秒级查询,对象存储数据支持大规模历史检索。