tar*_*rka 1 amazon-s3 amazon-web-services amazon-athena amazon-kinesis-firehose
我正在尝试使用AWS Athena为现有平台提供分析。目前的流程是这样的:
/year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/...基本流程有效。但是,这有几个问题......
第一个(也是最重要的)是这些数据是多租户应用程序的一部分。每个事件中都有一个名为account_id. 将发出的每个查询都将由特定帐户发出,我不想扫描每个查询的所有帐户数据。我需要找到一种仅查询相关数据的可扩展方式。我确实考虑过尝试account_id使用Kinesis 来提取并将其用作分区。但是,目前不支持此功能,并且对于超过 10,000 个账户,AWS 20k 分区限制很快就会成为一个问题。
第二个问题是文件大小!AWS 建议文件不要小于 128 MB,因为这会对查询时间产生不利影响,因为执行引擎可能会在打开 Amazon S3 文件的开销上花费更多时间。鉴于 Firehose 的性质,我只能达到每个文件 128 MB 的最大大小。
由于account_id许多原因,您可能不想将这么多帐户用作分区键。我认为您在限制方面很好,每个表的分区限制是 1M,但这并不意味着这是一个好主意。
不过,您可以通过对部分帐户 ID 进行分区来显着减少扫描的数据量。如果您的账户 ID 是均匀分布的(如 AWS 账户 ID),您可以根据前缀进行分区。如果您的帐户 ID 是第一个数字上的数字分区,则每个查询将扫描的数据量将减少 90%,两位数将减少 99% – 同时仍将分区数保持在非常合理的水平。
不幸的是,我不知道如何用 Glue 做到这一点。我发现 Glue 在进行 ETL 时通常非常无用。根据我的经验,即使是简单的事情也很难。我使用 Athena 的 CTAS 功能与一些简单的 S3 操作相结合,将 CTAS 操作生成的数据作为分区添加到现有表中,取得了更大的成功。
如果您想出一种提取帐户 ID 的方法,您还可以对每个帐户使用单独的表进行试验,您可以在数据库中拥有 10 万个表。它与表中的分区没有太大区别,但可能会更快,具体取决于 Athena 如何确定要查询的分区。
不要太担心 128 MB 文件大小的经验法则。拥有大量小文件确实比拥有少量大文件更糟糕——但也确实如此,扫描大量数据以过滤掉一小部分对性能和成本来说非常不利。Athena 可以在一秒钟内提供结果,即使是对数百个只有几 KB 大小的文件的查询。我会担心先确保 Athena 读取正确的数据,然后再考虑理想的文件大小。
如果您告诉我更多有关每个帐户的数据量和帐户的预期生命周期的信息,我可以提供更详细的目标建议。
更新:鉴于 Firehose 不允许您更改输入数据的目录结构,而且 Glue 通常非常糟糕,以及您在评论中提供的附加上下文,我会这样做:
创建一个 Athena 表,其中包含数据中所有属性的列,并将日期作为分区键。这是您的输入表,只会针对此表运行 ETL 查询。不要担心输入数据有单独的年、月和日目录,您只需要一个分区键。将这些作为单独的分区键会使事情复杂化,并且拥有一个意味着它可以是 type DATE,而不是STRING每次要进行日期计算时都必须将三个单独的列组合成一个日期。
使用相同的列创建另一个 Athena 表,但按account_id_prefix日期或月份进行分区。这将是您运行查询的表。account_id_prefix将是您帐户 ID 中的一两个字符 - 您必须测试哪个最有效。您还必须决定是按日期还是更长的时间跨度进行分区。日期将使 ETL 更容易和更便宜,但更长的时间跨度将产生更少和更大的文件,这可以提高查询效率(但可能更昂贵)。
创建执行以下操作的 Step Functions 状态机(在 Lambda 函数中):
CreatePartitionAPI 调用来创建分区(不幸的是,这需要大量信息才能工作,不过您可以运行GetTable调用来获取它。例如使用["2019-04-29"]asValues和"s3://some-bucket/firehose/year=2019/month=04/day=29"as StorageDescriptor.Location。这相当于运行ALTER TABLE some_table ADD PARTITION (date = '2019-04-29) LOCATION 's3://some-bucket/firehose/year=2019/month=04/day=29'– 但通过 Glue 进行比在 Athena 中运行查询更快,更适合 Lambda。GetPartitions创建的临时表中创建的分区,并在查询表中创建相同的分区BatchCreatePartitions。如果您决定在比日期更长的时间进行分区,您仍然可以使用上述过程,但您还需要删除查询表中的分区和 S3 上的相应数据,因为每次更新都会替换现有数据(例如按月分区) ,我建议您尝试一下,您将在整个月内每天创建新文件,这意味着需要删除旧文件)。如果你想每天多次更新你的查询表,它会是一样的。
这看起来很多,看起来像 Glue Crawlers 和 Glue ETL 所做的 - 但根据我的经验,它们并没有让它变得如此简单。
在您的情况下,数据是使用 Hive 样式分区进行分区的,Glue Crawler 了解这一点,但在许多情况下,您不会获得 Hive 样式分区,而只是 Y/M/D(我实际上并不知道 Firehose 可以提供数据)方式,我认为它只做了 Y/M/D)。Glue Crawler 每次运行时也会做很多额外的工作,因为它无法知道数据添加到哪里了,但是您知道从昨天开始添加的唯一分区是昨天的分区,因此减少了爬行一步到位。
Glue ETL 也让事情变得非常困难,与 Lambda 和 Step Functions 相比,它是一项昂贵的服务。您要做的就是将原始数据格式 JSON 转换为 Parquet 并重新分区。据我所知,不可能用比 Athena CTAS 查询更少的代码来做到这一点。即使您可以用更少的代码使用 Glue ETL 进行转换操作,您仍然需要编写大量代码来替换目标表中的分区——因为这是 Glue ETL 和 Spark 根本不支持的东西。
Athena CTAS 并不是真正用来做 ETL 的,我认为我上面概述的方法比它应该复杂得多,但我相信它比尝试做同样的事情(即不断更新)要简单得多并可能根据另一个表中的数据替换表中的分区,而无需每次都重建整个表)。
您通过这个 ETL 过程获得的是,您的摄取不必担心按时间划分的分区,但您仍然可以获得针对查询进行了优化的表。
| 归档时间: |
|
| 查看次数: |
3770 次 |
| 最近记录: |