Oodle 如何实现大规模可观测性的高速查询
Oodle 通过分离存储与计算、使用对象存储和按需计算,实现大规模可观测性数据的高效存储与查询,尤其适合 AI 驱动的突发查询负载。
在可观测性领域,传统数据库架构往往将存储与计算紧密耦合,导致为应对突发查询而过度预留容量,成本高昂。Oodle 采用了一种不同的思路:将数据持久化到对象存储(如 S3),并在需要时才启动计算资源。这种设计听起来简单,但要在大规模负载下保持快速响应,需要对数据写入、压缩和查询执行进行精细优化。
Oodle 的架构主要服务于指标数据,但同样适用于日志和追踪。其核心原则包括:数据不可变性、近期数据对事故响应至关重要、查询负载波动大、同一数据可能被反复查询。AI 的引入进一步加剧了这些需求:更多服务产生更多遥测数据,AI 辅助调试工具会并行发起大量查询,且模型生命周期要求更长的数据保留周期。传统的内聚式架构无法在不过度配置的情况下应对这种增长。
指标数据的特殊性在于,它们通常以约30秒的间隔到达,但并非按时间序列顺序写入,而是以轮询方式分散在大量序列中。这导致三个实际问题:不能依赖简单的顺序写入、压缩时需要拼接交错片段、用户期望在压缩后台进行时仍能快速查询最新数据。
Oodle 的解决方案包括:
- 存储与计算分离:对象存储提供持久性和经济性,无服务器计算(AWS Lambda)处理突发查询。
- 写入(Ingestion):通过 Prometheus Remote Write 或 OTLP 协议接收数据,批量写入预写日志(WAL)对象到 S3。采用压力刷新策略避免热点阻塞,早期分区减少后续合并工作。
- 压缩(Compaction):将无序的 WAL 数据转换为读取友好的文件格式,包括合并去重、写入索引文件、清理旧对象。
- 近期数据快速通道(Blazer):将最近的 WAL 数据缓存到内存,提供快速查询,直到压缩完成。同时支持高可用副本。
- 查询路径:按数据鲜度分发查询,常规负载使用专用计算,突发负载使用 Lambda 无服务器工作节点。列式 PromQL 引擎与列式压缩文件配合,仅读取所需列,减少数据扫描。
- 文件格式优化:按指标名称排序数据块、尾元数据支持定向读取、压缩元数据字典编码、列块级跳过等减少不必要的数据解码。
此外,Oodle 还注意避免串行 S3 调用,采用并行读取和范围读取,并缓存小元数据以减少开销。压缩文件大小控制在 128MB 左右,既便于并行化,又避免了巨大的单体文件。数据和元数据分离存储,元数据文件小,可快速获取。
最终,工程团队体验到了显著改善:更少的存储集群维护、更好的保留经济性、更好的突发查询并发处理能力,以及更快的从数据采集到可用答案的路径。Oodle 的设计目标是支持每小时超过10亿时间序列的吞吐量。