Grafana Loki 文件系统对象存储(Filesystem Object Store)完整指南:配置、原理与生产限制
【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki
文件系统对象存储是 Grafana Loki 中开箱即用、无需任何外部依赖的存储后端:它把 chunk、索引、规则等对象以普通文件的形式写入磁盘目录,是本地开发、功能验证、概念验证(POC)与低流量场景下最便捷的选择。读完本文,你将掌握common.storage.filesystem与storage_config两种配置方式、单租户下fake目录的由来、基于thanos-io/objstore的新一代可选文件系统客户端,以及文件数量膨胀、持久性、高可用与保留删除等生产级限制的应对方案。
什么是文件系统对象存储
Loki 的存储架构将日志数据抽象为"对象",并以统一的ObjectClient接口进行读写。文件系统对象存储就是这个接口在本地磁盘上的实现:它把每一个对象(如一个 chunk、一份规则文件)写入你指定的目录,文件即对象、目录即"桶"。
对象存储客户端实现中,FSObjectClient持有两个核心字段:
cfg:FSConfig,其Directory字段就是对象根目录;pathSeparator:当前操作系统的路径分隔符。
客户端初始化时会执行filepath.Clean(cfg.Directory)做路径清理,并通过util.EnsureDirectory确保目录存在——因此即使目录尚不存在,Loki 首次启动也会自动创建它。这一点在NewFSObjectClient中可以直接看到(fs_object_client.go)。
从代码看,该实现提供了一组与云对象存储语义对齐的操作:PutObject写入文件(os.O_WRONLY|os.O_CREATE|os.O_TRUNC,权限 0644)并在写入后调用fl.Sync()落盘;GetObject/GetObjectRange读取文件或文件区间;List通过filepath.Walk递归枚举目录;DeleteObject在删除后还会逐级向上清理空目录(fs_object_client.go)。换句话说,这个"对象存储"本质上就是把对象存储 API 翻译成了一组文件系统调用。
两种配置方式
Loki 支持两种配置文件系统对象存储的途径,二者等价,实际配置时二选一即可。
方式一:推荐 ——common.storage.filesystem块
官方推荐在common.storage.filesystem中配置,这也是文档给出的标准写法:
common: storage: filesystem: chunks_directory: /tmp/loki/chunks rules_directory: /tmp/loki/rules从 pkg/loki/common/common.go 可以看到FilesystemConfig的定义:
chunks_directory:chunk 存储目录;rules_directory:ruler 规则文件存储目录。
它们对应的命令行 Flag 分别是common.storage.filesystem.chunk-directory与common.storage.filesystem.rules-directory(common.go)。common块的意义在于把多处组件共享的存储配置集中到一处,避免在storage_config、ruler.storage等位置重复书写。
方式二:storage_config直接指定
也可以直接在storage_config下配置 chunk 目录,此时只有一个directory字段:
storage_config: filesystem: directory: /tmp/loki/这条配置对应的是 pkg/storage/chunk/client/local/fs_object_client.go 中的FSConfig.Directory,Flag 为local.chunk-directory。注意这种写法只覆盖 chunk 对象的存储位置,规则存储仍需在 ruler 相关配置中单独指定。
单租户模式与fake目录
文件系统存储按租户(tenant)隔离:Loki 会为每一个租户创建一个独立文件夹,该租户的全部 chunk 都存放在自己的文件夹内。
当 Loki 以单租户模式运行时,所有 chunk 会被放入名为fake的目录。fake是 Loki 在单租户模式下合成(synthesize)出的租户名称——Loki 内部始终以租户维度组织数据,即使你没有显式配置多租户,它也会用fake这个占位租户 ID 来归类所有数据。仓库代码中大量测试与构建路径都以"fake"作为租户标识(例如 pkg/bloombuild/builder/builder.go 中通过user.InjectOrgID(..., "fake")注入租户上下文),这正印证了fake作为单租户合成租户名的约定。
多租户模式下,每个租户目录名即租户 ID,chunk 文件按租户隔离存放,互不干扰。关于多租户机制的更多细节,可参考文档 multi-tenancy(仓库内对应主题见 docs/sources/operations)。
基于 thanos-io/objstore 的可选客户端(opt-in)
除上述默认实现外,Loki 还提供一个基于thanos-io/objstore的可选文件系统客户端,采用显式开启(opt-in)方式:
storage_config: use_thanos_objstore: true object_store: filesystem: dir: /tmp/loki开启后,需要在storage_config.object_store.filesystem.dir(等价地,common.storage.object_store.filesystem.dir)中指定目录。pkg/storage/bucket/filesystem/config.go 中该客户端只有一个配置字段Directory(YAML 键为dir),对应的 Flag 是filesystem.dir;filesystem也被登记在 pkg/storage/bucket/client.go 的SupportedBackends列表中。
这一迁移路径的底层逻辑在 pkg/storage/factory.go 中可以看到:
UseThanosObjstore对应的 YAML 键为use_thanos_objstore,当前仓库的默认值已是true;- 当它为
true时,NewObjectClient 会走bucket.NewObjectClient(...)的 thanos 客户端路径;若此时object_store块完全空白(用户没意识到默认值已变化),会直接报错提示config must be specified in the object_store section; - 当它为
false时,会回退到internalNewObjectClient的旧版(legacy)客户端路径,并打印警告,提示旧客户端已弃用、不再推荐使用。
因此,如果你正在使用旧版storage_config.filesystem配置,应关注这一迁移方向:未来版本中基于 thanos-io/objstore 的客户端将成为配置对象存储客户端的默认方式。仓库内还有对应的配置示例与迁移指南,可在 docs/sources/configure 与 docs/sources/setup/migrate 目录中查找"Thanos 存储配置示例"与"存储客户端迁移"相关内容。
优点(Pros)
文件系统对象存储的优点非常直接:
- 极其简单:运行 Loki 不需要任何额外软件(无需部署 S3、GCS 之类的服务端),开箱即用;
- 兼容 TSDB:可与 TSDB 索引存储配合工作,而 TSDB 正是官方推荐的索引存储方案;
- 适合轻量场景:非常适合低流量应用、概念验证(Proof of Concept)以及"玩一玩" Loki 的本地实验环境。
缺点(Cons)与生产限制
Grafana Labs 官方不支持将文件系统对象存储用于生产环境,即使购买了支持合同的客户也不在支持范围内。因此它更适合开发与验证,生产环境请优先考虑 S3、GCS、Azure 等托管对象存储。
扩展性(Scaling):单目录文件数存在上限
当单个目录中的 chunk 文件数量增长到一定规模后,文件系统本身会成为瓶颈。项目 issue #1502 记录了一个真实案例:一位用户在该文件存储中积累了约550 万个 chunk 文件后遇到了奇怪的文件系统错误,该 issue 同时给出了可行的规避方法。
由于Loki 为每个流(stream)写一个 chunk,所以控制活跃流数量是减少 chunk 文件数的根本手段。同时可以调节以下 ingester 参数来减少 chunk 刷盘频率(注意:降低刷盘频率会以更高的内存占用为代价):
| 参数 | 默认值 | 作用 |
|---|---|---|
chunk_target_size | 1.5 MB(1572864 字节) | 每个 chunk 的目标压缩后大小。非精确值,chunk 可能因其他原因(如空闲超时)提前刷盘;设为 0 时按固定 10 个 block 创建 chunk |
max_chunk_age | 2h | chunk 在内存中驻留的最长时间,超过即刷盘。可考虑调大默认值 |
chunk_idle_period | 30m | 空闲(无新数据写入)chunk 在内存中驻留多长时间后刷盘。可考虑调大到与max_chunk_age一致 |
这些参数在源码中的对应关系可以逐一验证:
chunk_target_size对应 ingester 的-ingester.chunk-target-sizeFlag,默认1572864字节即 1.5 MB,注释明确说明"这是目标压缩后大小,并非精确值"(pkg/ingester/ingester.go);max_chunk_age对应-ingester.max-chunk-age,默认2*time.Hour,注释为"timeseries chunk 在内存中的最大时长,超时即刷盘并新建 chunk"(pkg/ingester/ingester.go),刷盘判断逻辑可见 pkg/ingester/flush.go 中to.Sub(from) > i.cfg.MaxChunkAge的比较;chunk_idle_period对应-ingester.chunks-idle-period,默认30*time.Minute,注释说明"没有任何更新的 chunk 在内存中驻留超过该时长后刷盘,即使它是半满的"(pkg/ingester/ingester.go)。
即便如此,文件系统存储仍然可以承载 TB 级别的日志数据,但务必牢记:单个目录中文件系统能高效管理的文件数是有限度的,规划容量时要把这一点考虑进去。
持久性(Durability)
对象数据的持久性完全取决于底层文件系统本身。相比之下,S3、GCS 等托管对象存储在后端做了大量数据冗余与校验工作,能提供远高于本地磁盘的持久性保障。如果磁盘损坏且没有备份,文件系统存储中的数据将随之丢失。
高可用(High Availability)
文件系统存储不支持以集群方式运行 Loki,除非你以某种方式共享文件系统(例如通过 NFS 挂载)。但共享文件系统通常会给 Loki 带来糟糕的体验——这一点对几乎所有依赖共享文件的应用都成立。原因显而易见:多个 Loki 实例并发写同一批文件,会产生锁竞争、缓存一致性、原子性等一系列问题;从源码看,FSObjectClient的写入操作是直接的os.OpenFile+io.Copy,并没有任何跨节点的分布式锁或协调机制(fs_object_client.go)。
保留与删除(Retention and deletion)
使用文件系统 chunk 存储时,Loki 不会根据磁盘用量或剩余空间删除 chunk。它只依据你的保留(retention)配置删除数据,因此磁盘写满(disk-full)的场景必须由你在 Loki 之外自行处理,例如配合定时清理脚本或磁盘监控告警。
保留删除由 compactor 组件执行。启用保留功能需要同时设置两项配置:
compactor.retention_enabled: true:开启基于保留策略的删除;compactor.delete_request_store: filesystem:将删除请求存储在该对象存储中,这样 compactor 才能读取并执行删除请求。
compactor: retention_enabled: true delete_request_store: filesystem底层实现上,文件系统客户端还提供了DeleteChunksBefore(ctx, ts)方法,它会遍历整个目录,删除所有修改时间早于指定时间戳的文件,并在日志中输出file has exceeded the retention period, removing it(fs_object_client.go)——这正是 retention 删除在文件系统后端上的落地逻辑。
关于保留策略的完整配置与删除请求的更多说明,可进一步阅读 Retention 文档 与 日志删除文档。
快速上手示例
把以上知识串起来,一个典型的本地开发配置(单租户 + TSDB 索引 + 文件系统对象存储)大致如下:
auth_enabled: false common: path_prefix: /tmp/loki storage: filesystem: chunks_directory: /tmp/loki/chunks rules_directory: /tmp/loki/rules replication_factor: 1 schema_config: configs: - from: 2024-01-01 store: tsdb object_store: filesystem schema: v13 compactor: retention_enabled: true delete_request_store: filesystem配置完成后,以单二进制模式启动 Loki:
./loki -config.file=/path/to/config.yaml启动后检查/tmp/loki/chunks目录:单租户模式下会看到名为fake的文件夹,其中存放着该"租户"的全部 chunk 文件。仓库自带的本地配置示例 cmd/loki/loki-local-config.yaml 与 examples/getting-started/loki-config.yaml 可作进一步参考。
总结与选型建议
文件系统对象存储是了解 Loki 存储架构、快速跑通端到端链路的最佳起点:它零依赖、易配置、与 TSDB 索引存储完全兼容,通过fake租户目录机制让你直观看到"对象即文件"的存储模型。但它本质上没有提供任何超出本地文件系统的保障——文件数扩展受限、持久性依赖磁盘、无法安全集群化、磁盘清理需自行负责,因此 Grafana Labs 明确不对其提供生产支持。
选型建议:
- 本地开发、CI 测试、概念验证、低流量个人场景 → 直接使用文件系统存储;
- 生产环境、需要高可用与强持久性 → 改用 S3、GCS、Azure 等托管对象存储;
- 若已开始规划对象存储客户端的未来迁移,可关注
use_thanos_objstore: true+object_store.filesystem.dir的 thanos 客户端配置路径,尽早与后续版本的默认行为对齐。
【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考