【问题标题】:Any tips for scaling Spark horizontally任何水平缩放 Spark 的技巧
【发布时间】:2018-05-17 05:58:23
【问题描述】:

在将 Spark 执行从几个大型节点转移到许多较小的节点时,是否有人有任何提示?

我正在运行一个有 4 个执行器的系统,每个执行器有 24Gb 的内存和 12 个内核。如果我尝试将其扩展到 12 个执行程序,每个执行程序 4 个内核和 8 Gb 内存(相同的总 RAM,相同的总内核,只是分布不同),我会遇到内存不足错误: Container killed by YARN for exceeding memory limits. 8.8 GB of 8.8 GB physical memory used.

我将分区数量增加了 3 倍以创建更多(但更小)的分区,但这没有帮助。

在尝试水平缩放火花时,有人有任何提示和技巧吗?

【问题讨论】:

    标签: apache-spark hadoop-yarn


    【解决方案1】:

    这是一个相当广泛的问题,Spark 中的执行者规模调整是一种非常复杂的黑魔法,而 例如在 2015 年正确的经验法则现在已经过时了 strong>,正如我所说的任何内容都将在 6 个月内随着 Spark 的下一个版本过时。很大程度上取决于您正在做什么以及避免数据中的关键偏差。

    这是一个开始学习和发展自己理解的好地方: https://spark.apache.org/docs/latest/tuning.html

    Slideshare 上还有大量关于调整 Spark 的演示文稿,请尝试阅读/观看最新的演示文稿。任何超过 18 个月的都值得怀疑,超过 2 年的则忽略。

    我会假设您至少使用 Spark 2.x。

    您遇到的错误确实是由于执行程序大小调整不当造成的。正在发生的事情是,您的执行者试图一次做太多事情,并在内存不足时将自己陷入困境。

    在所有其他条件相同的情况下,这些是我应用它们时的当前经验法则:

    简短版

    • 3 - 4 个虚拟(超线程)内核和 29GB 的 RAM 是合理的默认执行程序大小(稍后我将解释原因)。如果您一无所知,请妥善划分您的数据并使用它。
    • 您通常应该将数据分区大小(在内存中)的目标设为 ~100MB 到 ~3GB

    我应用的公式

    执行器内存 = 执行器核心数 * 分区大小 * 1.3(安全系数)

    分区大小 = 磁盘上的数据大小 / 分区数 * 请求率

    反序列化比率是磁盘上数据大小与内存中数据大小的比率。相同数据的 Java 内存表示往往比磁盘大一点。

    您还需要考虑您的数据是否经过压缩,Parquet 和 ORC 等许多常见格式使用 gzip 或 snappy 等压缩。

    对于快速压缩的文本数据(非常容易压缩),我使用 ~10X - 100X。 对于混合了文本、浮点数、日期等的快速压缩数据,我通常看到 3X 到 15X 之间。

    执行器核心数 = 3 到 4 执行程序核心完全取决于您的计算是计算密集型还是内存密集型。试验一下,看看什么最适合您的用例。我从来没有见过有人了解 Spark 提倡超过 6 个内核。

    Spark 足够聪明,可以利用数据局部性,因此您的执行程序越大,您的数据为PROCESS_LOCAL 的机会就越大 在一定程度上,更多的数据局部性是好的。

    当 JVM 变得太大 > 50GB 时,它会开始超出最初设计的范围运行,并且根据您的垃圾收集算法,您可能会开始看到性能下降和 GC 时间变长。

    https://databricks.com/blog/2015/05/28/tuning-java-garbage-collection-for-spark-applications.html

    Java 中也有一个性能技巧,如果你的 JVM 小于 32GB,你可以使用 32 位压缩指针而不是 64 位指针,这样可以节省空间并降低缓存压力。

    https://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html https://blog.codecentric.de/en/2014/02/35gb-heap-less-32gb-java-jvm-memory-oddities/

    YARN 也会为您的执行程序大小增加 7% 或 384MB 的 RAM(以较大者为准)以用于开销/安全因素,这就是 29GB 经验法则的来源:29GB + 7% ~= 32GB

    您提到您使用的是 12 核、24GB RAM 执行器。这对我来说是一个危险信号。

    为什么?

    因为执行器中的每个“核心”都会被分配一个“任务”。一项任务相当于计算一个分区从“阶段”A到“阶段”B的转换所需的工作。

    https://jaceklaskowski.gitbooks.io/mastering-apache-spark/content/spark-taskscheduler-tasks.html https://jaceklaskowski.gitbooks.io/mastering-apache-spark/content/spark-DAGScheduler-Stage.html

    如果您的执行程序有 12 个内核,那么它​​将尝试以 24GB 的内存预算同时执行 12 个任务。 24GB / 12 核 = 每核 2GB。如果您的分区大于 2GB,您将收到内存不足错误。如果特定的转换使输入的大小加倍(即使是中间),那么您也需要考虑到这一点。

    【讨论】:

      猜你喜欢
      • 2016-10-25
      • 2023-03-17
      • 2011-05-26
      • 2015-09-20
      • 2016-04-22
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多