揭秘Spark应用性能调优

简介: 在多台机器上分布数据以及处理数据是Spark的核心能力,即我们所说的大规模的数据集处理。为了充分利用Spark特性,应该考虑一些调优技术。本文每一小节都是关于调优技术的,并给出了如何实现调优的必要步骤。 本文选自《Spark GraphX实战》。

引言:在多台机器上分布数据以及处理数据是Spark的核心能力,即我们所说的大规模的数据集处理。为了充分利用Spark特性,应该考虑一些调优技术。本文每一小节都是关于调优技术的,并给出了如何实现调优的必要步骤。
本文选自《Spark GraphX实战》。

1 用缓存和持久化来加速 Spark

  我们知道Spark 可以通过 RDD 实现计算链的原理 :转换函数包含在 RDD 链中,但仅在调用 action 函数后才会触发实际的求值过程,执行分布式运算,返回运算结果。要是在 同一 RDD 上重复调用 action 会发生什么?

RDD 持久化

  一般 RDD 不会保留运算结果,如果再次调用 action 函数,整个 RDD 链会重新 运算。有些情况下这不会有问题,但是对于许多机器学习任务和图处理任务,这就 是很大的问题了。通常需要多次迭代的算法,在同一个 RDD 上执行很多次,反复 地重新加载数据和重新计算会导致时间浪费。更糟糕的是,这些算法通常需要很长 的 RDD 链。
  看来我们需要另一种方式来充分利用集群可用内存来保存 RDD 的运算结果。 这就是 Spark 缓存(缓存也是 Spark 支持的一种持久化类型)。
  要在内存中缓存一个 RDD,可以调用 RDD 对象的 cache 函数。以下在 spark- shell 中执行的代码,会计算文件的总行数,输出文件内容 :

val filename = "..."
val rdd1 = sc.textFile(filename).cache
rdd1.count
rdd1.collect

如果不调用 cache 函数,当 count 和 collect 这两个 action 函数被调用时, 会导致执行从存储系统中读文件两次。调用了 cache 函数,第一个 action 函数(count 函数)会把它的运算结果保留在内存中,在执行第二个 action 函数(collection 函数)时,会直接在使用缓存的数据上继续运算,而不需要重新计算整个 RDD 链。 即使通过转换缓存的 RDD,生成新的 RDD,缓存的数据仍然可用。下面的代码会找出所有的注释行(以 # 开始的行数据)。

val rdd2 =rdd1.filter(_.startsWith("#"))
rdd2.collect

  因为 rdd2 源于已缓存的 rdd1,rdd1 已经把它的运算结果缓存在内存中了, 所以 rdd2 也就不需要重新从存储系统中读取数据。

注意:cache 方法作为一个标志表示 RDD 应当缓存,但并不是立即缓存。 缓存发生在当前 RDD 在下一次要被计算的时候。

持久化等级

  如上所述,缓存是其中一种持久化类型。下表列出了 Spark 支持的所有持久 化等级。
        【图1】
  每个持久化等级都定义在单例对象 StorageLevel 中。例如,调用 rdd.persist(StorageLevel.MEMORY_AND_DISK)方法会把 RDD 设置成内存和磁盘缓 存。 cache 方法内部也是调用 rdd.persist(StorageLevel.MEMORY_ONLY)。

注意 :其他的持久化等级,如 MEMORY_ONLY2、MEMORY_AND_ DISK2 等,也是可用的。它们会复制 RDD到集群的其他节点上,以便 提供容错能力。这些内容超出了本书范围,感兴趣的读者可以看看 Petar Zec' evic' 和 Marko

Bonac' i(Manning, 2016)的书 Spark in Action,这本书更 深入地介绍了 Spark 容错方面的内容。

图的持久化

  无论什么时候,通过 Graph 对象调用一些函数如 mapVertices 或 aggregateMessages, 这些操作都是基于下层的 RDD 实现的。
  Graph 对象提供了基于顶点 RDD 和边 RDD 方便的缓存和持久化方法。

在合适的时机反持久化

  虽然看起来缓存是一个应该被到处使用的好东西,但是用得太多也会让人过度依赖它。
  当缓存越来越多的 RDD 后,可用的内存就会减少。最终 Spark 会把分区数据从 内存中逐出(使用最少最近使用算法,LRU)。同时,缓存过多的 Java 对象,JVM 垃圾回收高耗是不可避免的。这就是为什么当缓存不再被使用时很有必要调用 un- persist 方法。对迭代算法而言,在循环中常用下面的方法调用模式 :

  • 调用 Graph 的 cache 或 persist 方法。
  • 调用 Graph 的 action 函数,触发 Graph 下面的 RDD 被缓存……
  • 执行算法主体的其余部分。
  • 在循环体的最后部分,反持久化,即释放缓存。

提示 :用Pregel API的好处是,它已经在内部做了缓存和释放缓存的操作。

何时不用缓存

  不能盲目地在内存中缓存 RDD。要考虑数据集会被访问多少次以及每次访问时 重计算和缓存的代价对比,重计算也可能比增加内存的方式付出的代价小。
  毫无疑问,如果仅仅读一次数据集,缓存 RDD 就毫无意义,这还会让作业运 行得更慢,特别是用了有序列化的持久化等级。

2.checkpointing

  图算法中一个常用的模式是用每个迭代过程中运算后的新数据更新图。这意味 着,实际构成图的顶点 RDD 亦或边 RDD 的链会变得越来越长。

定义 :当 RDD 由逐级继承的祖先 RDD 链形成时,我们说从 RDD 到 根 RDD 的路径是其谱系。

  下面清单所示的示例是一个简单的算法,可生成一个新顶点集并更新图。这个 算法迭代的次数由变量 iterations 控制。
        【图2】
  上述代码每一次调用 joinVertices 都会增加一个新 RDD 到顶点 RDD 链中。 显然我们需要使用缓存来确保在每次迭代中避免重新计算 RDD 链,但这并不能改变一个事实,那就是有一个不断增长的子 RDD 到父 RDD 的对象引用列表。
  这样的后果是,如果运行迭代次数过多,运行的代码中最终会爆出 Stack- OverflowError 栈溢出错误。通常迭代 500次就会出现栈溢出。
  而由 RDD 提供并且被 Graph 继承的一个特性 :checkpointing,能解决长 RDD 谱系问题。下面清单中的代码示范了如何使用 checkpointing,这样就可以持续输出 顶点,更新结果图。
              【图3】
  一个标记为 checkpointing 的 RDD 会把 RDD 保存到一个 checkpoint 目录,然 后指向父 RDD 的连接被切断,即切断了 lineage 谱系。一个标记为 checkpointing 的 Graph 会导致下面的顶点 RDD 和边 RDD 做 checkpoint。
  调用 SparkContext.setCheckpointDir 来设置 checkpoint 目录,指定一个 共享存储系统的文件路径,如 HDFS。
  如前面的代码清单所示,必须在调用 RDD 任何方法之前调用 checkpoint,这 是因为 checkpointing 是一个相当耗时的过程(毕竟需要把图写入磁盘文件),通常 需要不断地 checkpoint 避免栈溢出错误,一般可以每 100 次迭代做一次 checkpoint。

注意 :一个加速 checkpointing 的选择是 checkpoint 到 Tachyon(已 更名为 Alluxio),而不是checkpoint 到标准的文件系 统。Alluxio,来自 AMPLab,是一个“以内存为中心的有容错能力的分布式文件系统,它能让Spark 这类集群框架加速访问共享在内存中的文件”。

3 通过序列化降低内存压力

  内存压力(内存不够用)往往是 Spark 应用性能差和容易出故障的主要原因 之一。这些问题通常表现为频繁的、耗时的 JVM 垃圾回收和“内存不足”的错 误。checkpointing 在这里也不能缓解内存压力。遇到这种问题,首先要考虑序列化 Graph 对象。

定义 :数据序列化,Data serialization,是把 JVM 里表示的对象实 例转换(序列化)成字节流 ;把字节流通过网络传输到另一个 JVM 进程 中 ;在另一个 JVM 进程中,字节流可以被“反序列化”为一个对象实例。Spark用序列化的方式,可以在网络间传输对象,也可以把序列化后的字节流缓存在内存中。

  要用序列化,可以选用 persist 中下面的 StorageLevels :

  • StorageLevel.MEMORY_ONLY_SER
  • StorageLevel.MEMORY_AND_DISK_SER

序列化节省了空间,同时序列化和反序列化也会增加 CPU 的开销。

使用 Kryo 序列化

  Spark 默认使用 JavaSerializer 来序列化对象,这是一个低效的 Java 序列化框架,一个更好的选择是选用 Kryo。Kryo 是一个开源的 Java 序列化框架,提供了 快速高效的序列化能力。
  Spark 中使用 Kryo 序列 化,只需要设置 spark.serializer 参数为 org. apache.spark.serializer.KryoSerializer,如这样设置命令行参数 :

spark-shell --conf "spark.serializer=org.apache.spark.serializer.KryoSerializer"

  要是每次都这样设置参数,会很烦琐。可以在 $Spark_HOME/conf/spark-
defaults.conf 这个配置文件中,用标准的属性文件语法(用 Tab 分隔作为一行),把 spark.serializer 等参数及其对应的值写入这个配置文件,如下所示 :

spark.serializer org.apache.spark.serializer.KryoSerializer

  为保证性能最佳,Kryo 要求注册要序列化的类,如果不注册,类名也会被序列 化在对象字节码里,这样对性能有较大影响。幸运的是,Spark 对其框架里用到的 类做了自动注册 ;但是,如果应用程序代码里有自定义的类,恰好这些自定义类也 要用 Kryo 序列化,那就需要调用 SparkConf.registerKryoClasses 函数来手 动注册。下面的清单展示了如何注册 Person 这个自定义类。
         【图4】

检查 RDD 大小

  在应用程序调优时,常常需要知道 RDD 的大小。这就很棘手,因为文件或数 据库中对象的大小和 JVM 中对象占用多少内存没有太大关系。
  一个小技巧是,先将 RDD 缓存到内存中,然后到 Spark UI 中的 Storage 选项卡, 这里记录着 RDD 的大小。要衡量配置了序列化的效果,用这个方法也可以。

  本文选自《Spark GraphX实战》,点此链接可在博文视点官网查看此书。
                     图片描述
  想及时获得更多精彩文章,可在微信中搜索“博文视点”或者扫描下方二维码并关注。
                       图片描述

相关文章
|
分布式计算 数据处理 Apache
Spark和Flink的区别是什么?如何选择?都应用在哪些行业?
【10月更文挑战第10天】Spark和Flink的区别是什么?如何选择?都应用在哪些行业?
2453 1
|
机器学习/深度学习 SQL 分布式计算
Spark核心原理与应用场景解析:面试经验与必备知识点解析
本文深入探讨Spark核心原理(RDD、DAG、内存计算、容错机制)和生态系统(Spark SQL、MLlib、Streaming),并分析其在大规模数据处理、机器学习及实时流处理中的应用。通过代码示例展示DataFrame操作,帮助读者准备面试,同时强调结合个人经验、行业趋势和技术发展以展现全面的技术实力。
1816 0
|
机器学习/深度学习 SQL 分布式计算
Apache Spark 的基本概念和在大数据分析中的应用
介绍 Apache Spark 的基本概念和在大数据分析中的应用
532 0
|
机器学习/深度学习 SQL 分布式计算
介绍 Apache Spark 的基本概念和在大数据分析中的应用。
介绍 Apache Spark 的基本概念和在大数据分析中的应用。
|
SQL 分布式计算 Serverless
鹰角网络:EMR Serverless Spark 在《明日方舟》游戏业务的应用
鹰角网络为应对游戏业务高频活动带来的数据潮汐、资源弹性及稳定性需求,采用阿里云 EMR Serverless Spark 替代原有架构。迁移后实现研发效率提升,支持业务快速发展、计算效率提升,增强SLA保障,稳定性提升,降低运维成本,并支撑全球化数据架构部署。
1677 56
鹰角网络:EMR Serverless Spark 在《明日方舟》游戏业务的应用
|
分布式计算 Java 数据库连接
回答粉丝疑问:Spark为什么调优需要降低过多小任务,降低单条记录的资源开销?
回答粉丝疑问:Spark为什么调优需要降低过多小任务,降低单条记录的资源开销?
273 1
|
机器学习/深度学习 分布式计算 大数据
阿里云 EMR Serverless Spark 在微财机器学习场景下的应用
面对机器学习场景下的训练瓶颈,微财选择基于阿里云 EMR Serverless Spark 建立数据平台。通过 EMR Serverless Spark,微财突破了单机训练使用的数据规模瓶颈,大幅提升了训练效率,解决了存算分离架构下 Shuffle 稳定性和性能困扰,为智能风控等业务提供了强有力的技术支撑。
919 15
|
SQL 分布式计算 Serverless
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
511 0
|
分布式计算 大数据 Spark
Spark大数据处理:技术、应用与性能优化(全)PDF书籍推荐分享
《Spark大数据处理:技术、应用与性能优化》深入浅出介绍Spark核心,涵盖部署、实战与性能调优,适合初学者。作者基于微软和IBM经验,解析Spark工作机制,探讨BDAS生态,提供实践案例,助力快速掌握。书中亦讨论性能优化策略。[PDF下载链接](https://zhangfeidezhu.com/?p=347)。![Spark Web UI](https://img-blog.csdnimg.cn/direct/16aaadbb4e13410f8cb2727c3786cc9e.png#pic_center)
741 1
Spark大数据处理:技术、应用与性能优化(全)PDF书籍推荐分享
|
SQL 分布式计算 监控
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
本文演示了使用 EMR Serverless Spark 产品搭建一个日志分析应用的全流程,包括数据开发和生产调度以及交互式查询等场景。
57292 7
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用