2. Loki存储引擎演进史:从Boltdb-shipper到TSDB索引的架构变化

Loki 的存储引擎经历了两次重大架构变革,核心目标是解决大规模日志场景下的索引膨胀、查询性能衰减和运维复杂度问题。本章梳理从 Boltdb-shipper 到 TSDB 索引的演进路径,帮助理解每次变更背后的设计权衡。

2.1 第一阶段:Boltdb-shipper(单机索引 + 共享存储)

在 Loki 2.0 之前,每个 Ingester 实例使用本地 BoltDB 存储索引,并通过 Consul/Etcd 注册。这种模式存在明显的单点瓶颈和扩展性限制。

核心痛点:索引与 Ingester 强绑定,Ingester 重启或扩缩容时需重新构建索引;查询时需遍历所有 Ingester 的本地索引,跨节点查询延迟高。

Loki 2.0 引入 Boltdb-shipper 模式,将索引从本地磁盘迁移到对象存储(如 S3、GCS),实现索引的共享与持久化。架构变化如下:

  • 索引写入:Ingester 将 BoltDB 索引文件定期上传(shipping)到对象存储。
  • 索引读取:Querier 从对象存储下载索引文件到本地缓存,支持多副本并行查询。
  • 元数据管理:引入 table-manager 组件,负责索引分片(table)的创建、合并和过期删除。
Boltdb-shipper 架构示意图 Ingester 本地 BoltDB 索引 Ingester 本地 BoltDB 索引 Ingester 本地 BoltDB 索引 对象存储 索引文件 (BoltDB) 分片 0 分片 1 分片 2 ... Querier 本地缓存索引 Querier 本地缓存索引 Querier 本地缓存索引 table-manager 说明:Ingester 定期将本地 BoltDB 索引上传至对象存储;Querier 按需下载索引分片到本地缓存;table-manager 负责索引生命周期管理。
迁移要点:从单机 BoltDB 迁移到 Boltdb-shipper 时,需确保所有 Ingester 和 Querier 都能访问同一对象存储桶,并配置正确的 storage_config 中的 boltdb_shipper 参数。

2.2 第二阶段:TSDB 索引(高性能列式索引)

Boltdb-shipper 虽然解耦了索引与 Ingester,但 BoltDB 本身的 B+ 树结构在大规模标签组合场景下,索引文件体积增长迅速,查询时需下载整个分片文件,导致 I/O 和网络开销激增。

Loki 2.8+ 引入 TSDB 索引,借鉴 Prometheus TSDB 的列式存储思想,重新设计索引格式。核心变化包括:

维度 Boltdb-shipper TSDB 索引
存储格式 B+ 树(BoltDB) 列式 + 倒排索引(TSDB)
索引文件 单个 .db 文件,按分片组织 多段文件(.tsdb),按时间窗口组织
查询方式 下载整个分片到本地,全量扫描 按需读取索引段,支持谓词下推
内存占用 高(需缓存完整索引) 低(仅缓存元数据 + 热段)
写入放大 中等(BoltDB 合并写) 低(追加写 + 后台合并)
扩展性 依赖 table-manager 分片 原生支持分片 + 并行读取
版本漂移风险:TSDB 索引与 Boltdb-shipper 的索引文件格式不兼容。升级时需通过 loki-index-gateway 或离线转换工具完成索引格式迁移,否则旧数据无法被新版本查询。

2.3 架构对比:Boltdb-shipper vs TSDB 索引

从组件职责和查询链路看,两种模式的核心差异在于索引的组织粒度和读取策略:

  • Boltdb-shipper:索引按“表(table)”分片,每个分片是一个完整的 BoltDB 文件。查询时 Querier 需下载整个分片文件,即使只查询其中一小部分标签。
  • TSDB 索引:索引按“时间窗口(block)”分段,每个段内包含独立的倒排索引和符号表。查询时 Querier 只读取与查询时间范围重叠的段,且支持按标签过滤提前跳过无关段。
TSDB 索引架构示意图 对象存储 段 0 (12:00-12:30) 段 1 (12:30-13:00) 段 2 (13:00-13:30) 段 3 (13:30-14:00) 查询时间范围 12:10 - 12:50 仅读取段 0 和段 1 倒排索引 标签 → 符号表 谓词下推 说明:TSDB 索引按时间窗口分段存储,查询时只读取与时间范围重叠的段,并通过倒排索引实现标签级快速过滤,大幅减少 I/O 和网络传输。

2.4 演进收益与迁移挑战

TSDB 索引在查询性能、资源消耗和运维效率上均有显著提升,但迁移过程需要关注以下关键点:

收益项 具体表现 迁移挑战
查询延迟 P99 查询延迟降低 40%-60% 需确保所有 Querier 升级到支持 TSDB 的版本
存储成本 索引文件体积减少 50%-70% 旧 BoltDB 索引文件需手动或自动转换
内存占用 Querier 内存使用降低 30%-50% 需调整缓存策略(如 tsdb-max-query-bytes-read)
运维复杂度 不再依赖 table-manager 分片管理 需关闭 table-manager 并清理旧分片元数据
关键配置示例(启用 TSDB 索引):
# config.yaml
schema_config:
  configs:
    - from: "2024-01-01"
      store: tsdb
      object_store: s3
      schema: v13
      index:
        prefix: loki_index_
        period: 24h

storage_config:
  tsdb_shipper:
    active_index_directory: /data/loki/tsdb-index
    cache_location: /data/loki/tsdb-cache
    cache_ttl: 24h

2.5 版本兼容性矩阵

不同 Loki 版本对索引格式的支持情况如下,升级前务必核对:

Loki 版本 Boltdb-shipper TSDB 索引 备注
2.0 - 2.7 ✅ 默认 ❌ 不支持 仅支持 Boltdb-shipper
2.8 - 2.9 ✅ 兼容 ✅ 实验性 需通过 --experimental.tsdb-index 启用
3.0+ ⚠️ 弃用 ✅ 默认 Boltdb-shipper 不再维护,建议立即迁移
重要提醒:如果当前版本低于 2.8,请先升级到 2.8 或 2.9 的稳定版,确保 Boltdb-shipper 索引数据完整,再规划 TSDB 索引迁移。跨大版本升级(如 2.0 → 3.0)可能导致索引格式不兼容,数据不可读。