如何在Apache Beam中高效执行内存密集型流水线 避免SIGKILL故障
如何在Apache Beam中最优执行内存密集型流水线
背景
开发的流水线用于读取Naemura Bird数据集,将其中的图像和标注转换为TF目标检测API要求格式的TF Records格式TF Examples。使用DirectRunner在小样本图像集(4到5张)上测试运行正常。
问题现象
在更大的数据集(共3天数据的第1天,约21GB)上运行流水线时,运行一段时间后崩溃,返回无明确说明的SIGKILL错误。崩溃前观察到内存峰值,推测进程因内存负载过高被系统杀死。
通过strace跟踪了流水线运行,最后几行日志内容如下:
[pid 53702] 10:00:09.105069 poll([{fd=10, events=POLLIN}, {fd=11, events=POLLIN}, {fd=12, events=POLLIN}, {fd=13, events=POLLIN}, {fd=14, events=POLLIN}, {fd=15, events=POLLIN}, {fd=16, events=POLLIN}, {fd=17, events=POLLIN}, {fd=18, events=POLLIN}, {fd=19, events=POLLIN}, {fd=20, events=POLLIN}], 11, 100) = 0 (Timeout) [pid 53702] 10:00:09.205826 poll([{fd=10, events=POLLIN}, {fd=11, events=POLLIN}, {fd=12, events=POLLIN}, {fd=13, events=POLLIN}, {fd=14, events=POLLIN}, {fd=15, events=POLLIN}, {fd=16, events=POLLIN}, {fd=17, events=POLLIN}, {fd=18, events=POLLIN}, {fd=19, events=POLLIN}, {fd=20, events=POLLIN}], 11, 100 <unfinished ...> [pid 53534] 10:00:09.259806 mmap(NULL, 63082496, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3aa43d7000 [pid 53694] 10:00:09.297140 <... clock_nanosleep resumed>NULL) = 0 [pid 53694] 10:00:09.297273 clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=200000000}, <unfinished ...> [pid 53702] 10:00:09.306409 <... poll resumed>) = 0 (Timeout) [pid 53702] 10:00:09.306478 poll([{fd=10, events=POLLIN}, {fd=11, events=POLLIN}, {fd=12, events=POLLIN}, {fd=13, events=POLLIN}, {fd=14, events=POLLIN}, {fd=15, events=POLLIN}, {fd=16, events=POLLIN}, {fd=17, events=POLLIN}, {fd=18, events=POLLIN}, {fd=19, events=POLLIN}, {fd=20, events=POLLIN}], 11, 100) = 0 (Timeout) [pid 53702] 10:00:09.406866 poll([{fd=10, events=POLLIN}, {fd=11, events=POLLIN}, {fd=12, events=POLLIN}, {fd=13, events=POLLIN}, {fd=14, events=POLLIN}, {fd=15, events=POLLIN}, {fd=16, events=POLLIN}, {fd=17, events=POLLIN}, {fd=18, events=POLLIN}, {fd=19, events=POLLIN}, {fd=20, events=POLLIN}], 11, 100 <unfinished ...> [pid 53710] 10:03:55.844910 <... futex resumed>) = ? [pid 53709] 10:03:57.797618 <... futex resumed>) = ? [pid 53708] 10:03:57.797737 <... futex resumed>) = ? [pid 53707] 10:03:57.797793 <... futex resumed>) = ? [pid 53706] 10:03:57.797847 <... futex resumed>) = ? [pid 53705] 10:03:57.797896 <... futex resumed>) = ? [pid 53704] 10:03:57.797983 <... futex resumed>) = ? [pid 53703] 10:03:57.798035 <... futex resumed>) = ? [pid 53702] 10:03:57.798085 +++ killed by SIGKILL +++ [pid 53701] 10:03:57.798124 <... futex resumed>) = ? [pid 53700] 10:03:57.798173 <... futex resumed>) = ? [pid 53699] 10:03:57.798224 <... futex resumed>) = ? [pid 53698] 10:03:57.798272 <... futex resumed>) = ? [pid 53697] 10:03:57.798321 <... accept4 resumed> <unfinished ...>) = ? [pid 53694] 10:03:57.798372 <... clock_nanosleep resumed> <unfinished ...>) = ? [pid 53693] 10:03:57.798426 <... futex resumed>) = ? [pid 53660] 10:03:57.798475 <... futex resumed>) = ? [pid 53641] 10:03:57.798523 <... futex resumed>) = ? [pid 53640] 10:03:57.798572 <... futex resumed>) = ? [pid 53639] 10:03:57.798620 <... futex resumed>) = ? [pid 53710] 10:03:57.798755 +++ killed by SIGKILL +++ [pid 53709] 10:03:57.798792 +++ killed by SIGKILL +++ [pid 53708] 10:03:57.798828 +++ killed by SIGKILL +++ [pid 53707] 10:03:57.798864 +++ killed by SIGKILL +++ [pid 53706] 10:03:57.798900 +++ killed by SIGKILL +++ [pid 53705] 10:03:57.798937 +++ killed by SIGKILL +++ [pid 53704] 10:03:57.798973 +++ killed by SIGKILL +++ [pid 53703] 10:03:57.799008 +++ killed by SIGKILL +++ [pid 53701] 10:03:57.799044 +++ killed by SIGKILL +++ [pid 53700] 10:03:57.799079 +++ killed by SIGKILL +++ [pid 53699] 10:03:57.799116 +++ killed by SIGKILL +++ [pid 53698] 10:03:57.799152 +++ killed by SIGKILL +++ [pid 53697] 10:03:57.799187 +++ killed by SIGKILL +++ [pid 53694] 10:03:57.799245 +++ killed by SIGKILL +++ [pid 53693] 10:03:57.799282 +++ killed by SIGKILL +++ [pid 53660] 10:03:57.799318 +++ killed by SIGKILL +++ [pid 53641] 10:03:57.799354 +++ killed by SIGKILL +++ [pid 53640] 10:03:57.799390 +++ killed by SIGKILL +++ [pid 53639] 10:03:57.910349 +++ killed by SIGKILL +++ 10:03:57.910381 +++ killed by SIGKILL +++
解决方案
本地DirectRunner场景优化
DirectRunner为本地测试设计,本身无自动内存管控能力,可通过以下参数和代码调整解决内存溢出问题:
- 调低并行工作进程数:启动命令中添加参数
--direct_num_workers=N,N根据可用内存调整,16G内存建议设为2,32G内存建议设为4,避免大量图像同时加载到内存。同时添加--direct_running_mode=multi_processing,用多进程模式分散内存压力,避免单进程内存上限触顶。 - 缩小单批次处理量:拆分输入数据集为更小的分片,每10-20张图像输出一个TFRecord文件,避免单批次处理数据量过大导致内存溢出。
- 手动释放无用内存:在DoFn的处理逻辑中,完成图像编码、写入TFExample后,手动删除不需要的图像、标注变量,并主动触发垃圾回收:
import gc class ConvertToTFExampleFn(beam.DoFn): def process(self, element): # 图像读取、处理逻辑 img = load_image(element) tf_example = build_tf_example(img, annotation) # 手动释放无用内存 del img gc.collect() yield tf_example
- 关闭算子融合优化:Beam默认会将相邻算子融合为同一个执行单元,导致中间结果全部缓存在内存,添加启动参数
--experiments=no_optimize=fusion关闭融合,强制中间结果落盘释放内存。
生产级场景方案
如果需要长期处理TB级大规模数据集,建议切换到分布式Runner,例如FlinkRunner、SparkRunner,这类Runtime自带内存管控、负载均衡能力,会自动调度内存资源,避免单节点内存过载。
内容的提问来源于stack exchange,提问作者Smedegaard
相关产品推荐
相关产品推荐

