作者:来自 Elastic Kostas Krikellas, Martijn Van Groningen, Nhat Nguyen 及 Felix Barnsteiner
Elasticsearch 现在以每个数据点 3.75 字节的存储成本保存 OTel 指标,并且查询速度最高比 Prometheus 快 30 倍。以下是我们如何重构 TSDS 和 ES|QL。
亲自动手体验 Elasticsearch:深入探索 Elasticsearch Labs 仓库中的示例 notebooks,开始免费的云试用,或者立即在你的本地机器上体验 Elastic。
Elasticsearch 现在以每个数据点 3.75 字节的存储成本保存 OTel 指标 —— 相比一年前的 25 字节大幅下降 —— 并且相比Prometheus、Mimir和ClickHouse,查询速度最高快30 倍,存储效率最高提升 2.5 倍。这些提升来自于我们将 TSDS 存储和 ES|QL 计算引擎重构为完全列式的指标引擎,同时在此过程中加入了原生 OTel 摄取能力 —— 并且依然保留了 Elasticsearch 同时存储和查询日志、追踪以及任何其他数据的能力。
自8.7 版本以来,Elasticsearch 一直支持在时间序列数据流(TSDS)中存储指标。这个方案最初主要聚焦于存储效率提升,正如我们之前的一篇博客文章中所解释的那样。不过,在存储和查询指标方面,其性能仍未达到专用指标系统的水平,特别是在存储效率、索引吞吐量和查询延迟方面。
在过去一年中,我们重新审视了存储层,为 OTel 指标优化了数据摄取,并通过对时间序列数据引入向量化处理扩展了 ES|QL 计算引擎。与早期版本的 TSDS 相比,这些工作在整体性能方面带来了显著提升:
OTel 指标的存储效率最高提升6.6 倍,达到每个数据点 3.75 字节
OTel 数据的索引吞吐量最高提升50%
查询延迟最高提升160 倍,包括极快的计数器速率计算以及时间序列聚合中的窗口支持
因此,Elasticsearch 已成为领先的列式指标引擎,在索引吞吐量方面可与甚至超越 Prometheus、Mimir 和 ClickHouse 等竞争对手,并在存储效率方面最高领先2.5 倍,在查询性能方面最高领先30 倍。同时,它依然保留了存储日志及其他数据的能力,并能够完整使用 ES|QL 丰富的查询能力(例如 inline stats、lookup join) —— 这是其他基于 PromQL 的系统所缺乏的。
因此,Elasticsearch 可以作为所有用户数据的统一存储与查询引擎,在指标和可观测性应用方面无需做出任何妥协。
TSDS 的组织方式
TSDS 具有以下特性,这些特性有助于提升时间序列编解码器的性能,并在按时间序列聚合数据点时产生正确结果:
指标名称以及维度名称和值会被用来计算 [objectObject],这是每个时间序列的唯一标识符。
TSDS 会按照
[_tsid 升序, timestamp 降序]的顺序进行排序。因此,每个时间序列都会按顺序存储在磁盘上,较新的数据点优先出现。由于_tsid是基于维度值计算的,因此这些维度值在磁盘上也会被聚集存储。分片路由基于
_tsid,每个_tsid值只会出现在一个分片中。后备索引(backing indices)是有时间边界的,并且它们之间不存在时间重叠。
本文其余部分将解释我们如何利用这些特性来提升存储、索引和查询性能。
存储优化
当可以在单个文档中组合多个指标并共享相同维度值时,TSDS 已经能够实现极具竞争力的存储占用,最低可达到每个数据点 0.9 字节。然而,当大多数数据点都拥有唯一的一组维度时(这在 OTel 或 Prometheus 指标中非常常见),文档最终只会包含单个数据点。在这种情况下,存储成本达到每个数据点 25 字节,而专用指标存储系统通常只需要不到 10 字节。
为了进一步降低存储占用,我们在过去一年中实施了一系列优化:
使用 doc value skippers 替代倒排索引和 BKD 树
默认情况下,Elasticsearch 会为所有非指标字段创建倒排索引(文本字段)或 BKD 树(数值字段),即@timestamp和维度字段。这些索引能够提升包含这些字段过滤条件的查询性能,但会显著增加存储开销 —— 实际上会让每个字段的存储占用翻倍。
此外,这些索引还会在 segment merge 期间被处理,从而增加 CPU、内存和存储开销,并拖慢整个系统 —— 尤其是在高摄取吞吐量场景下,而这正是指标数据的典型特征。
Lucene 现已扩展支持 doc value skippers,这是一种分层稀疏索引形式,用于存储文档块中的最小值和最大值。范围查询可以检查这些最小值和最大值,并跳过不在请求范围内的文档块。
Skippers 在已排序字段上表现尤其优秀。由于 TSDS 按照[_tsid, timestamp desc]排序,因此维度值也会在磁盘上聚集存储。因此,可以使用 doc value skippers 替代@timestamp和维度字段上的索引,从而强化列式布局—— 每个字段存储在独立文件中,并且无需为了索引目的重复跟踪每个文档。
Doc value skippers 几乎不会带来额外存储开销 —— 用它们替代索引后,在 OTel 场景中,每个数据点的存储成本从原始的 25 字节减少了10 字节。
此外,当查询包含时间范围或维度值过滤条件(包括前缀和正则表达式)时,它们在实际运行中的表现也非常出色 —— 在我们的基准测试中,用 skippers 替代独立索引后,查询性能没有出现明显回退。
从9.3 版本开始,TSDS 默认启用 doc value skippers。
启用合成 ID
_id元数据字段也是存储占用的重要来源之一。TSDS 已经扩展支持在 doc values 不再用于复制后对其进行裁剪,但倒排索引仍然被保留下来,以高效支持基于 id 的 API(Get、Delete、Update)。
TSDS 的 ID 值是通过组合_tsid和@timestamp值生成的,这两个字段能够唯一标识每个数据点。由于这些字段已经配置了 doc value skippers,因此可以将_id上的倒排索引替换为:(a)从_id值中解析出_tsid和@timestamp值,以及(b)分别使用 doc value skippers 来检查匹配项。在指标摄取期间,需要特别注意避免昂贵的重复 ID 检查,而 segment 级别的 bloom-filters 能够有效控制这部分开销。
在指标场景中支持合成 ID 是 Elasticsearch 的首次尝试。这项优化使 OTel 指标每个数据点的存储成本在原始 25 字节基础上进一步减少了5 字节,并且没有损失任何功能。
从9.4 版本开始,TSDS 默认启用合成 ID。经过进一步评估后,我们计划将其扩展应用到日志及其他场景中。
裁剪序列号
序列号被用于复制,同时也通过乐观并发控制(Optimistic Concurrency Control - OCC)在文档修改操作中提供强一致性语义。虽然这些语义适用于某些场景,但它们并不适合指标数据,因为指标中并发更新非常少,而且在数据点具有相同 id 时也没有实际防止并发操作的需求。因此,我们决定在 TSDS 的所有 API 中禁用序列号的使用以及 OCC 支持,该变更在9.4 版本中生效。
这带来了显著的存储减少:在 OTel 数据中,每个数据点从最初的 25 字节中减少了4 字节。同时,由于不再需要倒排索引,并且序列号在复制不再需要后会被裁剪,从而进一步降低开销。按查询更新和删除操作仍然支持,但一致性语义有所减弱。
如果某个指标应用仍然认为 OCC 很重要,可以通过在相关 TSDS 的 index template 中设置index.disable_sequence_numbers: false来恢复旧行为。
使用大数值编码块
TSDS 已经使用了一种高级编码器,正如之前一篇文章中所解释的那样。该编码器在大多数情况下表现良好,但在重复的关键词和数字序列场景中性能较差,这会导致包含 IP 和 MAC 地址的维度出现存储膨胀问题。
我们发现,现有用于识别重复序列的逻辑需要更大的编码块才能发挥良好效果,尤其是在序列长度增加时更为明显。经过实验,在9.3 版本中将数值块大小从 128 提升到 512 个元素,从而在包含 IP 和 MAC 地址维度的 OTel 数据集中,每个数据点减少了 2 字节的存储开销。
我们也在研发一种更可配置的编码布局,允许根据字段类型和基数(cardinality)对块大小及其他参数进行更灵活的调整。
索引吞吐量
Elasticsearch 支持通过 bulk 方式进行文档摄取。这个入口长期以来都经过优化以保证宽松性,确保所有文档都能被接收。然而,这种灵活性会在索引过程中带来额外的处理成本。
指标类应用被证明非常适合采用不同的方法来降低这部分开销,如下所述。
引入 OTLP protobuf 入口
OTel 指标和 Prometheus 都已经建立了成熟的指标摄取协议,基于 protocol buffers(协议缓冲)。在过去,需要一个转换步骤,将收集到的 protobuf 消息转换为 Elasticsearch 可以消费的 bulk 请求。
Elasticsearch 最近新增了能够直接接收来自 OTel metrics collector 以及 Prometheus remote write 的消息的端点。与 JSON 解析相比,解析和处理这些(二进制)消息的成本更低,同时在_tsid计算中对维度进行 hash 操作可以在同一个 protobuf 消息中的多个数据点之间复用并摊销。
此外,_tsid在协调节点中每个文档只计算一次,然后传递到数据节点用于索引,从而避免在每个索引文档上重复执行这一昂贵步骤。这些优化使 OTel 指标的索引吞吐量最高提升约 20%。
OTLP 入口在 9.2 版本中以技术预览形式加入,并在 9.3 版本中正式 GA。同时,我们在9.4 版本中为 Prometheus remote write添加了类似入口(技术预览),并正在积极扩展以覆盖 OTel 日志和追踪数据。
通过 doc value skippers 降低索引 CPU
除了显著的存储占用减少之外,倒排索引在构建以及 segment merge 过程中也需要大量 CPU 进行处理和重建。使用 doc value skippers 替代这些索引,同样可以降低摄取时的 CPU 负载,从而带来约 10% 的索引吞吐提升,这也是在前述存储收益之外的额外收益。
合成 recovery source
文档在索引时提供的原始 source 在指标场景中并不会被持久存储。然而 Elasticsearch 仍然需要在复制过程中临时保存它。
这一点在9.1 版本发生了变化:source 在复制时改为按需合成,这被称为 synthetic recovery source。这一机制减少了约 50% 的磁盘 I/O,并对指标索引性能带来了显著提升。更多细节可参考相关文章。
查询执行
将倒排索引替换为 doc value skippers 会使 TSDS 变为纯列式存储布局,其中指标和维度字段都以 Lucene doc values 形式存储,每个字段都在各自独立的文件中进行编码和压缩。
结合 ES|QL 计算引擎的引入(其内部使用向量化执行),使得在 Elasticsearch 中为指标构建一个完全列式的存储与查询处理引擎成为可能。我们将这一思路推向极致,实现了一个列式指标处理引擎,在查询性能上能够稳定超越专用指标引擎以及其他列式存储系统。
计算引擎中的时间序列集成
时间序列处理主要基于对每个时间序列(即_tsid)应用聚合函数,例如 gauge 平均值或 counter 速率。这些部分结果随后会通过第二层函数进行归约,以生成按分组维度(例如按 host 和 process)聚合的结果。
可观测性仪表盘正是基于这一执行模型构建的,它提供指标随时间变化的汇总视图,并支持通过维度值和时间范围过滤来快速深入分析。
为了支持这一执行模型,我们引入了 TS source 命令,提供了一种简单但强大的语法,用于执行此类查询:它将“每个时间序列的内部聚合函数”和“对前述部分结果的外部聚合”组合在一起。
例如,以下查询计算过去一天内每个 host 的 search 请求速率的按小时求和:
TS metrics | WHERE TRANGE(1d) | STATS SUM(RATE(search_requests)) BY TBUCKET(1h), host为了执行该查询,计算引擎能够感知数据的存储方式,并针对每个_tsid值应用内部聚合函数。由于数据按照_tsid进行了排序,时间序列聚合函数会在获取指标值的过程中持续处理,直到_tsid发生变化或时间戳进入下一个时间桶为止。
这使得这些函数能够在获取到的指标值列上进行向量化执行,而维度值只会在_tsid发生变化时被获取一次。
第二层聚合函数的计算同样是高效的:部分聚合结果被存储在原始类型的数组中,并在_tsid值发生变化时进行填充。
计算引擎本身具备对并行查询执行的原生支持,能够充分利用可用的处理核心。时间序列聚合完全利用这一特性,在适用情况下并行处理数据点,通过提升 CPU 利用率来降低响应时间。
ES|QL 中的时间序列处理在 9.2 版本以技术预览形式引入,并在9.4 版本达到正式发布。我们预计所有指标应用都会采用它,并从显著提升的查询性能中受益。
零拷贝数据解码与加载
与通过/searchAPI 执行的聚合相比,向量化时间序列处理带来了立竿见影的性能提升(某些查询可达8 倍),但与竞争性的指标存储相比仍然存在差距。基准测试和性能分析显示,在计算引擎中,从数据解码到聚合函数执行之间存在过多的数组拷贝。
为此,引入了以下优化:
- TSDS 的编码器被扩展为可以直接将磁盘上的数据解码到计算引擎用于执行时间序列聚合的块内原始数组中。无需额外拷贝,因为计算引擎可以批量读取这些块,并按列逐个处理数组。
- 对于在一个块中重复 N 次单一值的情况,这些块会被表示为常量块,仅包含两个值,而不是长度为 N 的数组,这是一种内存中的运行长度编码形式。过滤和聚合操作也被扩展以高效处理这些块。这减少了
_tsid和维度字段的内存压力与 CPU 开销,因为这些值在索引排序后会被聚集存储。 - 对于聚合指标字段中为 null 的文档,会在 Lucene 层面直接过滤掉,避免在解码并写入块之前进行处理。
- 所有针对时间戳和维度字段的过滤器与正则表达式都会下推到 Lucene,由 doc value skippers 高效过滤不匹配的文档。
综合这些优化,查询执行速度提升超过10 倍(与向量化执行带来的 8 倍提升叠加后,总体可达 80 倍)。这些改进自9.2 版本引入 TS source 命令以来逐步加入,并持续优化至今。
优化计数器速率计算
虽然大多数时间序列聚合都可以轻松并行化执行,但累计计数器的速率计算却比较复杂,因为它需要按顺序处理所有数据点,以检测计数器重置(例如主机重启时)。为了解决这个问题,计算引擎使用_tsid前缀对时间序列进行线程级分片。
在设计中,我们特别注意为每个线程分配有序的_tsid值范围,而不是对_tsid进行哈希分片,这样每个线程都可以按顺序扫描磁盘数据,同时继续利用高效解码和零拷贝写入块的能力。
性能提升非常显著,速率计算的性能甚至超过了专用指标存储系统,下一节将详细展示这一点。
另一个关于累计计数器的有趣问题是:当时间桶边界没有数据点时,如何正确计算整个时间桶内的计数增长。指标系统通常使用外推法(extrapolation),将每个时间桶的首尾数据点延伸到边界,或计算相邻桶最后一个数据点之间的差值。
我们认为可以做得更好:通过在每个时间桶的最后一个数据点与下一个桶的第一个数据点之间进行插值,来估算边界上的值。然后,在每个时间桶的下边界和上边界的插值值之间计算差值,从而得到更精确的结果。
滑动窗口支持
Elasticsearch 长期以来支持按时间进行分桶聚合,但无法将处理窗口扩展到单个时间桶之外。例如,当按分钟分桶时,如果使用 5 分钟的窗口,就可以在更大范围内平滑突发峰值,并以更低噪声观察每个时间序列的底层趋势:
所有时间序列聚合函数都已扩展支持窗口(window),作为可选参数。
当窗口是时间桶的倍数时(例如 TBUCKET(5m) 配合 1h 窗口),计算引擎会先在与时间桶跨度一致的区间内对数据点进行聚合,然后再在窗口范围内合并这些部分结果。这种两阶段处理方式避免了对数据点的重复扫描,并实现了中间结果的最大复用,从而提升响应速度。
窗口支持在 9.3 版本以技术预览形式引入,并在9.4 版本达到正式发布。
高效的日期时间取整
时间序列查询通常包含时间分桶操作。虽然数据点可以轻松分配到小时以下的时间桶中,但当桶变大时,会涉及时区、夏令时、每月天数不固定等问题。Elasticsearch 具备复杂的日期时间取整逻辑来处理这些特殊情况,但在处理时间序列数据时,这会带来较高的 CPU 开销。
为此,计算引擎进行了扩展,能够识别哪些场景可以使用更简单的逻辑来将数据点分配到时间桶。例如,当桶小于一小时,或者时区与夏令时不会影响查询时,就会切换为简单的取模运算来进行日期时间取整。
这一优化使部分查询的响应时间进一步提升约30%。该改进在9.4 版本中引入。
性能评估
为了评估我们的方案性能,并跟踪其随时间的演进与改进,我们重点选择了 OTel 指标作为基准数据,因为:(a) OpenTelemetry 是行业标准的指标采集方案,被所有云厂商广泛采用;(b) 它会导致一种 “每个文档一个指标” 的存储布局,而这种布局传统上对 Elasticsearch 的性能并不友好。
我们依赖 Metricsgenreceiver 来生成数据集。该工具受 TSBS 启发,用于模拟 OTel hostmetricreceiver 收集的数据点。我们使用了两个数据集:
低基数(low-cardinality)场景:100 台主机每 1 秒发送一次指标,共计约 14k 条时间序列
高基数(high-cardinality)场景:10k 台主机每 10 秒发送一次指标,共计约 140 万条时间序列
我们在 EC2 单节点部署上进行基准测试,低基数和高基数数据集分别使用 c6i.4xlarge 和 c8g.8xlarge 机器。
在对比系统方面,我们使用了 Prometheus(v3.11.1)、Mimir(v3.0.6)以及 ClickHouse(v26.3.9.8-lts)。Prometheus 和 Mimir 具备完善的时间序列处理能力,例如计数器速率计算,而 ClickHouse 则缺乏此类支持,仅能提供近似结果(例如无法一致地处理计数器重置)。
尽管如此,我们仍然报告 ClickHouse 的响应时间,因为这可以说明:当我们将 Elasticsearch 优化为列式查询引擎后,即使在其他列式引擎未按时间序列语义处理数据的情况下,它仍然能够超越它们。
我们尽量为所有系统使用默认配置(包括 Elasticsearch),不针对特定工作负载进行调优。这有助于理解普通用户(缺乏经验或时间进行调优)在接入指标数据和搭建仪表盘时的真实体验。
我们主要关注单节点运行,以降低噪声并确保所有系统都能运行(例如 Prometheus 默认不支持多节点部署)。Elasticsearch 的性能在节点扩展时具备良好的可扩展性;我们计划在后续文章中分享扩展性测试结果。
存储效率与索引吞吐量
我们在提升存储效率方面的努力取得了显著成果。OTel 指标的性能从每个数据点 25 字节下降到 3.75 字节,仅用了一年时间就完成了这一提升。
在一个已经针对时间序列高度优化的系统之上还能实现这样的改进,这在行业中是非常罕见且令人印象深刻的。
目前的竞争格局看起来是有利的,Elasticsearch:
- 在存储效率和索引吞吐量方面略优于 Mimir
- 在存储效率方面比 Prometheus 高2.5 倍,在索引吞吐量方面也略有优势
- 在存储效率方面比 ClickHouse 高2 倍,在索引吞吐量方面高 40%
查询性能
新的用于指标处理的列式引擎在实践中证明非常高效。
我们使用了基于 gauge 平均值和 counter 速率的混合查询,这是最常见且需要不同优化方法的操作。查询区间为4小时数据,覆盖每个指标的所有时间序列。
ClickHouse 不支持时间序列聚合,因此结果具有有限价值,且不能直接与 Prometheus 或 Mimir 进行比较,这些系统原生支持时间序列处理。我们使用已发布的指南对每个查询进行调整,以在尽可能的范围内获得相似结果。
目的是展示我们的列式引擎与通用列式存储的对比情况。
以下是结果摘要:
| 查询类型 | Mimir | Prometheus | ClickHouse † |
|---|---|---|---|
| Gauge 平均值 | 最高快 30 倍 | 最高快 30 倍 | 最高快 8 倍 |
| Counter 速率 | 最高快 30 倍 | 最高快 30 倍 | 最高快 3.5 倍 |
| 主机名前缀过滤 | 最高快 5 倍 | 最高快 5 倍 | 最高快 3 倍 |
| 带窗口的 Gauge 平均值 | 最高快 25 倍 | 最高快 25 倍 | 最高快 4 倍 |
†ClickHouse 缺乏对时间序列聚合和计数器重置检测的原生支持。
Gauge 平均值
我们对按时间序列计算“每个主机的每小时平均内存利用率”的性能进行了对比评估,使用如下查询:
# PromQL avg by (host.name) (avg_over_time(system.memory.utilization[1h]))# ES|QL TS metrics-hostmetricsreceiver.otel-default | STATS AVG(AVG_OVER_TIME(system.memory.utilization)) BY host.name, TBUCKET(1h)Elasticsearch 在低基数和高基数数据集上都能轻松地比其他系统快最多 30 倍。
Counter 速率
接下来,我们对“每个主机按小时计算 CPU 速率平均值”的执行性能进行了对比,使用如下查询:
# PromQL avg by (host.name) (rate(system.cpu.time[1h]))# ES|QL TS metrics-hostmetricsreceiver.otel-default | STATS AVG(RATE(system.cpu.time)) BY host.name, TBUCKET(1h)尽管按时间序列顺序逐点处理数据,但 counter 速率性能与 gauge 平均值计算相当(相关时间序列的文档数量是上述查询的 6.6 倍)。
与其他系统相比,Elasticsearch 仍然保持显著优势,在低基数数据集中比 Mimir 和 Prometheus 快 30 倍,在高基数数据集中快 16 倍。
在高基数数据集中,Elasticsearch 能在不到 2 秒内处理 50 万条时间序列的 4 小时数据,这一点非常令人印象深刻,而其他系统则需要超过 30 秒,从而导致这类查询的仪表盘变得无响应。
ClickHouse 也更慢,尽管它没有用于检测计数器重置以及在时间桶之间进行外推/插值计算 delta 的逻辑。
主机名前缀过滤
接下来,我们对基于主机名前缀的过滤性能进行了对比,使用如下查询:
# PromQL avg by (host_name) (avg_over_time(system_cpu_load_average_1m{host_name=~"host-.*"}[5m]))# ES|QL TS metrics-hostmetricsreceiver.otel-default | WHERE host.name LIKE "host-*" | STATS AVG(AVG_OVER_TIME(system.cpu.load_average.1m)) BY host.name, TBUCKET(5m)尽管将 host.name 上的倒排索引替换为 doc value skipper,Elasticsearch 仍然能够保持最高 5 倍于其他系统的优势。
带窗口的 Gauge 平均值
我们对时间序列聚合在窗口为 90 分钟、时间桶为 30 分钟的情况下进行了性能对比,使用如下查询:
# PromQL avg by (host.name) (avg_over_time(system.memory.utilization[90m]))&step=30m# ES|QL TS metrics-hostmetricsreceiver.otel-default | STATS AVG(AVG_OVER_TIME(system.memory.utilization, 90m)) BY host.name, TBUCKET(30m)Elasticsearch 在低基数数据集中保持最高 25 倍的优势,在高基数数据集中保持最高 8 倍的优势。ClickHouse 的性能落后近 4 倍,这说明了我们在窗口查询操作方面方法的高效性。
Elasticsearch 指标的未来
Elasticsearch 已扩展出指标存储与处理能力,在性能上优于 Prometheus、Mimir 和 ClickHouse。我们正在快速推进对 PromQL 和 Prometheus remote write 的支持,这些功能在9.4 版本中也作为技术预览提供。
这些扩展使熟悉 Prometheus 及相关系统的用户可以将应用迁移到 Elasticsearch —— 无需迁移现有仪表盘。由于 Prometheus 集成复用了本文所述的同一存储与查询引擎,因此相同的性能收益也适用于 Prometheus。
此外,指标既可以用 PromQL 查询,也可以用 ES|QL 查询,甚至可以在同一个 ES|QL 查询管道中结合使用,从而显著增强分析能力,远超以往基于 Prometheus 的系统所能实现的范围。
在存储效率、索引吞吐量和查询性能方面的改进已经非常显著,但我们仍未停止。我们将继续优化时间序列数据的编码器,进一步降低每个数据点的字节数。同时还会改进批量指标处理,减少同步开销以及对结构良好指标数据而言不必要的冗余处理层。
我们还计划更广泛地使用 doc value skippers,在数据块级别存储预计算的 sum 和 count 等聚合结果,从而在适用情况下跳过数据点加载与处理,并采用更高 CPU 友好的分区与分组操作。
常见问题
什么是列式指标引擎,它为什么重要?
列式指标引擎将每个字段单独存储,而不是按行存储,然后在查询时只读取所需列。对于时间序列数据,这意味着 Elasticsearch 可以分别解码指标值、维度字段和时间戳,并在每一列上进行向量化操作。相比行存储,这种方式带来更快的聚合速度和更低的存储开销。
Elasticsearch 与 Prometheus 在时序指标存储和查询方面如何对比?
Elasticsearch 在 9.4 版本中将 OTel 指标压缩到每数据点 3.75 字节,比 Prometheus 低约 2.5 倍。在查询方面,Elasticsearch 在 gauge average 和 counter rate 基准测试中比 Prometheus 和 Mimir 快最高 30 倍。在高基数数据集(140 万时间序列)中,Elasticsearch 在不到 2 秒内处理 4 小时数据,而 Prometheus 需要超过 30 秒。
什么是 Elasticsearch TSDS,什么时候应该使用它?
TSDS(time-series data streams - 时间序列数据流)是 Elasticsearch 用于指标与时间序列数据的存储格式。它按_tsid和时间戳排序文档,将字段以列式 doc values 存储,并使用专用编码器压缩数据。适用于所有指标工作负载,尤其是 OpenTelemetry 或 Prometheus 数据,对存储效率和查询速度有要求的场景。
ES|QL 中的 TS source 命令是什么?
TS是 ES|QL 的 source 命令,在 9.4 版本达到正式发布,用于执行时间序列查询,采用双层模型:先对每个时间序列执行内部聚合(如RATE()或AVG_OVER_TIME()),再对结果进行外层聚合。计算引擎按时间序列排序执行数据,支持向量化与并行处理。例如:TS metrics | STATS AVG(RATE(cpu.time)) BY host.name, TBUCKET(1h)。
Elasticsearch 如何从每个 OTel 数据点 25 字节降到 3.75 字节?
在 9.1 到 9.4 版本中通过四项优化实现:用 doc value skippers 替代倒排索引(减少 10 字节)、启用合成 ID(减少 5 字节)、裁剪序列号(减少 4 字节)、以及将编码块从 128 提升到 512(减少 2 字节)。最终在一年内实现约 6.7 倍的存储压缩。
Elasticsearch 能否在不迁移仪表盘的情况下替代 Prometheus?
Elasticsearch 支持 Prometheus remote write(9.4 技术预览)和 PromQL 查询(9.4 技术预览)。现有 Grafana PromQL 仪表盘只需少量修改即可指向 Elasticsearch。由于 TSDS 存储和 ES|QL 引擎同时支撑 PromQL 和 ES|QL,两者都能获得相同性能收益。
什么是 doc value skippers,为什么对指标很重要?
doc value skippers 是 Lucene 的结构,用于存储文档块的最小值和最大值。在 TSDS 中,它们替代了维度字段和@timestamp上的倒排索引。这样可以每个数据点减少约 10 字节存储,并降低约 10% 的索引 CPU 开销,同时在时间范围与维度过滤上没有性能回退。
原文:https://www.elastic.co/search-labs/blog/elasticsearch-columnar-metrics-engine-30x-faster-prometheus