AWS Glue Python Shell Job处理2GB文件触发MemoryError求助
首先直接回应你的问题:Glue Python Shell并非天生无法处理2GB以上的文件,而是你的全量加载+字符串拼接的处理方式导致了内存过载。Glue Python Shell默认是单进程单线程运行在单个DPU上(1个DPU对应4vCPU、16GB内存),当你把2GB的文件全量读进列表l_data_body,再通过''.join()生成完整字符串时,Python的字符串特性和内存管理会导致内存占用急剧膨胀——因为每个列表元素都是独立的字符串对象(带有额外元数据开销),而join操作会创建一个全新的大字符串,这个过程中需要的临时内存会远超过文件本身的大小,这就是你看到内存飙升到6GB以上的原因。
不用切换到Glue Spark的话,这里有几个针对性的优化方案:
1. 核心优化:流式逐行处理(推荐)
彻底避免把整个文件加载到内存,改用流式读取-处理-写入的模式,每次只处理一行或一小段数据,内存占用会维持在极低水平。
示例代码(基于boto3的S3流式API):
import boto3 from io import BytesIO # 初始化S3客户端 s3 = boto3.client('s3') INPUT_BUCKET = 'your-input-bucket' INPUT_KEY = 'path/to/your/2gb-file.txt' OUTPUT_BUCKET = 'your-output-bucket' OUTPUT_KEY = 'path/to/processed-file.txt' # 流式读取输入文件 with s3.get_object(Bucket=INPUT_BUCKET, Key=INPUT_KEY) as response: input_stream = response['Body'] # 初始化输出缓冲区,达到阈值后批量写入S3 output_buffer = BytesIO() CHUNK_SIZE = 100 * 1024 * 1024 # 100MB批量写入 for line in input_stream.iter_lines(chunk_size=8192, decode_unicode=True): # 执行你的处理逻辑:删除指定行、移除行尾字符等 if '要删除的标记内容' not in line: # 移除行尾指定字符,再添加换行符 processed_line = line.rstrip(';') + '\n' output_buffer.write(processed_line.encode('utf-8')) # 缓冲区达到阈值时写入S3,清空缓冲区 if output_buffer.tell() >= CHUNK_SIZE: s3.put_object(Bucket=OUTPUT_BUCKET, Key=OUTPUT_KEY, Body=output_buffer.getvalue()) output_buffer.seek(0) output_buffer.truncate() # 写入剩余的最后一批数据 if output_buffer.tell() > 0: s3.put_object(Bucket=OUTPUT_BUCKET, Key=OUTPUT_KEY, Body=output_buffer.getvalue())
这种方式的内存占用只会维持在几MB到几十MB,完全不会触发MemoryError。
2. 优化字符串拼接逻辑(如果必须批量处理)
如果你的业务逻辑需要批量处理多行,不要用''.join()处理整个大列表,改用io.StringIO作为可变缓冲区来逐步拼接,它比原生字符串拼接更节省内存:
from io import StringIO buffer = StringIO() for line in filtered_lines: buffer.write(processed_line) final_content = buffer.getvalue()
不过这种方式还是不如流式处理高效,仅适合必须批量处理的场景。
3. 提升Glue Python Shell的资源配置
如果暂时不想修改代码,可以尝试提高Maximum capacity到2(对应2个DPU,32GB内存),更大的内存空间可以容纳全量加载后的内存占用。但这只是治标不治本,长期来看流式处理才是可持续的方案。
4. 压缩文件处理
如果你的输入文件是未压缩的,可以先将其压缩为gzip格式(S3支持直接读取压缩文件),然后在Glue中流式读取并解压处理,压缩后的文件体积会大幅减小,内存占用也会显著降低。
内容的提问来源于stack exchange,提问作者bda

