mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
PRF:20170410 Writing a Time Series Database from Scratch.md
PART 5 @LuuMing 太辛苦了,这篇这么长,这么专业都翻译的这么好。我连校对都分了五次才逐步校对完,这还是逼着自己完成的。
This commit is contained in:
parent
fa8226e112
commit
3c9fce50ed
@ -354,76 +354,95 @@ __name__="requests_total" -> [ 9999, 1000, 1001, 2000000, 2000001, 2000002,
|
||||
|
||||
### 基准测试
|
||||
|
||||
我发起了一个最初版本的基准测试,它基于现实世界数据集中提取的大约 440 万个序列描述符,并生成合成数据点对应到这些序列中。这个方法仅仅测试单独的存储系统,快速的找到高并发负载场景下的运行瓶颈和触发死锁至关重要。
|
||||
我从存储的基准测试开始了初步的开发,它基于现实世界数据集中提取的大约 440 万个序列描述符,并生成合成数据点以输入到这些序列中。这个阶段的开发仅仅测试了单独的存储系统,对于快速找到性能瓶颈和高并发负载场景下的触发死锁至关重要。
|
||||
|
||||
在概念性的运用完成之后,基准测试能够在我的 Macbook Pro 上维持每秒 2000 万的吞吐量—并且所有 Chrome 的页面和 Slack 都保持着运行。因此,尽管这听起来都很棒,它这也表明推动这项测试没有的进一步价值。(或者是没有在高随机环境下运行)。毕竟,它是合成的数据,因此在除了好的第一印象外没有多大价值。比起最初的设计目标高出 20 倍,是时候将它部署到真正的 Prometheus 服务器上了,为它添加更多现实环境中的开销和场景。
|
||||
在完成概念性的开发实施之后,该基准测试能够在我的 Macbook Pro 上维持每秒 2000 万的吞吐量 —— 并且这都是在打开着十几个 Chrome 的页面和 Slack 的时候。因此,尽管这听起来都很棒,它这也表明推动这项测试没有的进一步价值(或者是没有在高随机环境下运行)。毕竟,它是合成的数据,因此在除了良好的第一印象外没有多大价值。比起最初的设计目标高出 20 倍,是时候将它部署到真正的 Prometheus 服务器上了,为它添加更多现实环境中的开销和场景。
|
||||
|
||||
我们实际上没有可重复的 Prometheus 基准测试配置,特别是对于不同版本的 A/B 测试。亡羊补牢为时不晚,[现在就有一个了][11]!
|
||||
我们实际上没有可重现的 Prometheus 基准测试配置,特别是没有对于不同版本的 A/B 测试。亡羊补牢为时不晚,[不过现在就有一个了][11]!
|
||||
|
||||
工具可以让我们声明性地定义基准测试场景,然后部署到 AWS 的 Kubernetes 集群上。尽管对于全面的基准测试来说不是最好环境,但它肯定比 64 核 128GB 内存的专用<ruby>裸机服务器<rt>bare metal servers</rt></ruby>更能反映出用户基础。我们部署两个 Prometheus 1.5.2 服务器(V2 存储系统)和两个从 2.0 分支继续开发的 Prometheus (V3 存储系统) 。每个 Prometheus 运行在配备 SSD 的专用服务器上。我们将横向扩展的应用部署在了工作节点上,并且让其暴露典型的微服务量。此外,Kubernetes 集群本身和节点也被监控着。整个配置由另一个 Meta-Prometheus 所监督,它监控每个 Prometheus 的健康状况和性能。为了模拟序列分流,微服务定期的扩展和收缩来移除旧的 pods 并衍生新的 pods,生成新的序列。查询负载通过典型的查询选择来模拟,对每个 Prometheus 版本都执行一次。
|
||||
我们的工具可以让我们声明性地定义基准测试场景,然后部署到 AWS 的 Kubernetes 集群上。尽管对于全面的基准测试来说不是最好环境,但它肯定比 64 核 128GB 内存的专用<ruby>裸机服务器<rt>bare metal servers</rt></ruby>更能反映出我们的用户群体。
|
||||
|
||||
总体上,伸缩与查询的负载和采样频率一样极大的超出了 Prometheus 的生产部署。例如,我们每隔 15 分钟换出 60% 的微服务实例去产生序列分流。在现代的基础设施上,一天仅大约会发生 1-5 次。这就保证了我们的 V3 设计足以处理未来几年的工作量。就结果而言,Prometheus 1.5.2 和 2.0 之间的性能差异在不温和的环境下会变得更大。
|
||||
总而言之,我们每秒从 850 个暴露 50 万数据的目标里收集了大约 11 万份样本。
|
||||
我们部署了两个 Prometheus 1.5.2 服务器(V2 存储系统)和两个来自 2.0 开发分支的 Prometheus (V3 存储系统)。每个 Prometheus 运行在配备 SSD 的专用服务器上。我们将横向扩展的应用部署在了工作节点上,并且让其暴露典型的微服务度量。此外,Kubernetes 集群本身和节点也被监控着。整套系统由另一个 Meta-Prometheus 所监督,它监控每个 Prometheus 的健康状况和性能。
|
||||
|
||||
在此配置运行一段时间之后,我们可以看一下数字。我们评估了两个版本在 12 个小时之后到达稳定时的几个指标。
|
||||
为了模拟序列分流,微服务定期的扩展和收缩来移除旧的 pod 并衍生新的 pod,生成新的序列。通过选择“典型”的查询来模拟查询负载,对每个 Prometheus 版本都执行一次。
|
||||
|
||||
总体上,伸缩与查询的负载以及采样频率极大的超出了 Prometheus 的生产部署。例如,我们每隔 15 分钟换出 60% 的微服务实例去产生序列分流。在现代的基础设施上,一天仅大约会发生 1-5 次。这就保证了我们的 V3 设计足以处理未来几年的工作负载。就结果而言,Prometheus 1.5.2 和 2.0 之间的性能差异在极端的环境下会变得更大。
|
||||
|
||||
总而言之,我们每秒从 850 个目标里收集大约 11 万份样本,每次暴露 50 万个序列。
|
||||
|
||||
在此系统运行一段时间之后,我们可以看一下数字。我们评估了两个版本在 12 个小时之后到达稳定时的几个指标。
|
||||
|
||||
> 请注意从 Prometheus 图形界面的截图中轻微截断的 Y 轴
|
||||
|
||||
![Heap usage GB](https://fabxc.org/blog/2017-04-10-writing-a-tsdb/assets/heap_usage.png)
|
||||
> 堆内存使用(GB)
|
||||
![Heap usage GB](https://fabxc.org/tsdb/assets/heap_usage.png)
|
||||
|
||||
内存资源使用对用户来说是最为困扰的问题,因为它相对的不可预测且能够导致进程崩溃。
|
||||
显然,被查询的服务器正在消耗内存,这极大程度上归咎于查询引擎的开销,这一点可以当作以后优化的主题。总的来说,Prometheus 2.0 的内存消耗减少了 3-4 倍。大约 6 小时之后,在 Prometheus 1.5 上有一个明显的峰值,与我们设置 6 小时的保留边界相对应。因为删除操作成本非常高,所以资源消耗急剧提升。这一点在下面几张图中均有体现。
|
||||
*堆内存使用(GB)*
|
||||
|
||||
![CPU usage cores](https://fabxc.org/blog/2017-04-10-writing-a-tsdb/assets/cpu_usage.png)
|
||||
> CPU 使用(核心/秒)
|
||||
内存资源的使用对用户来说是最为困扰的问题,因为它相对的不可预测且可能导致进程崩溃。
|
||||
|
||||
类似的模式展示 CPU 使用,但是查询的服务器与非查询的服务器之间的差异尤为明显。每秒获取大约 11 万个数据需要 0.5 核心/秒的 CPU 资源,比起评估查询所花费的时间,我们新的存储系统 CPU 消耗可忽略不计。
|
||||
显然,查询的服务器正在消耗内存,这很大程度上归咎于查询引擎的开销,这一点可以当作以后优化的主题。总的来说,Prometheus 2.0 的内存消耗减少了 3-4 倍。大约 6 小时之后,在 Prometheus 1.5 上有一个明显的峰值,与我们设置的 6 小时的保留边界相对应。因为删除操作成本非常高,所以资源消耗急剧提升。这一点在下面几张图中均有体现。
|
||||
|
||||
![Disk writes](https://fabxc.org/blog/2017-04-10-writing-a-tsdb/assets/disk_writes.png)
|
||||
> 磁盘写入(MB/秒)
|
||||
![CPU usage cores](https://fabxc.org/tsdb/assets/cpu_usage.png)
|
||||
|
||||
图片展示出的磁盘利用率取得了令人意想不到的提升。这就清楚的展示了为什么 Prometheus 1.5 很容易造成 SSD 损耗。我们看到最初的上升发生在第一个块被持久化到序列文件中的时期,然后一旦删除操作引发了重写就会带来第二个上升。令人惊讶的是,查询的服务器与非查询的服务器显示出了非常不同的利用率。
|
||||
Prometheus 2.0 on the other hand, merely writes about a single Megabyte per second to its write ahead log. Writes periodically spike when blocks are compacted to disk. Overall savings: staggering 97-99%.Prometheus 2.0 在另一方面,每秒仅仅写入大约一兆字节的日志文件。当块压缩到磁盘之时,写入定期地出现峰值。这在总体上节省了:惊人的 97-99%。
|
||||
*CPU 使用(核心/秒)*
|
||||
|
||||
![Disk usage](https://fabxc.org/blog/2017-04-10-writing-a-tsdb/assets/disk_usage.png)
|
||||
> 磁盘大小(GB)
|
||||
类似的模式也体现在 CPU 使用上,但是查询的服务器与非查询的服务器之间的差异尤为明显。每秒获取大约 11 万个数据需要 0.5 核心/秒的 CPU 资源,比起评估查询所花费的 CPU 时间,我们的新存储系统 CPU 消耗可忽略不计。总的来说,新存储需要的 CPU 资源减少了 3 到 10 倍。
|
||||
|
||||
与磁盘写入密切相关的是总磁盘空间占用量。由于我们对样本几乎使用了相同的压缩算法,因此磁盘占用量应当相同。在更为稳定的配置中,这样做很大程度上是正确地,但是因为我们需要处理高序列分流,所以还要考虑每个序列的开销。
|
||||
如我们所见,Prometheus 1.5 在两个版本达到稳定状态之前,使用的存储空间因保留操作而急速上升。Prometheus 2.0 似乎在每个序列上具有更少的消耗。我们可以清楚的看到写入日志线性地充满整个存储空间,然后当压缩完成后立刻掉下来。事实上对于两个 Prometheus 2.0 服务器,它们的曲线并不是完全匹配的,这一点需要进一步的调查。
|
||||
![Disk writes](https://fabxc.org/tsdb/assets/disk_writes.png)
|
||||
|
||||
*磁盘写入(MB/秒)*
|
||||
|
||||
迄今为止最引人注目和意想不到的改进表现在我们的磁盘写入利用率上。这就清楚的说明了为什么 Prometheus 1.5 很容易造成 SSD 损耗。我们看到最初的上升发生在第一个块被持久化到序列文件中的时期,然后一旦删除操作引发了重写就会带来第二个上升。令人惊讶的是,查询的服务器与非查询的服务器显示出了非常不同的利用率。
|
||||
|
||||
在另一方面,Prometheus 2.0 每秒仅向其预写日志写入大约一兆字节。当块被压缩到磁盘时,写入定期地出现峰值。这在总体上节省了:惊人的 97-99%。
|
||||
|
||||
![Disk usage](https://fabxc.org/tsdb/assets/disk_usage.png)
|
||||
|
||||
*磁盘大小(GB)*
|
||||
|
||||
与磁盘写入密切相关的是总磁盘空间占用量。由于我们对样本(这是我们的大部分数据)几乎使用了相同的压缩算法,因此磁盘占用量应当相同。在更为稳定的系统中,这样做很大程度上是正确地,但是因为我们需要处理高的序列分流,所以还要考虑每个序列的开销。
|
||||
|
||||
如我们所见,Prometheus 1.5 在这两个版本达到稳定状态之前,使用的存储空间因其保留操作而急速上升。Prometheus 2.0 似乎在每个序列上的开销显著降低。我们可以清楚的看到预写日志线性地充满整个存储空间,然后当压缩完成后瞬间下降。事实上对于两个 Prometheus 2.0 服务器,它们的曲线并不是完全匹配的,这一点需要进一步的调查。
|
||||
|
||||
前景大好。剩下最重要的部分是查询延迟。新的索引应当优化了查找的复杂度。没有实质上发生改变的是处理数据的过程,例如 `rate()` 函数或聚合。这些就是查询引擎要做的东西了。
|
||||
|
||||
![Query latency](https://fabxc.org/blog/2017-04-10-writing-a-tsdb/assets/query_latency.png)
|
||||
> 第 99 个百分位查询延迟(秒)
|
||||
![Query latency](https://fabxc.org/tsdb/assets/query_latency.png)
|
||||
|
||||
数据完全符合预期。在 Prometheus 1.5 上,查询延迟随着存储的数据而增加。只有在保留操作开始且旧的序列被删除后才会趋于稳定。作为对比,Prometheus 从一开始就保持在合适的位置。
|
||||
我们需要花一些心思在数据是如何被采集上,对服务器发出的查询请求通过估计以下方面被选中:查询范围和即时查询的组合,进行或轻或重的计算,访问或多或少的文件。它并不需要代表真实世界里查询的分布。也不能代表冷数据的查询性能,我们可以假设所有的样本数据都是保存在内存中的热数据。
|
||||
尽管如此,我们可以相当自信地说,整体查询效果对序列分流变得非常有弹性,并且提升了高压基准测试场景下 4 倍的性能。在更为静态的环境下,我们可以假设查询时间大多数花费在了查询引擎上,改善程度明显较低。
|
||||
*第 99 个百分位查询延迟(秒)*
|
||||
|
||||
![Ingestion rate](https://fabxc.org/blog/2017-04-10-writing-a-tsdb/assets/ingestion_rate.png)
|
||||
> 摄入的样本/秒
|
||||
数据完全符合预期。在 Prometheus 1.5 上,查询延迟随着存储的序列而增加。只有在保留操作开始且旧的序列被删除后才会趋于稳定。作为对比,Prometheus 2.0 从一开始就保持在合适的位置。
|
||||
|
||||
最后,快速地看一下不同 Prometheus 服务器的摄入率。我们可以看到搭载 V3 存储系统的两个服务器具有相同的摄入速率。在几个小时之后变得不稳定,这是因为不同的基准测试集群节点由于高负载变得无响应,与 Prometheus 实例无关。(两点之前的曲线完全匹配这一事实希望足够具有说服力)
|
||||
尽管还有更多 CPU 和内存资源,两个 Prometheus 1.5.2 服务器的摄入率大大降低。序列分流高压导致了无法采集更多的数据。
|
||||
我们需要花一些心思在数据是如何被采集上,对服务器发出的查询请求通过对以下方面的估计来选择:范围查询和即时查询的组合,进行更轻或更重的计算,访问更多或更少的文件。它并不需要代表真实世界里查询的分布。也不能代表冷数据的查询性能,我们可以假设所有的样本数据都是保存在内存中的热数据。
|
||||
|
||||
尽管如此,我们可以相当自信地说,整体查询效果对序列分流变得非常有弹性,并且在高压基准测试场景下提升了 4 倍的性能。在更为静态的环境下,我们可以假设查询时间大多数花费在了查询引擎上,改善程度明显较低。
|
||||
|
||||
![Ingestion rate](https://fabxc.org/tsdb/assets/ingestion_rate.png)
|
||||
|
||||
*摄入的样本/秒*
|
||||
|
||||
最后,快速地看一下不同 Prometheus 服务器的摄入率。我们可以看到搭载 V3 存储系统的两个服务器具有相同的摄入速率。在几个小时之后变得不稳定,这是因为不同的基准测试集群节点由于高负载变得无响应,与 Prometheus 实例无关。(两个 2.0 的曲线完全匹配这一事实希望足够具有说服力)
|
||||
|
||||
尽管还有更多 CPU 和内存资源,两个 Prometheus 1.5.2 服务器的摄入率大大降低。序列分流的高压导致了无法采集更多的数据。
|
||||
|
||||
那么现在每秒可以摄入的<ruby>绝对最大<rt>absolute maximum</rt></ruby>样本数是多少?
|
||||
|
||||
我不知道——而且故意忽略。
|
||||
但是现在你可以摄取的每秒绝对最大样本数是多少?
|
||||
|
||||
存在的很多因素都会影响 Prometheus 数据流量,而且没有一个单独的数字能够描述捕获质量。最大摄入率在历史上是一个导致基准出现偏差的度量量,并且忽视了更多重要的层面,例如查询性能和对序列分流的弹性。关于资源使用线性增长的大致猜想通过一些基本的测试被证实。很容易推断出其中的原因。
|
||||
我不知道 —— 虽然这是一个相当容易的优化指标,但除了稳固的基线性能之外,它并不是特别有意义。
|
||||
|
||||
我们的基准测试模拟了高动态环境下 Prometheus 的压力,它比起真实世界中的更大。结果表明,虽然运行在没有优化的云服务器上,但是已经超出了预期的效果。
|
||||
有很多因素都会影响 Prometheus 数据流量,而且没有一个单独的数字能够描述捕获质量。最大摄入率在历史上是一个导致基准出现偏差的度量,并且忽视了更多重要的层面,例如查询性能和对序列分流的弹性。关于资源使用线性增长的大致猜想通过一些基本的测试被证实。很容易推断出其中的原因。
|
||||
|
||||
> 注意:在撰写本文的同时,Prometheus 1.6 正在开发当中,它允许更可靠地配置最大内存使用量,并且可能会显著地减少整体的消耗,提高 CPU 使用率。我没有重复进行测试,因为整体结果变化不大,尤其是面对高序列分流的情况。
|
||||
我们的基准测试模拟了高动态环境下 Prometheus 的压力,它比起真实世界中的更大。结果表明,虽然运行在没有优化的云服务器上,但是已经超出了预期的效果。最终,成功将取决于用户反馈而不是基准数字。
|
||||
|
||||
> 注意:在撰写本文的同时,Prometheus 1.6 正在开发当中,它允许更可靠地配置最大内存使用量,并且可能会显著地减少整体的消耗,有利于稍微提高 CPU 使用率。我没有重复对此进行测试,因为整体结果变化不大,尤其是面对高序列分流的情况。
|
||||
|
||||
### 总结
|
||||
|
||||
Prometheus 开始应对高基数序列与单独样本的吞吐量。这仍然是一项富有挑战性的任务,但是新的存储系统似乎向我们展示了未来的一些好东西:<ruby>超大规模<rt>hyper-scale</rt></ruby>,<ruby>高收敛度<rt>hyper-convergent</rt></ruby>,GIFEE 基础设施。好吧,它似乎运行的不错。
|
||||
Prometheus 开始应对高基数序列与单独样本的吞吐量。这仍然是一项富有挑战性的任务,但是新的存储系统似乎向我们展示了未来的一些好东西。
|
||||
|
||||
第一个配备 V3 存储系统的 [alpha 版本 Prometheus 2.0][12] 已经可以用来测试了。在早期阶段预计还会出现崩溃,死锁和其他 bug。
|
||||
|
||||
存储系统的代码可以在[这个单独的项目中找到][13]。Prometheus 对于寻找高效本地存储时间序列数据库的应用来说可能非常有用,之一点令人非常惊讶。
|
||||
存储系统的代码可以在[这个单独的项目中找到][13]。Prometheus 对于寻找高效本地存储时间序列数据库的应用来说可能非常有用,这一点令人非常惊讶。
|
||||
|
||||
> 这里需要感谢很多人作出的贡献,以下排名不分先后:
|
||||
|
||||
@ -431,16 +450,15 @@ Prometheus 开始应对高基数序列与单独样本的吞吐量。这仍然是
|
||||
|
||||
> Wilhelm Bierbaum 对新设计不断的建议与见解作出了很大的贡献。Brian Brazil 不断的反馈确保了我们最终得到的是语义上合理的方法。与 Peter Bourgon 深刻的讨论验证了设计并形成了这篇文章。
|
||||
|
||||
> 别忘了我们整个 CoreOS 团队与公司对于这项工作的赞助与支持。感谢所有那些听我一遍遍唠叨 SSD,浮点数,序列化格式的同学。
|
||||
|
||||
> 别忘了我们整个 CoreOS 团队与公司对于这项工作的赞助与支持。感谢所有那些听我一遍遍唠叨 SSD、浮点数、序列化格式的同学。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fabxc.org/blog/2017-04-10-writing-a-tsdb/
|
||||
|
||||
作者:[Fabian Reinartz ][a]
|
||||
译者:[译者ID](https://github.com/LuuMing)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
作者:[Fabian Reinartz][a]
|
||||
译者:[LuuMing](https://github.com/LuuMing)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user