ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Rust 打造 OpenObserve:低成本替代 ELK 与 Prometheus 的可观测性实践

Rust 打造 OpenObserve:低成本替代 ELK 与 Prometheus 的可观测性实践 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 当作长期存储和统一查询层这样两边的好处都能拿到。下面这个表格是我整理的核心对比方便你快速判断适不适合自己的场景。对比维度ElasticsearchPrometheusOpenObserve开发语言JavaGoRust资源占用高JVM 堆内存大中本地存储受限低无 GC存储成本高中低对象存储日志支持强弱强指标支持弱强中链路支持需额外组件不支持原生支持部署复杂度高中低查询语言DSLPromQLSQL 风格3. 部署实操从零跑起来一个 OpenObserve3.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_EMAILadminexample.com \ -e ZO_ROOT_USER_PASSWORDComplexPass123! \ -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_PROVIDERminio \ -e ZO_S3_SERVER_URLhttp://minio.example.com:9000 \ -e ZO_S3_REGION_NAMEus-east-1 \ -e ZO_S3_ACCESS_KEYyour-access-key \ -e ZO_S3_SECRET_KEYyour-secret-key \ -e ZO_S3_BUCKET_NAMEopenobserve \ -e ZO_S3_FORCE_PATH_STYLEtrue这里有几个点要注意。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 adminexample.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: adminexample.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 的存储限制折腾过的朋友值得花点时间试一试。
返回列表