运行Spark作业的副作用有意义吗



我想运行一个Spark作业,其中每个RDD负责通过网络连接发送特定流量。每个RDD的返回值不是很重要,但我可能会要求他们返回发送的消息数量。重要的部分是网络流量,这基本上是在每个RDD上运行函数的副作用。

在Spark中执行上述任务是个好主意吗?

我正在尝试模拟来自多个来源的网络流量,以测试接收端的数据收集基础设施。我可以手动设置多台机器来运行发送方,但我认为如果我能利用Spark现有的分布式框架,那就太好了。

然而,Spark似乎是为程序"计算"然后"返回"某些东西而设计的,而不是为程序运行其副作用而设计的。我不确定这是否是一个好主意,我很感激其他人的意见。

需要明确的是,我正在考虑以下

IDs = sc.parallelize(range(0, n))
def f(x):
    for i in range(0,100):
        message = make_message(x, i)
        SEND_OVER_NETWORK(message)
    return (x, 100)
IDsOne = IDs.map(f)
counts = IDsOne.reduceByKey(add)
for (ID, count) in counts.collect():
    print ("%i ran %i times" % (ID, count))

一般来说,这没有意义:

  1. Spark是一个重量级的框架。它的核心是这个巨大的机器,它确保数据的正确分发、收集、恢复等。它对整体性能和延迟有重大影响,但在只有副作用的任务中没有任何好处
  2. Spark并发的粒度相对较低,分区是并发的主要单元。在这个级别上,处理变得同步。在完成当前分区之前,不能移动到下一个分区。

    假设在您的情况下,有一个缓慢的SEND_OVER_NETWORK。如果您使用map,那么您几乎会阻塞整个分区上的处理。您可以使用mapPartitions进入较低级别,使SEND_OVER_NETWORK异步,并仅在处理完整个分区后返回。它更好,但仍然不太理想。

    您可以增加分区的数量,但这意味着更高的记账开销,所以在一天结束时,您可以使情况变得更糟而不是更好。

  3. Spark API主要用于无副作用操作。这使得很难表达不适合这种模式的操作。

    可以说更重要的是,Spark只保证每个操作至少执行一次(如果rdd从未实现,则忽略零次)。例如,若应用程序只需要一次语义,事情就会变得棘手,尤其是当您考虑第2点时。

    可以在主Spark逻辑之外跟踪每个分区的本地状态,但如果你做到了,这是一个很好的迹象,表明Spark不是合适的工具。

最新更新