2. Loki 核心架构:组件、读写路径与职责

Loki 的架构设计深受 Prometheus 启发,采用 微服务 + 水平扩展 模式,将日志的接收、存储、查询与前端路由解耦为独立组件。理解这一架构是后续进行压测建模、容量预测与变更门禁设计的基础。

2.1 整体架构总览

Loki 的核心组件包括 Distributor、Ingester、Querier 与 Query Frontend。它们通过共享的 对象存储(如 S3、GCS、MinIO)与 一致性哈希环(Consul / etcd)协同工作。下图展示了各组件的逻辑关系与数据流向:

Loki 核心架构组件关系图 Loki 核心架构组件关系 日志客户端 Distributor Ingester 组 (写入 + 内存缓存) 对象存储 Querier Query Frontend 数据流方向 写入:客户端 → Distributor → Ingester → 对象存储 查询:Frontend → Querier → 对象存储 + Ingester

2.2 组件职责与关键特性

每个组件承担明确的职责,并可通过增加副本数实现水平扩展。下表总结了各组件的核心功能与压测关注点:

组件 核心职责 关键特性 压测关注点
Distributor 接收日志写入请求,验证并分发 无状态、一致性哈希路由、速率限制 QPS、请求大小、gRPC 连接数
Ingester 缓存日志到内存,批量刷写到对象存储 有状态、chunk 管理、WAL 持久化 内存占用、chunk 刷写频率、磁盘 IO
Querier 执行 LogQL 查询,合并结果 无状态、支持并行查询、缓存 查询并发、索引扫描、对象存储延迟
Query Frontend 查询路由、分片、缓存、限流 无状态、查询分片、结果缓存 缓存命中率、分片策略、超时控制
压测提示: Distributor 和 Querier 为无状态组件,适合作为水平扩展的压测入口;Ingester 为有状态组件,其内存与刷写策略直接影响写入吞吐与数据持久性,是容量预测的核心建模对象。

2.3 写入路径详解

一条日志从客户端到达对象存储,经历以下关键步骤:

  1. 客户端推送:Promtail / Fluent Bit 等客户端将日志流推送到 Distributor 的 HTTP/gRPC 端点。
  2. 验证与哈希:Distributor 校验日志标签(Label)合法性,并根据标签计算一致性哈希,确定目标 Ingester 副本。
  3. 转发至 Ingester:Distributor 将日志流转发给对应的 Ingester 实例。Ingester 将日志追加到内存中的 chunk(数据块)中。
  4. 确认响应:Ingester 写入成功后返回 ACK,Distributor 再向客户端返回 204 状态码。
  5. 异步刷写:Ingester 根据配置的 chunk_idle_period(默认 1 分钟)或 chunk_target_size(默认 1.5 MB)将内存 chunk 压缩并上传到对象存储。
写入路径关键指标:
  • loki_distributor_bytes_received_total — 接收字节数
  • loki_ingester_chunks_flushed_total — chunk 刷写总数
  • loki_ingester_memory_chunks — 当前内存中 chunk 数量

2.4 读取路径详解

查询请求的处理路径与写入路径解耦,支持 即时查询 与 范围查询:

  1. 查询请求到达 Query Frontend:Frontend 根据查询时间范围进行 分片(split by time)和 并行化。
  2. 分发至 Querier:Frontend 将子查询分发给多个 Querier 实例并行执行。
  3. 数据源选择:Querier 同时查询 Ingester 内存中的热数据 和 对象存储中的冷数据,合并结果。
  4. 结果聚合:Querier 将子查询结果返回给 Frontend,Frontend 进行最终聚合与排序,返回给客户端。
Loki 读写路径对比 写入路径(蓝色)与读取路径(橙色) 客户端 Distributor Ingester 对象存储 对象存储 Querier Query Frontend 客户端 路径对比要点 写入路径:客户端 → Distributor → Ingester → 对象存储(异步刷写) 读取路径:客户端 → Query Frontend → Querier → 对象存储 + Ingester(热数据)

2.5 组件协作与一致性保障

Loki 通过 一致性哈希环 确保写入请求被正确路由到持有对应日志流的 Ingester。当 Ingester 实例发生扩缩容或故障时,哈希环自动更新,Distributor 重新计算路由。Querier 在查询时通过 Read 路径 同时访问 Ingester 的内存数据与对象存储的持久化数据,保证数据完整性。

容量预测注意: Ingester 的内存消耗与 chunk 数量、日志流基数(active streams)强相关。在压测沙盘中,应重点监控 loki_ingester_memory_streams 与 loki_ingester_chunk_utilization 指标,以预测内存瓶颈点。

2.6 组件通信协议

组件间通信采用 gRPC 与 HTTP 两种协议,具体使用场景如下:

通信方向 协议 数据格式 说明
客户端 → Distributor HTTP / gRPC Protobuf / JSON 日志推送接口
Distributor → Ingester gRPC Protobuf 内部转发,低延迟
Ingester → 对象存储 HTTP (S3/GCS API) 压缩 chunk 异步刷写
Querier → Ingester gRPC Protobuf 查询热数据
Querier → 对象存储 HTTP 压缩 chunk 查询冷数据
Query Frontend → Querier gRPC Protobuf 子查询分发

理解这些通信协议有助于在压测沙盘中模拟真实流量特征,例如 gRPC 连接复用、HTTP 连接池大小等参数调优。