2. Loki 架构回顾:读写路径、Ingester、Querier、Distributor 组件交互
在深入告警路由与性能调优之前,必须重新理解 Loki 的核心架构。Loki 的读写分离设计直接决定了告警规则的执行位置、查询延迟的瓶颈以及路由参数的生效范围。本节将拆解三个关键组件——Distributor、Ingester、Querier——以及它们之间的数据流与交互契约。
2.1 读写路径总览
Loki 采用 “写时复制索引、读时计算” 的哲学。写入路径追求低延迟、高吞吐;读取路径则依赖 Querier 对存储层和 Ingester 内存中的数据进行实时合并。下图展示了完整的读写分离架构:
2.2 核心组件职责与交互
| 组件 | 职责 | 关键交互对象 | 告警路由影响点 |
|---|---|---|---|
| Distributor | 接收日志流,验证合法性,基于哈希环将数据分片转发至 Ingester | Ingester、Consul/Etcd(哈希环) | 无直接路由影响,但决定了数据分布均匀性 |
| Ingester | 缓存写入数据,定期刷盘至对象存储;同时响应 Querier 的实时数据查询 | Distributor、Querier、对象存储 | 内存中未刷盘数据影响告警的实时性 |
| Querier | 执行 LogQL 查询,合并来自 Ingester(实时)和对象存储(历史)的结果 | Ingester、对象存储、Query Frontend | 告警规则在此执行,路由参数(如 parallelism)直接影响查询性能 |
2.3 Distributor:写入入口与数据分片
Distributor 是写入路径的第一站。它不存储任何数据,只负责转发。其核心流程如下:
- 接收与验证:接收来自 Promtail、Docker 插件等 Agent 的日志流,检查标签合法性、时间戳范围。
- 哈希分片:根据标签组合(如
{job="nginx", env="prod"})计算哈希值,通过一致性哈希环确定目标 Ingester 副本。 - 复制转发:默认复制因子为 3,将日志流同时发送到多个 Ingester 以保证高可用。
告警路由关联点: Distributor 的
distributor.ring.replication-factor 参数控制副本数。如果副本数过高,Ingester 内存压力增大,可能导致告警查询时 Ingester 响应变慢。建议保持默认值 3,仅在极端高可用场景下调整为 5。
2.4 Ingester:读写交汇的内存枢纽
Ingester 是 Loki 中唯一同时参与读写路径的组件。它维护着最近写入的日志数据在内存中,并定期将数据压缩、索引后刷入对象存储。
2.4.1 写入阶段
- 接收 Distributor 推送的日志流,追加到内存中的 chunk(数据块)。
- 每个 chunk 默认最大 1.5MB 或 30 分钟,任一条件满足即触发刷盘。
- 刷盘后,chunk 变为只读,Ingester 释放内存。
2.4.2 读取阶段
- Querier 发起查询时,Ingester 返回内存中尚未刷盘的实时数据。
- 对于已刷盘的数据,Querier 直接从对象存储读取,Ingester 不再参与。
性能陷阱: 如果告警规则的查询时间范围覆盖了 Ingester 内存中的大量未刷盘数据(例如最近 5 分钟的实时告警),Querier 必须等待所有 Ingester 返回结果。当 Ingester 数量超过 50 个时,建议启用
query-frontend 的 querier.ingester-query-probing 来减少等待超时。
2.5 Querier:告警规则的执行引擎
Querier 是告警规则的实际执行者。当 ruler 组件触发告警评估时,它会向 Querier 发送 LogQL 查询请求。Querier 的工作流程如下:
- 并行查询:将查询拆分为多个子查询,同时发送到所有 Ingester 和对象存储。
- 结果合并:等待所有子查询返回,按时间戳排序、去重、合并。
- 返回结果:将最终结果返回给 Ruler 进行告警规则匹配。
2.5.1 关键性能参数
| 参数 | 默认值 | 告警路由调优建议 |
|---|---|---|
querier.max-concurrent |
10 | 告警规则较多时(>50 条),建议提升至 20-30,避免排队 |
querier.ingester-query-probing |
false | Ingester 数量 >30 时开启,减少无效等待 |
querier.query-parallelism |
14 | 告警查询涉及多标签组合时,适当降低至 8-10 防止 Ingester 过载 |
querier.split-queries-by-interval |
1h | 告警查询时间范围 >1h 时自动拆分,建议保持默认 |
2.6 组件交互时序:一次告警评估的完整路径
为了更直观地理解组件间的协作,下图展示了一次告警规则评估的完整时序:
2.7 组件交互对告警路由的启示
核心结论:
- Ingester 是延迟瓶颈:告警规则查询最近数据时,必须等待所有 Ingester 返回。如果 Ingester 内存中积压了大量未刷盘数据,查询延迟会显著增加。
- Querier 的并行度需要谨慎设置:
querier.max-concurrent和querier.query-parallelism决定了 Querier 对 Ingester 的并发请求数。设置过高可能导致 Ingester CPU 飙升,设置过低则告警评估排队。 - Distributor 的哈希环影响数据局部性:告警规则如果按特定标签(如
namespace)查询,数据分布越均匀,Querier 的合并开销越小。