Spark:The Definitive Guide--读书小结(四)

本文总结了阅读《Spark权威指南》的体验,涵盖了大数据与Spark概述、DataFrame与SQL、低级API、生产应用、流处理、高级分析与机器学习,以及Spark生态。重点讲解了性能优化策略和常见问题解决方法,适合初学者学习Spark 2.0技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

大概花了一个月(2020-09~2020-10)左右的时间,看完了整本书。笔者毕业后,主要从事机器学习、数据挖掘方向的相关工作。由于Spark作为目前主流的分布式计算引擎,个人也一直在用Spark进行相关的数据分析与建模工作。通读全书,感觉比较适合入门级学习,主要介绍了Spark 2.0相关API及Spark生态。涵盖Spark SQL、Struct Streaming、GraphX、MLlib等内容。对初学者而言是一本不错的书籍。

数据、源码链接: https://github.com/databricks/Spark-The-Definitive-Guide

第Ⅰ部分 大数据与Spark概述

链接: https://blog.youkuaiyun.com/Java_Man_China/article/details/109321946

第Ⅱ部分 结构化API–DataFrame、SQL和Dataset

链接: https://blog.youkuaiyun.com/Java_Man_China/article/details/109321946

第Ⅲ部分 低级API

链接: https://blog.youkuaiyun.com/Java_Man_China/article/details/109378254

第Ⅳ部分 生产与应用

Spark UI
无论是为了调试还是更好的理解应用程序在集群上的执行过程,通过Spark UI和Spark日志是最方便获取监控报告的方式,这些报告包括Spark应用程序的运行状态,如RDD的转化和查询计划的执行信息等。
在这里插入图片描述
Jobs:对应Spark作业
Stages:对应各个阶段(及相关任务)
Storage:包含当前在Spark应用程序中缓存的信息和数据
Environment: Spark应用程序的配置信息
SQL: 对应提交的结构化API查询(SQL及DataFrame)
Executors: 应用程序中各执行器的详细信息

Summary Metrics:
查看某个Job的某个stage中所有task的执行情况,显示了各种指标的统计概要,注意警惕不均匀的数据分布。在本例中,各项指标分布均匀。
在这里插入图片描述
Spark常见问题:

  1. Spark作业未启动:
    集群配置问题或应用程序资源需要过大导致,常见的问题是每个执行器进程分配了太大的内存,超过了集群管理器的内存资源配额。

    解决方案:
    合理申请Spark资源

  2. 任务缓慢
    此问题在优化程序时非常常见,这可能是由于工作负载没有被均匀分布在集群各节点上(数据倾斜),或者由于某台计算节点比其它节点速度慢(硬件问题)。

    解决方案:
    1.尝试增加分区数,减少每个分区被分配到的数据量。
    2.分配给执行器进程更多的内存。
    3.尝试通过另一列组合来重新分区或自定义分区。
    4.打开推测功能,可以解决单节点硬件带来的速度缓慢问题。
    5.检查UDF函数是否在其对象分配或业务逻辑中有资源浪费。
    6.Dataset在执行大量的对象实例化并将记录转化为用户定义函数中的Java对象,可能会导致大量垃圾回收。请查看Spark UI中垃圾回收指标。

    任务缓慢和落后者可能是调试中遇到的最困难的问题之一,因为有太多的可能性导致任务缓慢,然而大多数情况下是某种数据倾斜导致的。

  3. 缓慢的聚合操作
    在执行groupby操作时产生缓慢任务或聚合操作之后的作业也执行的非常缓慢。

    解决方案:
    1.在聚合操作前增加分区数量可能有助于减少每个任务中处理不同key的数量。
    2.增加执行器的内存配额也可以缓解此问题。如果一个key数据量过大,增加内存可以减少与磁盘交互数据并更快的完成任务,尽管他可能依旧比其它进程要慢得多。
    3.如果你发现聚合操作之后的任务也很慢,这意味着你的数据集在聚合后依旧可能不均衡,尝试repartition并对数据进行随机重分区。
    4.优化代码逻辑,尽可能使所有filter操作和select操作在聚合之前发生。
    5.确保空值被正确的表示(建议使用Spark的null关键字),不要用”"或“empty”等表示,因为Spark优化器通常会在作业初期来跳过对null值得处理,但它无法为你自定义的空值进行此优化。
    这个问题并不能总是能够得到解决,如果你的作业中需要对存在数据倾斜的某个Key执行聚合操作,那么执行聚合操作时就是很慢。

  4. 缓慢的连接操作

    解决方案:
    1.实验不同的连接操作顺序,前提是一些连接操作会过滤大量数据。
    2.执行连接操作前,对数据集进行分区,这对于减少数据集在集群之前的移动是非常有用的,特别是多个连接操作中使用相同的数据集时。请注意,分区是以数据shuffle为代价的。
    3.数据倾斜导致的连接变慢
    4.可以强制采用广播小表的方式

  5. driver端OOM
    通常是由于驱动器进程收集了过多的数据集,从而导致内存不足。
    解决方案:
    1.查看collet之类操作的数据集是否过大
    2.可能使用了广播数据,但是广播的数据集太大
    3.应用程序长时间运行导致生成了大量对象,并且无法释放它们。
    4.增加driver端内存

  6. excutor OOM
    应用程序有时可以自动从这类错误中恢复,但不一定,主要还是取决于导致这种错误的根本原因。

    解决方案:
    1.增加excutor 内存
    2.在使用RDD或Dataset时,由于对象实例化可能导致产生执行器的内存溢出,应尽可能避免使用UDF,同时尽可能使用Spark的结构化操作。

  7. 序列化错误
    主要表现为作业失败并显示序列化错误。用结构化API时,这种现象非常罕见。但当你使用RDD或UDF执行自定义逻辑时,或序列化到执行器的任务或共享数据无法被序列化时,就常会遇到序列化错误。

    解决方案:
    1.如果你正在使用Kyro序列化,确保注册了你的类
    2.在scala或java中创建UDF时,不要在UDF中引用封闭对象的任何字段

Spark性能优化
提高性能最好的方法是实现良性的检测功能和作业历史跟踪功能,没有这些信息就很难理解你的优化策略是否真的提高了性能。

间接性能优化
1.RDD对象序列化:Kryo序列化比Java序列化更紧凑,效率更高

2.数据存储:Spark处理最有效的文件存储格式是parquet

3.文件可拆分:无论选择哪种文件都应该保证它式可拆分的,这样不同的任务就可以并行的读取文件。通常选择gzip压缩的parquet文件。zip和tar压缩的文件不可拆分

4.表分区:如果用户在其查询时经常按照”date“进行过滤,就可以用该列进行分区,这可以大大减少用户在大多数查询中读取的数据量,从而显著提高速度。

5.表分桶:当按列分区时,若分割细粒度太细导致很多小文件,此时可以尝试表分桶。

6.文件的数量:如果有很多小文件,获得文件列表和找到每个文件的开销都将非常大。例如,hdfs每个数据块是128MB,如果你有30个小文件,每个是5MB,实际上只要2个数据块就可以存储,但此时却需要请求30个块。可以通过maxRecordsPerFile选项控制每个文件中的记录数。一般建议调整文件大小几十兆(至少)。

7.内存压力、垃圾回收:尽可能的多使用结构化API,这不仅会提高Spark执行效率,而且还会大大降低内存压力,因为结构化API不会产生JVM对象。

直接性能优化

1.并行度:如果需要加速某一个特地的阶段,最先尝试的应该就是增加其并行度。可以通过spark.default.parallelism属性来设置它。

2.过滤优化:尽可能的将过滤器移动到Spark任务的最开始,有时,甚至可以放置在数据的源头。启动表分区和表分桶也有助于实现此目的。

3.重分区、合并
重分区的调用可能会导致Shuffle操作,但是通过平衡集群上的数据可以从整体上优化作业的执行,所以这个代价是值得的。重分区主要有coalesce(不会发生shuffle、单节点合并分区)、repartition(发生shuffle、跨节点重分区)。重分区操作应该在连接操作之前或这cache操作之前调用会产生非常好的效果。

4.自定义分区
尝试在RDD级别上自定义分区,可以更好的解决数据倾斜问题。DataFrame上的分区主要采用的是hash分区。

5.避免使用UDF函数
UDF是昂贵的,因为它们强制的将数据表示为JVM对象

6.缓存
重复使用相同的数据集时,最有用的优化方式之一就是将其缓存(内存或磁盘)。这将使得后续多次读取更块,不会再重头执行一遍。由于缓存会导致数据序列化、反序列化和存储开销,因此并不是我们应该一直做的事。例如,你只想在后续的操作中访问该数据集一次,此时缓存只会降低速度。

7.广播变量,针对大小表Join操作时可采用

8.聚合操作时,采用RDD,用reduceByKey替换groupByKey

第Ⅴ部分 流处理

链接: https://editor.youkuaiyun.com/md/?articleId=109321946//未写待续

第Ⅵ部分 高级分析与机器学习

链接: https://editor.youkuaiyun.com/md/?articleId=109321946//未写待续

第Ⅶ部分 生态系统

链接: https://editor.youkuaiyun.com/md/?articleId=109321946//未写待续

Welcome to this first edition of Spark: The Definitive Guide! We are excited to bring you the most complete resource on Apache Spark today, focusing especially on the new generation of Spark APIs introduced in Spark 2.0. Apache Spark is currently one of the most popular systems for large-scale data processing, with APIs in multiple programming languages and a wealth of built-in and third-party libraries. Although the project has existed for multiple years—first as a research project started at UC Berkeley in 2009, then at the Apache Software Foundation since 2013—the open source community is continuing to build more powerful APIs and high-level libraries over Spark, so there is still a lot to write about the project. We decided to write this book for two reasons. First, we wanted to present the most comprehensive book on Apache Spark, covering all of the fundamental use cases with easy-to-run examples. Second, we especially wanted to explore the higher-level “structured” APIs that were finalized in Apache Spark 2.0—namely DataFrames, Datasets, Spark SQL, and Structured Streaming—which older books on Spark don’t always include. We hope this book gives you a solid foundation to write modern Apache Spark applications using all the available tools in the project. In this preface, we’ll tell you a little bit about our background, and explain who this book is for and how we have organized the material. We also want to thank the numerous people who helped edit and review this book, without whom it would not have been possible.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值