1. 为什么我又把可观测性栈折腾了一遍
做后端和运维的这些年,可观测性这块我踩的坑实在太多了。日志、指标、链路三件套,几乎每个项目都绕不开。早些年用 ELK 那一套,Elasticsearch 加 Kibana,日志检索确实爽,但资源占用也真的吓人。一台 8C16G 的机器,光 ES 的 JVM 堆就能吃掉一半内存,稍微上点量磁盘 IO 就开始报警。后来指标监控换成 Prometheus 加 Grafana,轻量了不少,但 Prometheus 的本地存储又是个坑,数据保留时间一长,查询就开始变慢,远程存储方案配起来又是一堆组件。
我一直在想,有没有一个东西能把日志和指标揉在一起,资源占用还低,部署别那么折腾。直到我认真试了 OpenObserve,一个用 Rust 写的云原生可观测性平台,才觉得这事儿有点意思了。它主打的就是一个二进制文件搞定日志、指标、链路,存储成本号称比 Elasticsearch 低一个数量级,而且原生支持对象存储。这篇文章我就把自己从零搭建、接入数据、调优排错的完整过程梳理一遍,给同样被 ES 和 Prometheus 折腾过的朋友一个参考。不管你是刚接触可观测性的新手,还是已经维护过几套监控栈的老手,应该都能从里面找到点能直接抄作业的东西。
2. OpenObserve 到底是个什么东西
2.1 核心定位与解决的问题
OpenObserve 的定位很明确,就是一个云原生可观测性平台,把日志、指标、链路追踪统一到一个系统里。它用 Rust 从头写的,没有 JVM 那层包袱,编译出来就是一个静态二进制文件,启动速度快,内存占用低。我第一次跑起来的时候特意看了下,空载状态下内存也就几十兆,跟 Elasticsearch 动辄几个 G 的堆内存完全不是一个量级。
它解决的问题其实很具体。传统方案里,日志用 ELK,指标用 Prometheus,链路用 Jaeger 或者 SkyWalking,三套系统各自独立,数据没法关联,运维成本也高。OpenObserve 想做的就是把这些数据统一存储、统一查询,而且底层直接对接对象存储,比如 S3、MinIO 这些,存储成本能压得很低。官方给的数据是,相比 Elasticsearch,存储成本能降低大约 140 倍,这个数字我一开始也不太信,但实际用下来,压缩率确实很夸张。
2.2 技术栈选型背后的逻辑
Rust 这个选择是 OpenObserve 最核心的差异点。Rust 没有垃圾回收,内存安全靠所有权机制保证,编译出来的程序性能接近 C/C++,但开发效率又比 C++ 高不少。对于可观测性这种需要高吞吐、低延迟的场景,Rust 确实很合适。我实测下来,单节点处理日志写入的时候,CPU 占用很平稳,没有那种 JVM 常见的 GC 停顿。
存储层面,OpenObserve 用的是 Parquet 列式存储格式,配合对象存储。Parquet 的好处是压缩率高,查询的时候只需要读取相关列,IO 效率高。它内部还做了索引优化,对常用的字段会建立索引,查询速度有保障。另外它支持数据保留策略,可以按时间或者按大小自动清理,不用自己写定时任务去删数据。
部署形态上,它支持单节点和集群两种模式。单节点适合中小规模,一个二进制文件加一个配置文件就能跑。集群模式适合大规模场景,需要配合对象存储和 etcd 来做协调。我这次主要用的是单节点加 MinIO 的组合,对大部分团队来说,这个配置已经够用了。
2.3 和 Elasticsearch、Prometheus 的对比
先说和 Elasticsearch 的对比。ES 强在全文检索和生态成熟,但弱在资源占用和运维复杂度。OpenObserve 在日志检索这块,基本功能都有,全文搜索、字段过滤、时间范围查询都没问题,但一些高级的聚合分析功能,比如复杂的嵌套聚合,还是 ES 更丰富。不过对于日常的日志排查,OpenObserve 完全够用,而且它的查询语法更简单,学习成本低。
再说和 Prometheus 的对比。Prometheus 的强项是指标采集和告警,它的 Pull 模型和 PromQL 非常成熟。OpenObserve 也支持指标数据,可以通过 OTLP 协议接收,也可以用 Prometheus 的远程写入接口。但它的告警功能相对简单,复杂的告警规则还是得靠 Prometheus 或者 Grafana 来做。我的做法是,Prometheus 继续负责采集和告警,把 OpenObserve 当作长期存储和统一查询层,这样两边的好处都能拿到。
下面这个表格是我整理的核心对比,方便你快速判断适不适合自己的场景。
| 对比维度 | Elasticsearch | Prometheus | OpenObserve |
|---|---|---|---|
| 开发语言 | Java | Go | Rust |
| 资源占用 | 高,JVM 堆内存大 | 中,本地存储受限 | 低,无 GC |
| 存储成本 | 高 | 中 | 低,对象存储 |
| 日志支持 | 强 | 弱 | 强 |
| 指标支持 | 弱 | 强 | 中 |
| 链路支持 | 需额外组件 | 不支持 | 原生支持 |
| 部署复杂度 | 高 | 中 | 低 |
| 查询语言 | DSL | PromQL | SQL 风格 |
3. 部署实操:从零跑起来一个 OpenObserve
3.1 环境准备与安装方式选择
我这次用的环境是一台 4C8G 的云主机,系统是 Ubuntu 22.04。OpenObserve 的安装方式有好几种,可以直接下载二进制文件,也可以用 Docker 跑,还有 Helm Chart 可以部署到 K8s 集群。我建议新手先用 Docker 跑一遍,熟悉了之后再考虑二进制部署或者集群模式。
Docker 方式最简单,一条命令就能起来。不过要注意,默认配置下数据是存在容器内部的,容器一删数据就没了。所以生产环境一定要挂载数据卷,或者直接配置对象存储。我一开始就是没挂卷,重启了一次容器发现数据全丢了,又重新导了一遍,这个坑你们别踩。
如果你要用二进制方式,去 GitHub 的 release 页面下载对应平台的压缩包,解压之后就是一个可执行文件。启动的时候指定配置文件和數據目录就行。二进制方式的好处是没有容器那层开销,性能会更好一点,而且方便做系统服务。
3.2 Docker 快速启动与参数详解
先说我用的 Docker 命令,然后逐个解释参数。
docker run -d \ --name openobserve \ -p 5080:5080 \ -p 5081:5081 \ -e ZO_ROOT_USER_EMAIL="admin@example.com" \ -e ZO_ROOT_USER_PASSWORD="ComplexPass123!" \ -e ZO_DATA_DIR="/data" \ -v /opt/openobserve/data:/data \ public.ecr.aws/zinclabs/openobserve:latest端口方面,5080 是 HTTP 端口,Web UI 和 API 都走这个。5081 是 gRPC 端口,集群内部通信用。环境变量里,ZO_ROOT_USER_EMAIL和ZO_ROOT_USER_PASSWORD是设置初始管理员账号的,第一次启动必须设置,否则没法登录。ZO_DATA_DIR指定容器内的数据目录,配合-v挂载到宿主机,数据就能持久化了。
启动之后,浏览器打开http://你的IP:5080,用刚才设置的邮箱和密码登录,就能看到 Web 界面了。界面挺简洁的,左边是功能菜单,有日志、指标、链路、告警这些模块。第一次进去会提示你创建组织或者直接开始使用,跟着引导走就行。
注意:密码一定要设置得复杂一点,包含大小写字母、数字和特殊字符,否则启动会报错。我一开始设了个简单的密码,容器直接起不来,看日志才发现是密码强度校验没过。
3.3 配置对象存储(以 MinIO 为例)
单节点模式下,数据默认存在本地磁盘。但如果数据量大了,本地磁盘肯定不够用,这时候就要配对象存储。我用的是 MinIO,自己搭的,也可以用云厂商的 S3 服务。配置方式是在环境变量里加几个参数。
-e ZO_S3_PROVIDER="minio" \ -e ZO_S3_SERVER_URL="http://minio.example.com:9000" \ -e ZO_S3_REGION_NAME="us-east-1" \ -e ZO_S3_ACCESS_KEY="your-access-key" \ -e ZO_S3_SECRET_KEY="your-secret-key" \ -e ZO_S3_BUCKET_NAME="openobserve" \ -e ZO_S3_FORCE_PATH_STYLE="true"这里有几个点要注意。ZO_S3_PROVIDER指定为 minio,如果是 AWS S3 就填 s3。ZO_S3_FORCE_PATH_STYLE对于 MinIO 来说必须设为 true,否则会报路径错误。Bucket 需要提前创建好,OpenObserve 不会自动创建。我一开始没建 bucket,启动后一直报错,查了半天日志才发现这个问题。
配好对象存储之后,数据就会写到 S3 里,本地只保留一些元数据和缓存。这样存储成本能降很多,而且数据可靠性也有保障。MinIO 的部署这里就不展开了,网上教程很多,用 Docker 跑一个单节点也很简单。
4. 数据接入:日志、指标、链路怎么进去
4.1 日志接入的几种方式
日志接入是最常用的场景。OpenObserve 支持多种日志采集方式,最常用的是通过 Fluent Bit、Vector 或者 OpenTelemetry Collector 来转发。我这边用的是 Vector,因为它配置灵活,性能也不错。
Vector 的配置大概是这样,把本地的日志文件采集起来,转发到 OpenObserve 的 HTTP 接口。
[sources.app_logs] type = "file" include = ["/var/log/app/*.log"] [sinks.openobserve] type = "http" inputs = ["app_logs"] uri = "http://openobserve.example.com:5080/api/default/stream/_json" method = "post" auth.strategy = "basic" auth.user = "admin@example.com" auth.password = "ComplexPass123!" encoding.codec = "json"这里default是组织名称,stream是流名称,可以自己定义。OpenObserve 会自动根据 JSON 的字段创建 schema,不需要提前建表。这个设计比 Elasticsearch 的 mapping 要灵活很多,ES 里字段类型冲突是个很头疼的问题,OpenObserve 这边处理得比较宽松。
如果你不想装额外的采集器,也可以直接用 HTTP API 推送日志。比如用 curl 发一条 JSON 过去,就能在界面上看到。这种方式适合做测试,或者应用直接集成。
4.2 指标数据接入 Prometheus 远程写入
指标这块,OpenObserve 支持 Prometheus 的远程写入协议。配置 Prometheus 的时候,在配置文件里加一段 remote_write 就行。
remote_write: - url: "http://openobserve.example.com:5080/api/default/prometheus/api/v1/write" basic_auth: username: "admin@example.com" password: "ComplexPass123!"这样 Prometheus 采集到的指标就会同时写到本地和 OpenObserve。本地保留短期数据用于告警,OpenObserve 存长期数据用于查询和分析。这个架构我觉得挺合理的,两边各司其职。
另外,OpenObserve 也支持 OTLP 协议接收指标。如果你用的是 OpenTelemetry Collector,可以直接把数据导出到 OpenObserve。配置方式和日志类似,改一下 exporter 的 endpoint 就行。
4.3 链路追踪数据接入
链路追踪数据也是通过 OTLP 协议接入的。OpenTelemetry Collector 的配置里,把 exporter 指向 OpenObserve 的 OTLP 接口。
exporters: otlphttp: endpoint: "http://openobserve.example.com:5080/api/default" headers: Authorization: "Basic base64编码的账号密码"链路数据接入之后,在 Web 界面的 Traces 模块就能看到调用链了。可以按服务名、操作名、时间范围来筛选,点进去能看到每个 span 的详细信息,包括耗时、状态码、标签这些。对于排查微服务之间的调用问题,这个功能很实用。
提示:OTLP 接口的认证用的是 Basic Auth,需要把账号密码做 base64 编码。我一开始直接填了明文,一直报 401,后来才反应过来要编码。
5. 查询与可视化:怎么把数据用起来
5.1 SQL 风格的查询语法
OpenObserve 的查询语法是 SQL 风格的,对于熟悉 SQL 的人来说上手很快。比如查最近 15 分钟的 error 日志,可以这样写。
SELECT * FROM "app_logs" WHERE level = 'error' AND _timestamp >= now() - interval '15 minutes' ORDER BY _timestamp DESC LIMIT 100字段名就是 JSON 里的 key,_timestamp是内置的时间字段。支持的操作符也挺全的,等于、不等于、大于小于、LIKE、IN 这些都有。聚合查询也支持,比如按服务名统计错误数量。
SELECT service_name, count(*) as error_count FROM "app_logs" WHERE level = 'error' GROUP BY service_name ORDER BY error_count DESC这个语法比 Elasticsearch 的 DSL 要直观太多了。ES 的 DSL 嵌套一深,写起来就很痛苦,调试也麻烦。OpenObserve 的 SQL 风格查询,基本上会 SQL 就能用,学习成本低很多。
5.2 仪表盘配置与告警规则
Web 界面里可以创建仪表盘,把常用的查询保存成图表。支持折线图、柱状图、饼图、表格这些常见的图表类型。配置的时候选好数据源和查询语句,设置一下时间范围和刷新间隔就行。我一般会把核心服务的错误率、响应时间、请求量这几个指标做成一个仪表盘,方便每天扫一眼。
告警功能相对简单一些,可以基于查询结果设置阈值告警。比如错误日志数量超过 100 条就触发告警。告警渠道支持邮件、Webhook 这些。不过复杂的告警规则,比如多条件组合、告警抑制,还是得靠 Prometheus 的 Alertmanager 来做。我的做法是,简单的日志告警用 OpenObserve,指标告警继续用 Prometheus,两边互补。
5.3 数据保留与成本控制
数据保留策略可以在流的设置里配置。可以按时间保留,比如保留 30 天,也可以按大小保留,比如最多占 100GB。超过保留期的数据会自动清理,不用自己写脚本。
存储成本这块,因为底层用的是对象存储加 Parquet 压缩,实际占用比原始数据小很多。我实测下来,日志数据的压缩比大概在 10:1 到 20:1 之间,具体取决于数据的重复度和字段类型。相比 Elasticsearch 默认的存储方式,确实省了不少。如果你对成本敏感,这个优势还是很明显的。
6. 踩坑记录与常见问题排查
6.1 启动失败与端口冲突
最常见的问题就是端口被占用。5080 和 5081 这两个端口如果被其他服务占了,OpenObserve 就起不来。启动的时候看日志,会提示 bind 失败。解决办法就是改端口,或者把占用的服务停掉。我一开始 5080 被一个测试服务占了,查了半天才发现。
还有一个是数据目录权限问题。如果用二进制方式部署,运行 OpenObserve 的用户需要对数据目录有读写权限。权限不够的话,启动会报错。用 Docker 的话一般不会有这个问题,因为容器内是 root 用户。
6.2 数据写入慢或丢失
数据写入慢,首先要看网络。如果 OpenObserve 和采集器不在同一台机器,网络延迟会影响写入速度。其次是看磁盘 IO,如果本地磁盘写入跟不上,也会导致数据积压。配了对象存储之后,写入会先到本地缓存,再异步上传到 S3,所以本地磁盘的性能还是有影响的。
数据丢失的情况,我遇到过一次是因为采集器的 buffer 设置太小,日志量突增的时候 buffer 满了就丢数据。后来把 Vector 的 buffer 调大,并且开启了磁盘缓存,就没再丢过了。所以采集端的配置也很重要,不能只盯着服务端。
6.3 查询超时与性能优化
查询超时一般是因为时间范围太大,或者没有加过滤条件,导致扫描的数据量太大。优化方法有几个。一是尽量缩小时间范围,只查需要的时间段。二是加上字段过滤,利用索引加速。三是避免 SELECT *,只查需要的字段,减少 IO。
另外,如果数据量特别大,可以考虑对数据进行分区。OpenObserve 支持按时间分区,查询的时候会自动裁剪掉不相关的分区,速度会快很多。这个在流设置里可以配置,按小时或者按天分区都行。
下面这个表格是我整理的一些常见问题和解决办法,方便快速查阅。
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 启动失败,端口报错 | 端口被占用 | 改端口或停掉占用服务 |
| 启动失败,权限报错 | 数据目录权限不足 | 修改目录权限或换用户 |
| 数据写入慢 | 网络延迟或磁盘 IO 瓶颈 | 优化网络,换 SSD |
| 数据丢失 | 采集端 buffer 太小 | 调大 buffer,开磁盘缓存 |
| 查询超时 | 时间范围大或没加过滤 | 缩小范围,加过滤条件 |
| 对象存储报错 | Bucket 不存在或配置错误 | 检查 bucket 和配置参数 |
6.4 与现有监控体系的整合经验
如果你已经有了一套 Prometheus 加 Grafana 的体系,不用全部推翻重来。可以把 OpenObserve 当作长期存储和日志查询的补充。Prometheus 继续做采集和告警,Grafana 继续做可视化,OpenObserve 负责日志的存储和检索,以及指标的长期归档。这样迁移成本最低,风险也最小。
我自己的做法是,新项目直接用 OpenObserve 做日志和链路,指标还是走 Prometheus。老项目慢慢迁移,先把日志采集切过来,观察一段时间没问题了,再考虑其他数据。这种渐进式的迁移方式,对业务影响最小。
7. 一些实操心得和后续扩展思路
用了一段时间下来,我觉得 OpenObserve 最适合的场景是中小团队,没有专门的运维团队去维护复杂的 ELK 集群,但又需要日志和指标的统一查询能力。它的部署简单,资源占用低,存储成本也可控,这几个点对于资源有限的团队来说很友好。
如果你要上生产环境,我有几个建议。第一,一定要配对象存储,本地磁盘只做缓存,这样数据可靠性和扩展性都有保障。第二,采集端要做好缓冲和重试,避免网络抖动导致数据丢失。第三,定期检查数据保留策略,避免存储成本失控。第四,监控 OpenObserve 自身的健康状态,比如写入延迟、查询延迟这些指标,可以暴露给 Prometheus 来采集。
后续扩展的话,可以试试集群模式,配合 K8s 部署,做高可用。也可以把 OpenObserve 的查询 API 集成到自己的运维平台里,做统一的监控入口。另外它支持多租户,如果公司有多个团队,可以按团队划分组织,做资源隔离。
这个项目还在快速迭代,新功能加得挺快的。我个人的体会是,它不一定能完全替代 Elasticsearch 和 Prometheus,但在某些场景下,确实是一个更轻量、更省心的选择。特别是对于那些被 ES 的资源占用和 Prometheus 的存储限制折腾过的朋友,值得花点时间试一试。