独立集群 + Docker 上的 PySpark 性能不佳

Posted

技术标签:

【中文标题】独立集群 + Docker 上的 PySpark 性能不佳【英文标题】:Poor PySpark performance on Stand-alone cluster + Docker 【发布时间】:2016-08-23 09:55:45 【问题描述】:

我在 AWS c4.8xlarge 机器(一台或多台)上的 Docker 容器内运行 Spark 从站,与仅在笔记本电脑上使用 multiprocessing(使用四核 Intel i7)相比,我很难获得预期的性能-6820HQ)。 (请参阅下面的编辑,相同的硬件也会产生巨大的开销)

我正在寻找可以在单线程、多进程或分布式 Spark 场景中工作的“多处理器”水平扩展分析模型训练的解决方案:

class Multiprocessor:
    # ...

    def map(self, func, args):
        if has_pyspark:
            n_partitions = min(len(args), 1000)
            return _spark_context.parallelize(args, n_partitions).map(func).collect()
        elif self.max_n_parallel > 1:
            with multiprocessing.Pool(self.max_n_parallel) as pool:
                return list(pool.map(func, args))
        else:
            return list(map(func, args))

如您所见,Spark 的作用是分发计算并简单地检索结果,parallelize().map() 是唯一使用的 API。 args 只是一个整数 id 元组的列表,没有太重。

我正在使用 Docker 1.12.1 (--net host)、Spark 2.0.0(独立集群)、Hadoop 2.7、Python 3.5 和 openjdk-7。相同训练数据集的结果,每次运行都受 CPU 限制:

5.4 分钟,本地多处理(4 个进程) 5.9 分钟,四个 c4.8xlarge 从属设备(每个使用 10 个内核) 本地 Spark 6.9 分钟(master local[4]) 7.7 分钟,三个 c4.8xlarge 从属设备(每个使用 10 个内核) 25 分钟,单个 c4.8xlarge 从属设备(10 核)(!) 27 分钟,本地 VM Spark 从站(4 核)(!)

所有 36 个虚拟 CPU 似乎都在使用,平均负载为 250 - 350。要映射大约 360 个args 值,它们的处理时间为 15 - 45 秒(第 25 和第 75 个百分位数)。 CG时间是微不足道的。甚至尝试返回“空”结果以避免网络开销,但这并不影响总时间。通过 *** Ping 到 AWS 需要 50 - 60 毫秒。

关于我应该研究哪些其他指标的任何提示,我觉得我在某处浪费了大量的 CPU 周期。我真的很想围绕 Spark 构建架构,但基于这些 PoC,至少 AWS 上的机器太贵了。必须使用我可以访问的其他本地硬件进行测试。

编辑 1:在笔记本电脑上的 Linux VM 上进行测试,使用独立集群需要 27 分钟,比使用 local[4] 多 20 分钟。

编辑 2:每个从属“核心”似乎有 7 个 pyspark 守护进程,所有这些都占用大量 CPU 资源。这是预期的行为吗? (图片来自笔记本电脑的虚拟机)

编辑 3:实际上,即使只启动一个单核从属设备也会发生这种情况,我得到 100% 的 CPU 利用率。根据this answer 红色表示内核级线程,Docker 可以在这里发挥作用吗?无论如何,我不记得在使用 Python 2.7 进行原型设计时看到过这个问题,我得到的性能开销非常小。现在更新到 Java OpenJDK 8,它没有任何区别。 Spark 1.5.0 和 Hadoop 2.6 也得到了相同的结果。

编辑 4:我可以追踪到默认情况下 scipy.linalg.cho_factor 使用所有可用内核,这就是为什么我看到即使 Spark slave 使用一个内核时 CPU 使用率也很高的原因。必须进一步调查...

最终编辑:这个问题似乎与 AWS 或 Spark 无关,我在 Docker 容器中的独立 Python 上的性能很差。见我的answer below。

【问题讨论】:

【参考方案1】:

有同样的问题 - 对我来说,根本原因是内存分配。 确保为 spark 实例分配足够的内存。 在 start-slave.sh - 运行 --help 以获取内存选项(默认为每个节点 1GB,无论机器中的实际内存如何)。

您可以在 UI(master 上的端口 8080)中查看每个节点分配的内存。

您还需要在提交应用程序时设置每个执行程序的内存,即 spark-submit(再次默认为 1GB),就像以前一样 - 使用 --help 运行以获取内存选项。

希望这会有所帮助。

【讨论】:

【参考方案2】:

很抱歉造成混乱(我是 OP),我花了一段时间才深入了解真正发生的事情。我做了很多基准测试,最后我意识到在 Docker 映像上我使用的是 OpenBLAS,它默认使用多线程 linalg 函数。我的代码在80 x 80140 x 140 大小的矩阵上运行了数百次cho_solve。启动所有这些线程只会产生大量开销,而我一开始并不需要这些开销,因为我正在通过多处理或 Spark 进行并行计算。

# N_CORES=4 python linalg_test.py
72.983 seconds

# OPENBLAS_NUM_THREADS=1 N_CORES=4 python linalg_test.py
9.075 seconds

【讨论】:

以上是关于独立集群 + Docker 上的 PySpark 性能不佳的主要内容,如果未能解决你的问题,请参考以下文章

Hadoop 独立集群 Pyspark 加载 CSV 文件不存在(hdfs://home/usr/filepath.csv)

YARN 集群上的 PySpark 分布式处理

从 Docker 容器将 PySpark 连接到 Kafka

K3s 集群内 containerd 跟 docker 的区别

pyspark/EMR 中大型 DataFrame 上的 collect() 或 toPandas()

Dataproc 上的 PySpark 因 SocketTimeoutException 而停止