为什么 Spark 这么慢?今天优化 Spark 的 5 种方法

在竞争日益激烈的世界中寻找优势?通过 Kubernetes 2023 状态揭示 Kubernetes 可以为您的业务做些什么。现在阅读以探索如何利用 Kubernetes 的优势、解锁潜在解决方案并克服挑战。

当 Apache Spark 运行良好时,它确实运行良好。但有时,用户会发现自己在问这个令人沮丧的问题。

Spark之所以如此受欢迎,是因为它比传统的数据处理解决方案能够执行更多的计算和更多的流处理。与 MapReduce 等流行的传统系统相比,Spark 的速度要快 10-100 倍。但是,虽然 Spark 能够处理范围广泛的工作负载和大数据集,但有时也会遇到困难。这就是原因,这就是您可以采取的措施。

所以:您已经尝试了一些 Apache Spark 性能调优技术,但您的应用程序仍然很慢。此时,是时候深入了解您的 Spark 架构,并确定导致您的实例运行缓慢的原因。

驱动故障

在 Spark 架构中,驱动程序充当编排器。因此,它配备的内存少于执行程序。当驱动程序遇到 OutOfMemory (OOM) 错误时,可能是以下原因造成的:

简而言之,当驱动程序执行需要更多内存的服务或尝试使用比分配的内存更多的内存时,就会发生 OOM 错误。解决这种情况的两个有效的 Spark 调优技巧是:

高并发

有时,Spark 运行缓慢是因为运行的并发任务太多。

高并发能力是一个有益的特性,因为它提供了 Spark 原生的细粒度共享。这会导致最大的资源利用率,同时减少查询延迟。 Spark 将作业和查询划分为多个阶段,并将每个阶段分解为多个任务。 Spark 会根据多种因素并发执行这些任务。

但是,并行执行的任务数基于 spark.executor.cores 属性。虽然高并发意味着要执行多个任务,但如果该值设置得太高而没有适当考虑内存,执行程序将失败。

低效查询

为什么 Spark 这么慢?也许你有一个写得不好的查询潜伏在某处。

按照设计,Spark 的 Catalyst 引擎会自动尝试最大程度地优化查询。但是,如果查询本身写得不好,任何优化工作都注定会失败。例如,一个查询被编程为选择 Parquet/ORC 表的所有列。每列都需要某种程度的内存中列批处理状态。如果查询选择所有列,则会导致更高的开销。

一个好的查询读取尽可能少的列。一个好的 Spark 性能调优实践是尽可能使用过滤器。这有助于限制获取到执行程序的数据。

另一个好技巧是使用分区修剪。将查询转换为使用分区列是优化查询的一种方法,因为它可以极大地限制数据移动。

配置不正确

获得正确的内存配置对于 Spark 应用程序的整体性能至关重要。

每个 Spark 应用程序都有一组不同的内存和缓存要求。如果配置不正确,Spark 应用程序会变慢或崩溃。深入查看 spark.executor.memory 或 spark.driver.memory 值将有助于确定工作负载是否需要更多或更少的内存。

YARN 容器内存开销也会导致 Spark 应用程序变慢,因为 YARN 需要更长的时间来分配更大的内存池。实际情况是 YARN 在容器中运行每个 Spark 组件,例如驱动程序和执行程序。它产生的开销内存实际上是用于JVM(驱动程序)开销、interned字符串和JVM的其他元数据的堆外内存。

当由于 YARN 内存开销导致 Spark 性能下降时,您需要将 spark.yarn.executor.memoryOverhead 设置为正确的值。通常,为开销分配的理想内存量是执行程序内存的 10%。

您需要采取某些步骤来确保 Spark 运行不慢。以下是使您的 Spark 架构、节点和应用程序以最佳水平运行的一些有效方法。

数据序列化

这种特殊的 Spark 优化技术将内存中的数据结构转换为可以存储在文件中或通过网络传输的不同格式。使用这种策略,您可以显着提高分布式应用程序的性能。两种流行的数据序列化方法是:

Java 序列化——您使用 ObjectOutputStream 框架序列化数据,并利用 java.io.Externalizable 来完全控制序列化的性能。 Java 序列化提供轻量级持久性。

Kyro 序列化——Spark 利用 Kryo 序列化库 (v4) 比 Java 序列化更快地序列化对象。这是一种更紧凑的方法。要通过使用 Kyro 序列化真正提高 Spark 应用程序的性能,必须通过 registerKryoClasses 方法注册这些类。

缓存

缓存是一种高效的优化技术,在处理重复需要和查询的数据时使用。 Cache() 和 persist() 非常适合存储数据集、RDD 和 DataFrame 的计算。

需要记住的是,cache() 将数据放入内存中,而 persist() 将数据存储在用户指定或定义的存储级别中。缓存有助于降低成本并在处理重复计算时节省时间,因为从内存读取数据比从磁盘读取数据快得多。

数据结构调整

数据结构调整减少了 Spark 内存消耗。数据结构调优通常包括:

垃圾收集优化

垃圾回收是一种内存管理工具。每个应用程序都将数据存储在内存中,内存中的数据有一个生命周期。垃圾收集标记哪些数据不再需要,标记为删除,然后删除。删除发生在应用程序暂停期间。这些暂停是要避免的。当垃圾收集成为瓶颈时,使用带有 -XX:+UseG1GC 的 G1GC 垃圾收集器已被证明效率更高。

Spark 并不总是完美运行。这是一个很棒的数据处理平台,但不能让它完全自动运行。一致的 Spark 性能调优将帮助您的 Spark 基础设施以最佳水平运行

下次您发现自己问“为什么 Spark 这么慢?”时,请深入了解 Spark 架构并仔细研究。前面提到的 Spark 性能缓慢的原因可能只是罪魁祸首之一,而提到的提高性能的技巧可能是您需要改进的地方。

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。更多免费资源在http://www.gitweixin.com/?p=2627