S3海量对象高效读取方案建议及键前缀范围验证咨询
处理SOREL-20M S3存储桶大规模二进制文件的方案建议
背景
需要读取并处理AWS S3公开存储桶前缀s3://sorel-20m/09-DEC-2020/binaries/中的对象,该存储桶用于网络安全机器学习,包含超过1300万个二进制文件。
示例键如下:
09-DEC-2020/binaries/0000029bfead495a003e43a7ab8406c6209ffb7d5e59dd212607aa358bfd66ea 09-DEC-2020/binaries/000003b99c3d4b9860ad0b0ca43450603e5322f2cca3c9b3d543a2d6440305a0 09-DEC-2020/binaries/00000533148c26bcc09ab44b1acafe32dde93773d4a7e3dbd06c8232db5e437f ... 09-DEC-2020/binaries/fffffac77abc5f22baefd850a753b0e32a8c106f983f84f6b83fb20df465c7ab 09-DEC-2020/binaries/fffffd86f00a5b4547d3b99963cae39781fa015b3f869b3e232858dd6011d062 09-DEC-2020/binaries/fffffee23b47f84cfdf25c43af7707c8ffa94a974e5af9659e3ed67e2e30b80b
已尝试方案及问题
- AWS CLI命令:使用
aws s3 ls全量列出文件需要数小时;尝试用exclude/include参数过滤(如aws s3 cp s3://sorel-20m/09-DEC-2020/binaries/ . --recursive --dryrun --exclude '*' --include '0000029*'),仅能快速返回部分数据但无法完成查询,查询以'fff'开头的键时耗时极长。 - AWS Glue脚本:运行1小时后超时,脚本代码如下:
from pyspark.context import SparkContext from awsglue.context import GlueContext from awsglue.job import Job sc = SparkContext.getOrCreate() glueContext = GlueContext(sc) spark = glueContext.spark_session job = Job(glueContext) df = spark.read.format("binaryFile").option('pathGlobFilter', '0000029*').option("wholeFile","true").load("s3://sorel-20m/09-DEC-2020/binaries") #print(df.count()) df.select('Path').write.csv('s3://my-bucket') job.commit()
拟采用方案
计划用boto3启动16个并行进程,分别处理以0到f开头的键,示例代码如下:
import boto3 import sys session = boto3.Session() s3 = session.resource('s3') bucket = s3.Bucket('sorel-20m') # 脚本接收0到f之间的字符作为参数 first_char = sys.argv[1] prefix = f'09-DEC-2020/binaries/{first_char}' current_objects = bucket.objects.filter(Prefix=prefix) ...
所有操作在EC2上执行,本地网络带宽无瓶颈。
问题解答
是否推荐该方案?
非常推荐这个并行分治的方案,核心原因:
- S3底层的
list_objects_v2接口在指定前缀查询时,效率远高于全量遍历。按首字符(0-f)拆分后,每个进程仅处理1/16的数据集,能大幅降低单任务的遍历压力与耗时。 - 16个并行进程的数量处于合理范围,不会触发S3的请求限流,在EC2上也容易调度和控制。
如何确保所有键均以0到f范围内的字符开头?
从数据集设计和示例键可以看出,这些二进制文件的键后缀是SHA-256哈希值(64位十六进制字符串),而十六进制字符的范围恰好是0-9、a-f(数据集使用小写),因此所有键的首字符必然落在0-f范围内。
若要验证,可做快速抽样:
- 使用boto3调用
list_objects_v2,设置MaxKeys=100获取少量样本 - 提取每个键哈希部分的首字符,检查是否均为十六进制字符
编写脚本时,直接生成['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']这16个前缀,即可覆盖所有可能的键,确保无遗漏。
内容的提问来源于stack exchange,提问作者mherzog
相关产品推荐
相关产品推荐

