并行度
RDD的逻辑表示其实是一个对象集合,在物理执行期间,RDD会被分为一系列的分区,每个分区都是整个数据的子集。当 Spark调度并运行任务时, Spark会为每个分区中的数据创建出一个任务。该任务在默认情况下会需要集群中的一个计算核心来执行。Spak也会针对RDD直接自动推断出合适的并行度,这对于大多数用例来说已经足够了。输入RDD一般会根据其底层的存储系统选择并行度。例如,从HDFS上读数据的输入RDD会为数据在HDFS上的每个文件区块创建一个分区。从数据shuffle后的RDD派生下来的RDD则会采用与其父RDD相同的并行度。
并行度会从两方面影响程序的性能。首先,当并行度过低时, Spark集群会出现资源闲置的情况。比如,假设你的应用有1000个可使用的计算核心,但所运行的步骤只有30个任务,你就应该提高并行度来充分利用更多的计算核心。而当并行度过高时,每个分区产生的间接开销累计起来就会更大。评判并行度是否过高的标准包括任何是否是几乎在瞬间(毫秒级)完成的,或者是否观察到任务没有读写任何数据。
Spak提供了两种方法来对操作的并行度进行调优。
第一种方法是在数据shuffle操作时,使用参数的方式为shuffle后的RDD指定并行度。
第二种方法是对于任何已有的RDD,可以进行重新分区来获取更多或者更少的分区数。重新分区操作通过repartition()实现,该操作会把RDD随机打乱并分成设定的分区数目。如果你确定要减少RDD分区,可以使用coalesce()操作。由于没有打乱数据,该操作比repartition()更为高效。如果你认为当前的并行度过高或者过低,可以利用这些方法对数据分布进行重新调整。
序列化格式
当Spark需要通过网络传输数据,或是将数据溢写到磁盘上时, Spark需要把数据序列化为二进制格式。序列化会在数据进行混洗操作时发生,此时有可能需要通过网络传输大量数据。默认情况下,Spark会使用Java内建的序列化库。Spark也支持使用第三方序列化库Kryo,可以提供比Java的序列化工具更短的序列化时间和更高压缩比的二进制表示,但不能直接序列化全部类型的对象。几乎所有的应用都在迁移到Kryo后获得了更好的性能
内存管理
内存对 Spark来说有几种不同的用途,理解并调优 Spark的内存使用方法可以帮助优化Spark的应用。在各个执行器进程中,内存有以下所列几种用途
RDD存储
数据混洗与聚合的缓存区
用户代码
Spark可以执行任意的用户代码,所以用户的函数可以自行申请大量内存。例如,如果一个用户应用分配了巨大的数组或者其他对象,那这些都会占用总的内存。用户代码可以访问JVM堆空间中除分配给RDD存储和数据混洗存储以外的全部剩余空间。
在默认情况下,Spark会使用60%的空间来存储RDD,20%存储数据混洗操作产生的数据,剩下的20%留给用户程序。用户可以自行调节这些选项来追求更好的性能表现。如果用户代码中分配了大量的对象,那么降低RDD存储和数据混洗存储所占用的空间可以有效避免程序内存不足的情况。
领取专属 10元无门槛券
私享最新 技术干货