译自:New in Grafana Mimir: Introducing out-of-order sample ingestion
很早之前在使用thanos和多实例的Prometheus时经常会在thanos日志中看到时序数据乱序的问题。当时唯一的办法就是从对象存储中手动删除这部分数据,非常不方便。Grafana Mimir中对乱序数据的支持是一个很大的改进。
传统的Prometheus TSDB仅支持接收1小时内的有序采样,然后丢弃其他样本。这种方式可以让Prometheus高效地存储样本。但在实际中,Prometheus的拉取模式(以一定节奏从被观察的目标中提取数据)也给用户的使用带来了很多限制。
在一些使用场景下可能会存在乱序数据,如:
- 异步启动并写入指标的IoT设备
- 使用消息总线(如使用随机分片的Kafka)的复杂传递架构,可能存在拥塞延迟。
- 某些情况下受网络连接而孤立的Prometheus实例会尝试推送老的样本。
支持乱序的设计方案
我们和Dieter Plaetinck编写了一个设计文档来解决乱序问题。
数据的摄取
Prometheus TSDB有一个内存区域,称为head block。我们通过共享该head block来避免产生重复的内存索引,同时可以减低内存消耗。对于head block中的每个时序,我们在内存中保存了过去30个未压缩的乱序样本,并将其与有序样本完全隔离开来。当内存chunk中的乱序样本达到30个之后,它将会被压缩并刷新到磁盘,并从head block开始内存映射。
这一点类似head block处理有序样本的方式:内存中的有序样本会保存在一个压缩的chunk中,最大可以保存120个样本。由于需要保存到内存中,且乱序的chunk是未压缩的,因此我们将样本数限制为30,防止消耗过多的内存。
我们还引入了一个新的方式,称为Write-Behind-Log (WBL)。WBL类似Prometheus TSDB中的Write-Ahead-Log (WAL)。在WBL中,当在TSDB中添加样本之后才会写数据,而WAL是在TSDB数据变更前写数据。我们使用WBL来记录摄取的乱序样本,因为在摄取样本前,我们并不知道样本是有序的还是乱序的。
下图展示了该过程。注意乱序chunk之前可能会重叠(下图中:OOO = Out of Order)。
白色表示内存映射的乱序chunk,黄色表示活动状态(表示新来的样本,活动状态的样本可能会被合并)的乱序Head Chunk,而蓝色表示有序的Head Chunk,可以看到上述过程如下:
- 一开始内存中没有任何时序数据
- 此时来了两个样本,一个是时序为600的样本,另一个是时序为750的样本,它们作为一个有序的chunk
- 来了30个时序为1到150之间的乱序样本
- 来了10个样本,由于前面的chunk已经满了,因此需要为乱序数据创建一个新的chunk
- 随着样本的增加,需要创建更多的chunks。注意chunk1和chunk2有一个重叠的值,300
- 来了一个新的以时序0开始的样本,它被插入了chunk3,此时chunk3与chunk0、1、2重叠
查询
Prometheus TSDB有一个有用的抽象-查询器,它将head block和磁盘的持久块上的所有内容视为“块读取器”。TSDB使用一个head block包装器来读取固定时间范围内的有序数据。类似地,我们实现了另一个围绕head block且仅读取乱序chunk的包装器。这样,head block可以体现为两种块读取器:仅读取有序数据的,和仅读取乱序数据的。
现有的查询逻辑可以无缝地处理块读取器和其他持久块数据的合并结果。但查询器要求块读取器按排序提供非重叠的块。这样,head block的乱序块读取器需要在查询时合并重叠的chunks(如下图)。当访问样本时,会发生合并,但不会重新创建块。
压缩
TSDB中的持久块会与2小时Unix时间戳对齐。对于有序数据,每过2小时,我们会获取head block中的2小时内的老数据,并将其转变为持久块,这个称为head block的压缩过程。在压缩完有序数据后,也会对乱序数据进行压缩。
由于乱序数据的特点,其可能包含跨2个小时块的样本。因此,根据需要,我们在单次乱序数据的压缩过程中会生成多个持久块,如下所示。该持久块与其他持久块类似。在压缩之后,会根据需要清理WBL和其他内容。这些块可能会与磁盘中已有的块或head block中的有序数据重叠。
一旦产生了这些块,就完成了乱序代码的处理。TSDB能够从重叠的块中请求数据,并在需要时合并重叠的块。
Grafana Mimir 和 Grafana Cloud中的乱序样本摄取
我们引入了一个名为out_of_order_time_window
的配置参数来指定可以支持多老的乱序样本。默认为0,即不支持乱序样本。如果设置为1小时,则Grafana Mimir 会摄取过去1小时内的所有乱序样本。
性能特征
性能取决于:
- 摄取乱序样本的模式
- 乱序样本的数目
- 摄取的乱序样本率
在很多情况下,所有上述条件都会导致摄取器的CPU使用率增加。在有限验证的条件下,我们发现除处理乱序样本的摄取器(摄取和查询)上的CPU利用率为50%外,其他组件没有看到CPU变动。
在我们的环境中,内存的增加并不明显。但当时间序列的很大比率为乱序样本时会导致内存变化,但总体增长应该仍然很小。
PS
Prometheus v2.39.0版本已经支持乱序指标,通过out_of_order_time_window
配置乱序窗口