OpenObserve vs Loki:日志查询、存储和维护成本
用实际查询解释标签、结构化字段和错误处理的差异,再结合留存、查询并发、既有技术栈与完整成本,判断何时选 Loki、OpenObserve 或观测云。
已经围绕 Grafana 做监控、值班时总能确定服务和命名空间的团队,Loki 很自然。沿着这些标签缩小范围,再查最近一段时间的错误,不需要仅为换一个日志后端重新安排使用习惯。
OpenObserve 更吸引经常分析结构化业务日志的团队:按订单号跨服务查,再临时加几个字段做 SQL 聚合。数据量可以同样是一天 1 TiB,但这两类查询对索引、扫描和使用者的要求并不相同。
所以我会先保留熟悉的那套技术栈,再看有没有持续解决不了的查询。偶尔一次历史回查很慢,不一定值得迁平台;每天都在为了常用查询绕路,就值得认真比较。下面从实际的小样本查询讲起。
作者:观测云。资料与样本核对于 2026-10-09。下文实际运行 Loki 3.7.8、OpenObserve OSS 1.0.4 的小样本查询;没有进行生产负载或双方性能排名。
按 trace ID 查日志
假设业务给来一个 trace_id。Loki 可以先用 {service="checkout",env="prod"} 缩小日志流范围,再过滤这个 ID。问题是,值放在哪里?
把每个 trace ID 都做成流标签,会让大量不同的请求拆出大量流。Loki 官方建议把这类高基数字段放在结构化元数据中。它们仍可过滤,但不会像流标签那样参与流索引。结构化元数据需要相应的存储配置:本文使用 TSDB、schema v13。不能只改采集器字段就假定后端已经具备同样行为。Loki 标签、结构化元数据。
本次把 service、env 放在流标签,把 trace_id 放在结构化元数据,下面的查询返回了一条目标日志,不需要再从正文解析 JSON:
{service="checkout",env="prod"}
| trace_id="00000000000000000000000000000001"
OpenObserve 侧把 trace_id 保存为字段,同一条记录可以通过 SQL 找到:
SELECT event_id FROM query_samples
WHERE trace_id = '00000000000000000000000000000001'
在这个小样本里,两条查询都找到了目标记录。Loki 前面的服务与环境条件很重要:值班同事本来就知道服务,标签筛选很方便;只有一个订单号、连来源都不知道,搜索范围就会扩大。后一类工作如果经常发生,宽范围查询的耗时和资源才是选型重点。
OpenObserve 的字段与全文索引给 SQL 检索提供了加速路径,但不是任意表达式都会命中索引。谓词、时间范围和数据分布都会影响实际扫描量。SQL 使用习惯可以复用,查询资源仍需要按日常负载规划。OpenObserve Tantivy 索引。
字段解析和查询错误
样本里有 upstream timeout、upstream timed out、connection timeout 三种文本。Loki 的 |= "timeout" 返回两条;OpenObserve 的 message LIKE '%timeout%' 也返回两条。timed out 没有被命中。这是此次指定的子串匹配结果,不是两个产品的全文分词能力比较。
延伸阅读日志采集器选型:Vector、Fluent Bit 与 OTel Collector→
如果原先的告警依靠分词搜索,迁移时把它改成子串匹配,界面仍有结果,告警覆盖却可能变了。选型需要保留的,是业务想捕获哪类错误,而不只是搜索框里原来的几个字。
再把任务改成“统计耗时超过 900 毫秒的请求”,差异就更具体了。七条 JSON 样本的耗时包含字符串 "1200"、"1600"、"n/a" 和缺字段;Loki 额外接收了一行损坏的 JSON,用来检查解析错误路径。
以下 LogQL 在本次测试中返回 HTTP 400,因为数值过滤过程中出现错误:
sum(count_over_time(
{service="checkout",env="prod"}
| json | duration_ms > 900 [1h]
))
把 | __error__="" 放在数值过滤之后,得到预期的两条。这个位置有意义:只在 json 后面过滤一次,不能清除后续数值转换产生的错误。被排除的数据还需要另行统计,否则“慢请求减少了”可能只是坏字段变多了。LogQL 管道与错误。
OpenObserve 中直接 CAST(duration_ms AS DOUBLE),本次返回 HTTP 200,但 hits 为空、is_partial=true,并带有转换 n/a 失败的 function_error。换成下面的表达式,才得到两个预期事件,且 is_partial=false:
SELECT event_id FROM query_samples
WHERE TRY_CAST(duration_ms AS DOUBLE) > 900
ORDER BY event_id
TRY_CAST 让转换失败变为 NULL,解决的是查询能继续执行;它不会修复日志。缺字段和非法值都不会进入这个阈值统计,仍要保留相应的数据质量计数。
字段清洗放在哪里,也会影响后面的维护。格式稳定,在写入时统一数值和状态,常用查询就简单;来源多、格式变化频繁,保留原文再临时解析更灵活,却把解析资源和错误处理留给了查询端。两边都能加工数据,差别最后落在团队愿意维护哪一层。
查询并发与缓存
小样本只能确认语义。它无法回答一天 1 TiB、留存 30 天、十个人同时排障时,哪个方案更合适。
近期按服务找错误、跨一天查请求 ID、跨七天做接口聚合,是三种不同的负载。前两种主要服务日常排障,第三种可能扫描更多历史对象。冷查询和重复查询也不同:反复查询已经命中的缓存,只能说明热数据路径的表现。
真实使用还会叠加持续写入与后台查询。工程师等的十秒,可能花在排队,也可能花在对象读取、解压和聚合。前者需要处理资源竞争,后者可能需要调整索引、缓存或数据范围。低频历史分析允许慢一些,值班时的交互查询则通常更敏感,两类工作没有必要一律按最贵的响应目标配资源。
对象存储单价低,只解释了保存数据的一部分费用。为了让偶尔一次的宽查询快几秒而长期增加计算和缓存,未必划算;这类查询成为每天的主要工作后,同样的投入又可能值得。Loki 和 OpenObserve 的成本都要按这种使用频率理解。
保留期与存储费用
先设一个与产品无关的容量模型:每天 1 TiB 原始日志,80% 的普通日志留三天,20% 的重要日志留三十天。达到稳定状态后,原始留存量为:
延伸阅读OpenObserve vs 观测云:自建和托管的日志成本→
1 TiB × (80% × 3 + 20% × 30) = 8.4 TiB
全部留三十天则是 30 TiB。这两个数都还没应用压缩,也没包含索引、缓存、WAL 和副本;更不能直接乘同一个磁盘单价得到平台成本。它们说明的是:在比较两款存储之前,先区分数据价值,可能已经改变容量级别。
保留期修改以后,费用还受删除进度影响。旧对象没有实际删除,存储账单就不会马上降到新的稳态;前端只显示最近三天,也不会因此清掉三天前的数据。
已有 Grafana、告警规则、标签规范和运行经验的团队,需要把迁走这些资产的成本计入 OpenObserve 方案。反过来,主要由 SQL 使用者分析结构化业务日志的团队,也要计算维护 LogQL、标签策略和解析管道的额外投入。熟悉的技术栈往往有成本优势,但这个优势来自已经拥有的能力,需要具体列出来。
什么情况选 Loki,什么情况选 OpenObserve
Grafana 使用深入、标签规范已经稳定,日常以近期服务排障为主,继续使用 Loki 很合理。现有看板、规则和人员经验都能留下。
结构化字段分析多,SQL 已经是团队常用工具,又愿意维护查询和存储后端,OpenObserve 更合适。收益来自分析方式与现有技能匹配,不是因为对象存储天然让任何查询都更便宜。
需求变化后,选择也会变。原来主要按服务查日志,后来每天都要跨服务做业务分析,就值得重新配置或评估后端。关键是这些工作出现得够不够频繁。
使用观测云的成本差别
两套自建方案都需要把字段加工、留存、查询和告警配置起来,还要有人负责后端升级与容量。观测云把 Pipeline、多索引和日志关联做成现成功能;使用由供应商运营后端的 SaaS 服务时,可以减少接收、存储与查询集群的运行工作。Pipeline、日志索引、日志关联。
业务仍然需要提供正确的时间、服务和 trace ID,相关链路也必须实际采集并保留。SaaS 模式可减少后端建设和维护,私有部署仍需分清运维职责,自己的数据规范也仍然要做。
如果已有成熟 Loki,新增维护投入很少,继续用可能更经济;如果几位业务运维还要兼职搭日志平台,观测云的服务费就应与机器、建设时间和持续值守一起比较。直接可用的查询与告警,能让团队更早开始处理业务问题。
查看样本、版本和查询返回。测试均为本机单节点;Loki 因本机磁盘占用触发 WAL 保护,后续仅在关闭 WAL 的临时实例验证查询语义,因此没有任何持久性或吞吐结论。七条正常 JSON 在双方共用,损坏 JSON 仅用于 Loki 的额外错误测试。

