开源时间序列数据库分析 – 第四部分
在这篇文章中,我们分析了受欢迎的开源时序数据库引擎在保存和计算时序数据方面的能力。
周肇峰的著作
普罗米修斯
一系列的的关于开源时间序列数据库分析的文章已经完成。在这些文章中,比较与分析了基于Hbase的OpenTSDB、基于Cassandra的KairosDB、BlueFlood和Heroic,以及排名第一的InfluxDB中的TSDB。 InfluxDB是纯粹自主开发的TSDB。在审查相关文献时,我对基于LSM思想优化时间序列数据场景的底层存储引擎TSM产生了兴趣。文献中分享了从InfluxDB的初始使用到从LevelDB到BoltDB的更换,最终决定自主开发TSM的全过程,深入描绘了每个阶段的困扰点,核心问题需要解决的核心问题以及最终TSM的核心设计思想。我喜欢这种直观地教导技术进化的共享,而不是直接传达哪种技术最好。对于每个阶段的问题以及最终技术选择的原因进行深入分析的地方给我留下了深刻的印象,我从中学到了很多。
然而,在 InfluxDB 的 TSM 中,并没有详细说明,更多地侧重于策略和行为的描述。最近,我看到了一篇名为“从零开始编写时间序列数据库”的文章。尽管与标题略有矛盾,但它介绍了关于 TSDB 存储引擎的设计思想,以及非常有用的技巧和经验分享。此外,这个存储引擎不仅仅是一个概念或玩具,它实际上已经被应用于生产环境中。这是一个全新的存储引擎,完全由 Prometheus 2.0 在2017年11月发布时进行了重写。这个新的存储引擎声称带来了“巨大的性能改进”。
数据模型
普罗米修斯与其他主流的时间序列数据库(TSDB)一样,使用度量名称、标签(类似于标签)、以及度量值来定义数据模型。所有的时间序列都可以通过与度量名称和标签(也被称为键和值的配对)的组合来唯一识别。普罗米修斯支持基于标签的时间序列查询,可以使用简单条件和复杂条件。在存储引擎的设计中,主要考虑了数据存储(写入次数大于读取次数)、数据保留和基于时间序列数据特性的数据查询。普罗米修斯目前还不涉及数据分析。

这张照片展示了一个横轴为时间,纵轴为时间线的简单数据点分布。区域内的点表示数据点。每次Prometheus获取数据时,都会接收到区域内的垂直线,就像图中显示的一样。每条时间线每次只生成一个数据点,但同时生成数据点的时间线有很多。通过将这些数据点连接起来,就形成了垂直线。这个功能对于数据的写入和压缩优化策略具有非常重要的影响。
V2存储引擎
在本文中,我們將主要介紹V2儲存引擎的最新版本,即V3儲存引擎的部分設計理念。V2儲存引擎將每個時間線生成的數據點存儲到不同的文件中。我們將根據這個設計來討論一些話題。
1、优化写入:HDD和SSD的写入模式最理想的是顺序写和批量写。正如前面所述,Prometheus每次接收的数据是由许多数据点组成的垂直线。然而,这些数据点属于不同的时间线。在当前设计中,每个时间线的数据都存储在不同的文件中。因此,每次需要将大量不同的数据写入到多个不同的文件中。为了解决这个问题,V2存储引擎的优化策略是按顺序写入更大的数据块。在一个时间线中生成的数据必须批量写入。为此,需要在时间线维度上积累一定时间内的一定数量的数据点。除了批量写入,更大的数据块的写入还优化了热数据查询效率和数据压缩率。V2存储引擎采用了与Facebook Gorilla相同的压缩算法,将16字节的数据点平均压缩到1.37字节,并使内存和磁盘容量节省了12倍。为了按块写入数据,需要在服务器的内存中累积一定时间的数据。也就是说,热数据基本上被存储在内存中,从而实现了非常高的查询效率。
2、查询优化:对于时间序列数据,存在各种查询场景。可能会对某一时间轴的特定时间点的数据进行查询,也可能会对多个时间轴的多个时间点的数据进行查询,或者对某一时间段内多个时间轴的数据进行查询。就像上述数据模型图所示,查询是一个二维平面上的矩形数据块。无论是SSD还是HDD,优化硬盘数据的读取性能应该是只需读取硬盘上数个随机位置的数据来完成每个查询,并能按顺序读取大块数据。这与硬盘内的数据分布密切相关,主要涉及数据的写入。然而,并不一定需要实时的写入优化,可以通过后续数据匹配进行优化。V2存储引擎提供了一些优秀的优化策略,其中主要包括在更大的块中进行数据写入和热数据内存缓存。这两个优化策略将被V3继承。此外,V2还存在许多缺点。
-
- タイムラインの数が増えるとファイルの数が増え、遅かれ早かれinodeを使い果たしてしまう可能性があります。
-
- チャンクベースのアプローチでも、1回の書き込みに多くのタイムラインが関与している場合、IOPSの要件は依然として高くなります。
-
- すべてのファイルを読み書きのために常にオープンにしておくのは非現実的です。ファイルがクエリされると、大量のファイルを開いて、関連するデータポイントを見つけてメモリに読み込んで、再び閉じなければなりません。これでは、クエリの待ち時間が長くなってしまいます。
-
- データ削除では、大量のファイルをスキャンし、それらのファイルにデータを書き換えなければなりません。どちらもかなり長い時間がかかります。
- データの塊は、ディスクに書き込まれる前に一定期間メモリに蓄積される必要があります。V2では、チェックポイントを定期的に書き込む仕組みを利用して、メモリ内のデータが失われないようにしています。しかし、一般に、チェックポイントを記録する時間は、通常、許容されるデータ損失の時間窓よりも長く、さらにチェックポイントを復元するために必要な時間もかなり長いです。
在V2存储引擎中,时间线索引使用LevelDB存储标签和时间线之间的映射关系。当时间线数量逐渐增加时,查询效率会变得非常低。一般来说,时间线的基数相对较小。这是因为应用环境很少改变,且在运行稳定时时间线基数也保持稳定。然而,如果标签设置不当,例如将动态值(如程序版本号)作为标签使用,每次应用程序升级时标签的值将会发生变化。随着时间的推移,将存在越来越多的非活动时间线(在Prometheus环境中称为系列链)。时间线的大小会不断增大,影响索引查询的效率。
V3存储引擎
为了解决V2引擎的问题,V3引擎进行了完全的重新设计。V3引擎可以被看作是针对时间序列数据场景进行了优化的LSM的简化版本。可以通过LSM的设计理念来理解它。首先,让我们来看一下V3引擎的文件目录结构。

所有的数据都存储在数据目录中。数据目录的顶层是以’b-‘开头的带编号的块。每个块中包含有索引、块目录和meta.json文件。每个”chunks”目录中存储着不同系列数据点的原始块。V3的块和V2的块是相同的,唯一的区别是v3的块包含不止一个时间线,而是多个时间线。索引位于块下方,可以根据标签快速定位时间线和数据块。meta.json是一个简单的描述文件,用于保持有关块的可读信息,以便人们可以轻松理解存储状态和其中包含的数据。为了理解V3引擎的设计,只需要理解几个问题。1、块文件的存储格式是什么?2、如何存储索引以实现快速搜索?3、为什么最后一个块中包含的不是块而是”wal”目录?
设计的思路

普罗米修斯将数据按照时间维度分割成多个不重叠的块。每个块作为一个完全独立的数据库,包含该时间窗口的时间序列数据。每个数据块在转储到块文件后就不可变了。新的数据只能写入到最新的块中。所有新的数据将被写入到内存数据库中。为了防止数据丢失,所有输入数据也会被写入到临时写入日志(WAL)中。
V3完全借鉴了LSM的设计理念,并基于时序数据的特征进行了一些优化。它具有许多优点。
1、在查询时间范围的数据时,可以快速排除不相关的块。每个块都有独立的索引,因此可以有效解决V2的“系列转换”问题。
2、由于数据存储在内存中的块文件中,因此可以高效连续地写入更大的块数据,适用于SSD和HDD。
3、与V2类似,最近的数据也保留在内存中。最近的数据是访问频率较高的热数据。通过将这些数据保留在内存中,可以进行最有效的数据查询。
4、对于旧数据的删除非常简单且高效。只需要删除少量的目录即可。

在V3的版本中,数据块会以两个小时为适度间隔进行切割。这个间隔既不能太长也不能太短。若间隔过长,则需保存超过两个小时的数据,需要更大的内存空间。若间隔过短,则会有过多的数据块,需要查询过多的文件。两个小时的间隔会综合考虑后决定。然而,如果需要查询更大时间范围的数据,就无法避免查询多个文件。比如在查询一周的数据时,可能需要查询84个文件。类似LSM一样,在V3中也采用了压缩策略来优化查询。将小的数据块合并成较大的数据块。此外,还可以删除被删除的数据,重构样本块以提高查询性能,甚至可以在数据中途进行修正。被引用的文章中并没有详细介绍V3的压缩策略。如果感兴趣的话,可以看看InfluxDB是如何实现这一点的。InfluxDB提供了适用于各种情况的压缩策略。

以下是 V3 中过期数据删除的模式图示,比 V2 更简单。如果整个数据块的有效期已过,可以直接删除文件夹。然而,如果仅部分数据已过期,无法删除整个文件夹。需要等待所有数据的有效期过期,或进行压缩。值得注意的是,数据越旧,压缩过的数据块就会继续被压缩,导致数据块变得更大。为防止数据块变得过大跨越整个数据库,需要设定一个上限。通常,此上限基于保留窗口进行设置。
基本上,Prometheus的数据存储设计就是这样了。它相当明确且简单。与其他TSDB一样,Prometheus也有索引。V3索引结构相对简单。在这里,我想直接使用引用文章中提供的示例。


根据该文章的描述,V3并不像V2一样使用LevelDB。在持久化块中,索引是不变的。对于最近写入的块,V3会将所有索引保存在内存中并保持内存结构。这些索引在块关闭时会被持久化到磁盘上的文件中。这非常简单。通过维护时间轴和ID之间的映射关系,以及标签和ID列表之间的映射关系,可以确保高查询效率。Prometheus假设在实际世界的数据集中,约有440万个系列和约12个标签,每个标签具有5,000个以下的唯一标签。这些都占用非常少的内存。InfluxDB也采用了类似的策略,但其他TSDB使用ElasticSearch作为索引引擎。
概要的中文意思是简要陈述或总结。
如果时间序列数据中的写入操作大于读取操作,LSM存储引擎会有许多优点。像Hbase和Cassandra这样的TSDB中,也有直接基于开源LSM引擎的分布式数据库。还有一些基于LevelDB和RocksDB开发的TSDB。此外,还有完全自主开发的TSDB,如InfluxDB和Prometheus。之所以存在这么多类型的TSDB,是因为仍然有许多可以优化时间序列数据特定场景的方法,例如索引和压缩策略。Prometheus V3引擎的设计理念与InfluxDB非常相似,他们的优化思路非常一致。如果有新的需求出现,可能会有进一步的变更。
這個部落格是從英文版翻譯而來。您可以在這裡查看原文。我們使用部分機器翻譯,如果有任何錯誤,煩請指正,謝謝。
阿里巴巴云拥有两个数据中心在日本,并且是亚太地区第一大云基础设施供应商(2019 年加特纳报告)拥有超过60个可用区。
您可以通过此链接查看阿里巴巴云的详细信息。
阿里巴巴云日本官方页面。