首页 > 解决方案 > 对 AWS Athena 表进行分区以查询具有高基数的 S3 数据的最佳方法

问题描述

我们在 S3 中有一个存储桶,我们每天在其中存储数千条记录(我们最终拥有许多 GB 的数据并不断增加),我们希望能够对它们运行 Athena 查询。

S3 中的数据以如下模式存储:S3://bucket/Category/Subcategory/file. 有多个类别(超过 100 个),每个类别有 1-20 个子类别。我们存储在 S3 中的所有文件(以 apache parquet 格式)都包括传感器读数。有数百万个传感器读数的类别(传感器每天发送数千个读数)和只有几百个读数的类别(传感器平均每月发送几个读数),因此数据在类别之间分布不均。读数包括时间戳、传感器 ID 和值等。

我们希望以尽可能低的成本基于日期和 sensorid 对此存储桶的对象运行 Athena 查询。例如:给我该类别中高于该值的所有读数,或者给我一个类别中所有传感器的最后读数。

对我们的 athena 表进行分区的最佳方法是什么?将我们的读数存储在 S3 中以便 Athena 更容易运行查询的最佳方式是什么?我们可以自由地为每个文件保存一个读数 - 从而产生数百万个文件(能够轻松地对每个传感器 ID 或日期进行分区,但是如果我们每天有数百万个文件,那么性能呢?)或每个文件的多个读数(文件少得多,但无法直接对每个传感器 ID 或日期进行分区,因为并非文件中的所有读数都来自同一个传感器,我们需要按照它们到达的顺序保存它们)。Athena 对我们的案例来说是一个很好的解决方案还是有更好的选择?

任何见解都会有所帮助。先感谢您

标签: amazon-web-servicesamazon-s3amazon-athena

解决方案


一些评论。

Athena 对我们的案例来说是一个很好的解决方案还是有更好的选择?

当您不需要或想要设置更复杂的大数据管道时,Athena 非常棒:您只需将数据放在(或已经拥有)S3 中,就可以立即开始查询它。如果这对你来说已经足够了,那么 Athena 对你来说可能就足够了。

以下是正确回答该特定问题需要考虑的一些重要事项:

  • 你多久查询一次?(即,是否值得让某种大数据集群像 EMR 集群一样不间断地运行?还是在查询时付费更好,即使这意味着每次查询的成本最终可能会更高?)

  • 处理数据集时需要多大的灵活性?(即,Athena 是否提供您需要的所有功能?)

  • 您可能想要“一起”查询的所有数据存储是什么?(即,所有数据现在和将来都在 S3 中吗?或者您是否或将在其他服务中拥有数据,例如 DynamoDB、Redshift、EMR 等......?)

请注意,这些答案都不一定会说“不要使用 Athena” ——它们可能只是建议您未来可能想要遵循的路径。无论如何,由于您的数据已经在 S3 中,采用适合 Athena 的格式,并且您想开始查询它,Athena 现在是一个非常好的选择。

给我该类别中高于该值的所有读数,或者给我一个类别中所有传感器的最后读数。

在这两个示例中,您都按类别过滤。这表明按类别划分可能是一个好主意(无论您是否使用 Athena!)。您已经这样做了,将其/Category/作为 S3 中对象键的一部分。

确定分区方案的良好候选者的一种方法是考虑您将要运行的所有查询(至少是最常见的查询),并按相等或它们正在执行的组检查过滤器。例如,如果您经常使用WHERE XXX = ?.

也许您有更多不同类型的查询,但我不禁注意到您的两个示例都有类别过滤器,因此按类别分区感觉“自然”(就像您所做的那样)。

如果这只是一些巧合,并且按类别过滤并不像示例所建议的那样重要/常见,请随意添加其他常见查询示例的评论。

对我们的 athena 表进行分区的最佳方法是什么?将我们的读数存储在 S3 中以便 Athena 更容易运行查询的最佳方式是什么?

这里几乎没有一个(即最好的)答案。它总是基于数据集的许多特征 (结构;大小;记录数;增长等) 和访问模式 (读写比例;写入类型,例如仅追加、更新、删除等;在大部分查询中存在通用过滤器;您愿意牺牲哪些查询以优化其他查询;等等)

以下是一些一般性指导(不仅适用于 Athena,而且一般来说,如果您决定您可能需要 Athena 以外的其他东西)。

优化大数据环境有两点非常重要:

  1. I/O 很慢。

  2. 将工作均匀地分布在您拥有的所有“处理单元”上,理想情况下充分利用它们中的每一个。

这就是为什么它们很重要。

首先,对于很多“现实世界的访问模式”,I/O 是瓶颈:从存储中读取比在 CPU 中过滤记录要慢很多数量级。所以尽量集中精力减少 I/O 的数量。这意味着既要减少读取的数据,又要减少单个 I/O 操作的数量

其次,如果最终导致多个工人的工作分配不均,可能会出现一些工人很快完成,而另一些工作则需要更长的时间,并且他们的工作无法进一步划分。这也是一个很常见的问题。在这种情况下,您必须等待最慢的工作人员完成,然后才能获得结果。当您确保所有工人都在做相同数量的工作时,他们都会以接近 100% 的速度工作,并且他们都会几乎同时完成工作。这样,您就不必为较慢的等待更长的时间。

帮助实现这些目标的注意事项:

  • 避免文件太大太小

如果您有大量的小文件,那么您的分析系统将不得不发出大量的 I/O 操作来检索数据。这会损害性能(并且在 S3 的情况下,您按请求付费,可能会显着增加成本)。

如果您有少量大文件,根据文件格式和工作单元的特性,您最终可能无法过多地并行化工作,这可能会导致性能下降。

尽量保持文件大小统一,这样您就不会导致工作单元完成得太快然后空闲(在某些查询系统中可能是一个问题,但在其他系统中则不是)。

将文件保持在“每个文件几 GB”的范围内通常是一个不错的选择。

  • 使用压缩(并且更喜欢可拆分的压缩算法)。

压缩文件极大地提高了性能,因为它极大地减少了 I/O:大多数“现实世界”数据集都有很多常见的模式,因此是高度可压缩的。当数据被压缩时,分析系统从存储中读取的时间更少——与读取表单存储所节省的时间相比,在真正查询数据之前解压缩数据所花费的“额外 CPU 时间”可以忽略不计。

请记住,有些压缩算法是不可拆分的:这意味着必须从压缩流的开头开始访问中间的一些字节。使用可拆分压缩算法时,可以从文件中的多个位置开始解压缩。有多种好处,包括 (1) 分析系统可能能够跳过大部分压缩文件并只读取重要的内容,以及 (2) 多个工作人员可能能够同时处理同一个文件,因为他们可以每个人都可以访问文件的不同部分,而不必从头开始检查整个内容。

值得注意的是,gzip是不可拆分的(但是由于您特别提到了 Parquet,请记住 Parquet 格式可能在内部使用 gzip,并且可以独立压缩多个部分并将它们组合成一个 Parquet 文件,从而形成可拆分的结构;换句话说:阅读有关您正在使用的格式的详细信息并检查它是否可拆分)。

  • 使用列式存储。

也就是说,“每列”而不是“每行”存储数据。这样,单个大型 I/O 操作将为您需要的列检索大量数据,而不是检索几条记录的所有列然后丢弃不必要的列(读取不必要的数据会极大地损害性能)。

不仅可以减少从存储中读取的数据量,还可以提高 CPU 处理该数据的速度,因为您将拥有大量包含有用数据的内存页面,并且 CPU 执行一组非常简单的操作— 这可以显着提高 CPU 级别的性能。

此外,通过按列组织数据,通常可以实现更好的压缩,从而减少 I/O。

你提到 Parquet,所以这被照顾了。如果您想更改它,请记住使用列式存储。

  • 考虑一下为了决定分区方案而需要的查询。

就像上面关于类别过滤的示例一样,这在您作为示例提供的两个查询中都存在。

当你像上面的例子那样进行分区时,你将大大减少 I/O:查询系统将准确地知道它需要检索哪些文件,并且将避免读取整个数据集。

你去吧。

这些只是一些高级指导。要获得更具体的指导,有必要更多地了解您的数据集,但这至少应该让您开始问自己正确的问题。


推荐阅读