运行 Spark 作业的副作用是否有意义?

use*_*688 5 apache-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))
Run Code Online (Sandbox Code Playgroud)

zer*_*323 5

一般来说,这是没有意义的:

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

    假设您的情况有一个 Slow SEND_OVER_NETWORK。如果您map在整个分区上使用几乎所有的块处理。您可以使用 进入较低级别mapPartitions,进行SEND_OVER_NETWORK异步,并仅在处理整个分区时返回。它更好,但仍然不是最理想的。

    您可以增加分区数量,但这意味着更高的簿记开销,因此最终您可能会使情况变得更糟而不是更好。

  3. Spark API 主要是为无副作用操作而设计的。它使得表达不适合该模型的操作变得困难。

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

    可以跟踪 Spark 主逻辑之外的每个分区的本地状态,但如果您做到了这一点,则表明 Spark 不是正确的工具。