亚马逊AWS官方博客
s3logs-parquet – 高效处理海量 S3 访问日志
Amazon S3 因其安全性、可靠性、低成本和可编程性而受到广大使用者的欢迎,特别是对于数据湖、AI/ML、HCLS(医疗保健和生命科学)等工作负载。 每天有大量数据注入 Amazon S3 以进行数据持久化和进一步分析工作。 在这些数据上,我们的客户构建了各种复杂的数据处理管道,同时,也需要一种可追溯且合规的方式追踪 Amazon S3 的访问行为。Amazon S3 对象级别的 API 访问都记录在 Amazon S3 访问日志中,并以文本文件方式投递到日志目标 Amazon S3 存储桶里。
Amazon S3 访问日志记录了对象级别每一次对 Amazon S3 API 请求的详细信息,基于这些基础数据进一步挖掘,可以实现:流量统计、错误排查、安全追踪、合规审计、数据热度辨识等,完善对 Amazon S3 存储桶的精细化管理。
如果我们在 Amazon S3 的存储桶里的数据量达到了 PB 级别,并且每天有上千个数据处理流程在这些数据上执行各种分析任务,那么每天在这些数据上产生的访问日志可能会达到 TB 级别,直接在这些数据上进行后续的访问日志分析操作会比较耗时,并且,如果客户对这些访问日志有长期保留以满足合规要求的时候,需要考虑长期存储的成本问题。
在这篇博客中,我们会介绍开源工具 s3logs-parquet,对 Amazon S3 的访问日志进行转存 parquet 的处理,以实现对 Amazon S3 访问日志的高效查询和长期存储成本优化。
在我们深入工具细节之前,我们先来回顾一下 Amazon S3 访问日志的一些基本性质:
- 尽力交付(Best effort delivery)
在 Amazon S3 的官方文档中对这个机制有详细的描述,简而言之,Amazon S3 不保证访问日志交付到目标桶的时效性,在极少的情况下,访问日志可能会丢失或重复,因此,对于访问日志的获取有实时性要求,或者在审计的场景中,需要保证每次访问请求都被记录到的情况下 AWS CloudTrail 可能是您更好的选择。
关于使用 Amazon S3 访问日志和使用 AWS CloudTrail 的具体差异比较,大家可以参考 re:Invent 2022 STG337 Best practices for managing S3 data at scale, with Bridgewater Associates 中的详细介绍。
- 关于访问日志文件
访问日志文件由每条访问记录组成,包含了访问请求发生的时间,请求的类型,请求的对象等请求的详细信息, 具体的格式在官方文档中有详细描述。在实际的环境中,我们看到 Amazon S3 交付的访问日志文件中的访问日志条数和最终的访问日志文件大小会因实际负载的情况不同而不同,并且,多个不同时间点的访问记录可能会保存在同一个访问日志文件中。
- 按日期分区的交付方式
2023 年 11 月 21 日开始,Amazon S3 访问日志开始支持按日分区投递的方式,客户可以选择按日(UTC+0 的时间基线)来自动归集当日产生的访问日志文件。
为什么选择 Parquet
Apache Parquet 是一种开源文件格式,它以列式格式高效存储数据。提供通过采用列式压缩、不同编码格式、基于数据类型的压缩来高效存储数据的功能。 一般来说,更好的压缩比或跳过不需要的数据块意味着从 Amazon S3 读取更少的字节,从而提高查询性能并降低运行查询的成本。如果您需要使用 Amazon Athena 或 Amazon Redshift Spectrum 等工具在同一数据集上重复执行查询,Apache Parquet 通常是这些场景中推荐的文件格式,以减少查询运行时间,提升查询效率并节省长期存储成本。
s3logs-parquet
为了提升查询的效率,优化长期存储成本, 开源项目 s3logs-parquet 提供了一站式的 Amazon S3 访问日志转存 parquet 的方法。具体来说,整个工具分为两步来处理 Amazon S3 产生的访问日志:归集(aggregation)和转换(transformation)。
归集(aggregation)
在归集阶段,s3logs-parquet 会持续监控新产生的 Amazon S3 访问日志文件,并对每个访问日志文件中的访问日志条目按请求发生的时间进行归集。在这个过程中,如果您希望最终的输出 parquet 文件按照非 UTC+0 的时间进行归集,或者您希望最终输出文件的分区粒度可以细化到小时或者分钟级别,那您可以通过 S3LOGS_STAGGING_PARTITION_TZIF
和 S3LOGS_STAGGING_PARTITION_SECOND
两个参数来控制访问日志条目的归集粒度。
按特定时区对齐和归集访问日志的能力是很多工作在非 UTC+0 时区里用户非常普遍的需求。
转换(transformation)
在转换阶段,s3logs-parquet 会将归集后的访问日志文件转换成 parquet 格式,并使用可定制的前缀格式上传到 Amazon S3 上的指定位置。在需要长期保存输出文件的场景中,可以在上传 Amazon S3 时指定对象的存储类型。 这个过程由 S3LOGS_TRANSFORM_OUTPUT_PREFIX_FMT
和 S3LOGS_TRANSFORM_STORAGE_CLASS
来控制。
实际应用
我们假设一个产生海量 Amazon S3 访问日志的工作负载,包括:
- 一个拥有 30+PB 数据量的 Amazon S3 存储桶,上面运行着大数据的工作负载
- 上千个数据处理管道跑这个 Amazon S3 存储桶上执行,每秒产生 150,000 次请求
- 按以上的请求量,每天约产生 6TB 的 Amazon S3 访问日志文件
典型的部署场景
对于海量 Amazon S3 访问日志的处理场景,我们推荐使用单独的计算节点来运行 s3logs-parquet 进行日志归集和转换的工作,典型的部署架构如下:
- Amazon S3 访问日志交付到目标的 Amazon S3 存储桶,每个新交付的访问日志文件会通过 Amazon S3 事件通知机制产生一个事件通知,并投递到 Amazon SQS 消息队列中。
- 归集进程(s3logd)通过轮询 Amazon SQS 来获取最新的访问日志生成事件。
- 访问日志条目按请求发生的时间进行重新分区,并在 Amazon EC2 实例上暂存。
- 最后转换进程(s3logs transformer)执行从文本格式到 parquet 的格式的转换并上传回 Amazon S3 的指定位置。
Amazon EC2 方面,我们选用一台 m6gd.xlarge 计算实例来进行访问日志处理,执行模拟压力测试,原因有以下两点:
- 展示仅使用有限的资源就能完成海量访问日志的归集和转换工作。
- 通过使用 m6gd.xlarge提供的高性能实例存储暂存归集后的访问日志数据,在成本和处理性能之间取得平衡。
关于 Amazon EC2 的实例存储的特性可以参考官方文档。
模拟压力测试验证
我们使用 Amazon S3 访问日志模拟生成器 来模拟高强度的访问日志交付行为
具体来说,通过以上的配置我们产生:
- 每个访问日志文件包含 15,000 条日志条目
- 每个访问日志文件覆盖随机的 10 分钟之内的访问请求
- 每秒产生约 10 个访问日志文件
- 总共生成 16,000 个访问日志文件
根据上面配置,在测试周期里,我们会产生:
- 每秒钟 10 个访问日志文件 = 每分钟 600 个日志访问文件
- 总共 16,000 个文件 x 每个文件 15,000 行 = 总共 240,000,000 条模拟访问日志
让我们开启处理引擎!
启动归集进程(s3logd)以后,我们的 Amazon EC2 便开始从 Amazon SQS 接收事件并处理新产生的模拟访问日志文件。
从 Amazon SQS 的监控指标里我们观测到,每秒钟 Amazon SQS 里被处理完成的事件数量约为 600 个,符合我们预设的模拟访问日志产生量。
从结果来看,测试周期里,我们总共产生了 16,000 个文件,总大小约 173.3 GB的原始访问日志文件。
再看 parquet 的输出文件,在输出的 Amazon S3 存储桶里我们得到了总共 18 个 parquet 输出文件,总大小 34.7 GB。
因为我们的 parquet 文件采用了 GZIP 的压缩算法,所以 173.3GB / 34.7GB = 4.99
,我们得到了约 5 倍的压缩率。
接下去我们使用 Amazon Athena 来对生成的 parquet 文件进行总条目验证:
测试周期里总共转换了240,000,000 条模拟访问日志,符合我们预期。
在模拟访问日志中,我们为每条记录生成了属于 192.0.0.0/16 地址段的随机 IP 地址,因此可以通过查询 IP 地址,我们可以来验证 parquet 文件的查询效率。
在 240,000,000 条模拟日志中,我们找到了 65025 个不同的 IP 地址,得益于 parquet 的列式存储格式,这个查询动作不需要全量读取完整的数据集,整个扫描读取的数据量为 689.58MB,时间为 2.965 秒,减少了数据的读取量并提升了查询效率。
最后,我们使用 Amazon QuickSight 来查询生成的 parquet 文件中的请求时间“Time”字段,并绘制请求量的线图。模拟访问日志生器为我们生成了峰值约每秒 15,000 次请求的持续压力,通过下面的图标我们可以看到,结果同样符合我们的预期。
成本估算
A | B | C | D | E | F | |
1 | 服务 | 资源项 | 计费用量 | 单价 | 花费 | 描述 |
2 | Amazon EC2 | m6gd.xlarge | 1.5 | $0.1808/hour | $0.2712 | 1.5 小时按需 Amazon EC2 用量 |
3 | Amazon S3 API | GetObject | 16000 | $0.0004/1k | $0.0064 | 从 S3 下载 16000 个访问日志文件 |
4 | PutObject | 366 | $0.005/1k | $0.00183 | 转换成 parquet 文件后推送回 S3(使用 100MB 的分片大小) | |
5 | Amazon SQS | SendMessage | 16000 | $0.40/million | $0.0064 | 由新生成的 Amazon S3 访问日志文件产生的 Amazon S3 事件通知被投递到 Amazon SQS |
6 | ReceiveMessage | 16000 | $0.0064 | 从 Amazon SQS 获取事件消息的操作 (实际的请求数会小于 16000 次,因为每次 API 请求最多可以返回 10 条消息) | ||
7 | DeleteMessage | 16000 | $0.0064 | 当对应对消息被处理完成后,在 Amazon SQS 中删除消息产生的费用 | ||
8 | Message Payload | 16000 | $0.0064 | 每个消息体产生的费用,小于 64KB 的消息按 1 次请求计费 | ||
9 | Amazon S3 storage | s3 logs in raw text | 173.3 | $0.023/GB/mo | $3.9859 | 原始访问日志的月存储成本 |
10 | s3 logs in parquet | 34.7 | $0.7981 | 转换 parquet 以后的访问日志的月存储成本 |
表格中所有的价格按亚马逊云科技 us-east-1 区域的资源的按需价格进行计算,其中:
增加的成本:
- m6gd.xlarge Amazon EC2 实例的成本
- Amazon S3 对原始访问日志和输出 parquet 文件的 API 请求费用
- Amazon SQS API 请求费用和消息体费用
减少的成本:
- 存储成本从 $3.9859 大幅减少到 $0.7981
- 后续对生成 parquet 文件的查询效率提升和数据访问量降低带来的额外成本收益
结论
- 通过使用 s3logs-parquet,海量的 Amazon S3 访问日志可以在有限的资源投入下转换成 parquet 格式。
- 通过压缩并转换成 parquet 格式,可以有效减少 Amazon S3 访问日志的存储空间。
- 通过列式存储的 parquet 格式,可以有效优化大数据分析工具对 Amazon S3 访问日志的分析效率,优化访问的成本。
通过 Amazon S3 访问日志来对 Amazon S3 存储桶进行精细化管理是亚马逊云科技的最佳实践之一,基于访问日志进行访问行为分析场景非常多,在官方文档中列举了一些典型的应用场景,同时,大家也可以观看 Closing the lid on public S3 buckets: Preventing S3 bucket exposure – Part 2 来了解我们的客户是如何通过 Amazon S3 访问日志来进行数据资产管理的。