Python SideInput I/O会降低性能

Python SideInput I/O会降低性能,python,apache-beam,dataflow,Python,Apache Beam,Dataflow,我正在使用Python SDK 2.15.0构建一个数据流管道。在这个管道中,我需要在管道中的几个阶段将附加数据连接到每个元素 所有这些额外的数据都是从Google云存储上的avro文件中读取的(数据流和GCS bucket使用的区域相同),使用map函数组织为键值元组,然后使用pvalue.AsDict()作为侧输入传递给DoFn。在管道执行期间,侧输入数据不会更改 第一次连接(侧输入大小~1MB)进行得非常顺利。但是,第二个连接确实存在性能差的问题。其sideinput的大小约为50MB 数

我正在使用Python SDK 2.15.0构建一个数据流管道。在这个管道中,我需要在管道中的几个阶段将附加数据连接到每个元素

所有这些额外的数据都是从Google云存储上的avro文件中读取的(数据流和GCS bucket使用的区域相同),使用map函数组织为键值元组,然后使用pvalue.AsDict()作为侧输入传递给DoFn。在管道执行期间,侧输入数据不会更改

第一次连接(侧输入大小~1MB)进行得非常顺利。但是,第二个连接确实存在性能差的问题。其sideinput的大小约为50MB

数据流执行图清楚地显示了导致性能差的原因:我的ParDo步骤所消耗的大约90%的时间用于读取端输入。从sideinput读取的数据量超过其实际大小的数量级,即使我只使用了四个工作节点

我能做些什么来防止这种情况?我是否需要以某种方式配置工作缓存大小?在我的DoFn的setup方法中准备额外的数据,而不是将其作为sideinput传递,这样会更好吗

以下是我如何准备侧面输入:

sideinput_1=pvalue.AsDict(p |“读取侧输入数据1”>>beam.io.ReadFromAvro(“gs:/bucket/small_file.avro”,0,False,True)\
|“Prepare sideinput 1”>>beam.Map(λx:(x[“KEY”],x[“VALUE”]))
#为以后的联接准备数据
sideinput_2=pvalue.AsDict(p |“读取侧输入数据2”>>beam.io.ReadFromAvro(“gs://bucket/biger_file.avro”,0,False,True)\
|“准备侧面输入数据2”>>beam.Map(λx:((x[“KEYCOL1”]、x[“KEYCOL2”]、x[“KEYCOL3”])、x)))
使用侧边输入:


匹配=p |“读取地址数据”>>beam.io.Read(beam.io.BigQuerySource(query=sql\u addr,use\u standard\u sql=True))\
|“Join w/sideinput1”>>beam.ParDo(Join1(),sideinput_1)。带有_输出('unmatched',main='matched'))
结果=匹配[“匹配”]|“连接侧输入2”>>beam.ParDo(Join2(),侧输入2)

DoFn process method只包含在side input中查找键,并根据是否存在匹配,向元素添加一些附加数据。

好的,几个月后再讨论,根据获得的经验,让我再做一次尝试:

我非常肯定,侧输入的性能问题归结为内存交换问题。在管道中,还有一些非常相似的连接,但具有显著较小的侧输入。它们以合理的穿墙时间穿墙。但是,所有这些联接的比率(IO字节/sideinput字节)大致相等

当我将实现从ParDo with SideInput切换到时,受影响联接的性能提高了几个数量级。

关于side输入的大小以及何时使用CoGroupByKey而不是带有side输入的DoFn,还有一个问题:

在流媒体模式下,ParDo可用于高达100 MB的侧输入,在批处理模式下可用于1 GB的侧输入:

注意:如果可能的话,将SideInputs用于其中一个联接表实际上很小的任何活动—在流模式下约为100MB,或者在批处理模式下小于1GB。这将表现得更好[…]

我想没有适合每种情况的通用阈值。可能在很大程度上取决于您的管道、机器类型和工人数量等。在我的例子中,我认为由于管道的高度复杂性,阈值较低。它由约40个变换组成,包括几个连接


因此,如果在使用ParDo和Sideinput进行连接时遇到相同的问题,您可能希望尝试CoGroupByKey转换

好的,几个月后再讨论,根据获得的经验,让我再做一次尝试:

我非常肯定,侧输入的性能问题归结为内存交换问题。在管道中,还有一些非常相似的连接,但具有显著较小的侧输入。它们以合理的穿墙时间穿墙。但是,所有这些联接的比率(IO字节/sideinput字节)大致相等

当我将实现从ParDo with SideInput切换到时,受影响联接的性能提高了几个数量级。

关于side输入的大小以及何时使用CoGroupByKey而不是带有side输入的DoFn,还有一个问题:

在流媒体模式下,ParDo可用于高达100 MB的侧输入,在批处理模式下可用于1 GB的侧输入:

注意:如果可能的话,将SideInputs用于其中一个联接表实际上很小的任何活动—在流模式下约为100MB,或者在批处理模式下小于1GB。这将表现得更好[…]

我想没有适合每种情况的通用阈值。可能在很大程度上取决于您的管道、机器类型和工人数量等。在我的例子中,我认为由于管道的高度复杂性,阈值较低。它由约40个变换组成,包括几个连接


因此,如果在使用ParDo和Sideinput进行连接时遇到相同的问题,您可能希望尝试CoGroupByKey转换

好的,一旦我使用pvalue.AsList()传递dict as list,情况似乎好多了。根据源代码文档(),AsList强制实现边输入。似乎阿斯迪克特没有。还有什么办法可以强制字典的物化吗?为了能够以列表的形式传递dict,我将它包装在一个只包含一个元素的列表中——dictionary。我不喜欢这个解决方案,但它的性能确实要好得多。好的,一旦我使用pvalue.AsList()传递dict as list,它似乎会变得更好。根据源代码文档(),AsList强制实现