通过本书,你可以了解到:Spark SQL的新接口如何为SQL的RDD数据结构提升性能。Spark Core与Spark SQL中数据join的不同选择方式。充分利用标准RDD转换的技术。如何解决Spark中键值范式的性能问题。不借助Scala或其他JVM语言来编写高性能的Spark代码。采用改进建议后,如何来测试其功能及性能情况。使用Spark MLlib和Spark ML机器学习库。Spark的流处理组件、外部的社区扩展包。
前言
这本书为数据工程师和数据科学家所写,他们可以从Spark 中获得最大的收益。如果你一直在使用并深耕 Spark,但曾被内存错误和奇奇怪怪的间歇性故障所困扰,那么这本书很适合你。如果你一直在使用 Spark 进行一些探索或者尝试性的工作,但没有足够的信心将其应用于生产,这本书可能会有帮助。如果你对 Spark 很有热情,但是在性能提升方面没有达到你的预期,希望这本书能有所帮助。本书的目标人群是那些了解一些 Spark 使用方式、但对 Spark或者分布式计算理解不够的用户。更多推荐阅读请参考后面的“配套书籍及资料”。
本书旨在于帮助优化生产上的重复查询问题,而非针对探索实验。与其他框架相比,使用 Spark 编写高性能查询对于数据工程师来说更加重要,这一点对于数据科学家更加明显。这对于思考性能问题时很少严格考虑数据的统计属性、分布,以及布局的数据工程师还是很有帮助的。我们希望本书能够帮助他们将数据管道应用于生产环节之时,可以更加严格地考虑其中的数据。希望帮助读者提出一些问题,比如“我的数据是如何分布的?”“是否有数据倾斜?”“这一列的值的范围是多少”“我们期望如何对一个给定值进行分组”,然后将这些问题的答案应用到编写 Spark 查询的逻辑中。
然而,对于数据科学家来说即使只是出于探索性目的来使用 Spark,本书也能够培养一些关于编写高性能 Spark 查询的重要直观感受,这样随着探索性分析规模不可避免地增长,你就可以在第一时间更好地运行这些查询。我们希望可以引导那些习惯以分布式视角思考数据的人,可以更加严格地评估自己的程序,增强他们全面、快速的数据探索能力,同时可以与帮助他们将算法应用于生产的人更加有效地沟通。
无论你从事什么样的岗位,你所使用的数据量很可能都在迅速增长。你的最初方案可能需要进行扩展,解决新问题时用到的老技术也可能需要更迭。我们希望这本书能帮助你利用 Apache Spark 更容易地解决新问题,同时更高效地解决老问题。
第一版注释
非常感谢你正在阅读这本书的第一版!如果你在本书中发现一些错误、问题,或者有思路来改进某些方面,请通过 high-performance-spark@googlegroups.com 联系我们。如果你希望出现在本书的未来版本中的“致谢”部分,请备注下你要展示的名字。
配套书籍及资料
对于初学 Spark 的数据科学家和开发人员来说,由 Karau、Konwinski、Wendell 和 Zaharia 共同撰写的《Learning Spark》是一本不错的学习资料注1,另外由 Sandy Ryza、Uri Laserson、Sean Owen 和 Josh Wills 所写的《Advanced Analytics with Spark》对于一些数据科学家可能会比较有吸引力。而对于流处理感兴趣的,即将出版的由 François Garillot 所著的《Learning Spark Streaming》可能更加适用。
书籍之外,还有一些入门级的 Spark 培训资料。对于喜欢视频的来说,Paco Nathan 在 O’Reilly 有一套不错入门视频。商业方面,Databricks、Cloudera以及其他的 Hadoop/Spark 供应商也提供了相应的 Spark 培训。在 Apache Spark 的文档页面可以找到以往的 Spark 训练营录音,以及其他非常优秀的资源。
如果你没有 Scala 经验,我们将在第 1 章中尽最大努力说服你学会 Scala。感兴趣的话,可以参考 Dean Wampler 和 Alex Payne 所著的《ProgrammingScala, 2nd Edition》注2。
排版约定
本书使用了下述排版约定。
斜体(Italic)
表示新术语、URL、电子邮件地址、文件名和扩展名。
等宽字体(Constant Width)
表示程序片段,以及正文中出现的变量、函数名、数据库、数据类型、环境变量、语句和关键字等。
等宽斜体(constant width italic)
表示应该由用户输入的值或根据上下文确定的值替换的文本。
使用示例代码
从本书的 Github 仓库(https://github.com/highperformance-spark/highperformance-spark-examples)可以下载补充材料(代码示例、练习等),一些测试代码可以从 Spark Testing Base 和 Spark Validator 的 Github 仓库获取。Structured Streaming 机器学习的示例,通常出现在“evil”分类(xi 页的排版约定中有提及),可以从 https://github.com/holdenk/spark-structuredstreaming-ml 获取。
本书的目的在于帮助你更好地完成工作。通常情况下,可以在你的程序或者文档中使用本书的代码。不必联系我们获取代码的使用权,除非你需要使用大量的代码。例如,在写程序的时候引用几段代码不需要向我们申请许可。但以光盘方式销售或者重新发行 O’Reilly 书中的示例则需要获得许可。引用本书或引用本书中的示例代码来回答问题也不需要申请许可。代码遵循的是Apache 2.0 协议。如果要将本书中的大量代码加入到你的产品文档,则需要申请许可。
我们欣赏你在引用时注明出处,但不强求。引用通常包括书名、作者、出版社和 ISBN。如:“High Performance Spark by Holden Karau and Rachel Warren (O’Reilly). Copyright 2017 Holden Karau, Rachel Warren, 978-1-491-94320-5”。
如果觉得使用示例代码的情况不属于前面列出的合理使用或许可范围,请通过电子邮件联系我们,邮箱地址为 permissions@oreilly.com。
O’Reilly 在线学习平台(O’Reilly Online Learning)
近40 年来,O’Reilly Media 致力于提供技术和商业培训、知识和卓越见解,来帮助众多公司取得成功。
我们拥有独一无二的专家和革新者组成的庞大网络,他们通过图书、文章、会议和我们的在线学习平台分享他们的知识和经验。O’Reilly 的在线学习平台允许你按需访问现场培训课程、深入的学习路径、交互式编程环境,以及O’Reilly 和200 多家其他出版商提供的大量文本和视频资源。有关的更多信息,请访问http://oreilly.com。
如何联系作者
如果有需要进行反馈的内容, 请发邮件至 high-performance-spark@googlegroups.com。如果你有任何关于Spark 的任何想法,请在 twitter 上关注我们:
Holden: http://twitter.com/holdenkarau。
Rachel: https://twitter.com/warre_n_peace。
联系我们
美国:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
中国:
北京市西城区西直门南大街2号成铭大厦C座807室(100035)
奥莱利技术咨询(北京)有限公司
如果你对本书有一些评论或技术上的建议,请发送电子邮件到bookquestions@oreilly.com。
有关其他图书、讲座、会议、新闻的信息,请访问我们的网站:http://www.oreilly.com。
我们的Facebook:http://facebook.com/oreilly。
我们的Twitter:http://twitter.com/oreillymedia。
我们的YouTube:http://www.youtube.com/oreillymedia。
致谢
作者要感谢每一个曾对我们的早期文稿提出意见和建议的人。特别感谢 Anya Bida、Jakob Odersky 和 Katharine Kearnan 审核文稿和图表。我们要感谢Mahmoud Hanafy 对示例代码以及早期文稿的审核和改进。我们还要感谢Michael Armbrust 对 SQL 章节文稿的审核及反馈。Justin Pihony 是最活跃的早期读者之一,他提出了各个方面(包括语言、格式等)的修改建议。
感谢我们 O’Reilly 早期发行时的所有读者,他们对于各种错误提出了不少反馈,其中包括 Kanak Kshetri 和 Rubén Berengue。
最后,感谢我们各自的雇主理解我们在这本书的工作。尤其是Lawrence Spracklen 坚持让我们在这里提到他。
Holden Karau是一位加拿大人,在IBM的Spark技术中心担任软件开发工程师。同时作为一位Spark committer,经常在PySpark和机器学习方面进行贡献。另外曾在多次国际会议中发表关于Spark的演讲。
Rachel Warren是Alpine Data的软件工程师和数据科学家。在工作中,她利用Spark来解决实际场景中的数据处理和机器学习问题。另外,她还曾在工业界以及学术界担任过分析师和导师。
目录
前言 .1
第1 章 高性能Spark 介绍 7
1.1 Spark 是什么以及性能的重要性 .7
1.2 你可以从本书中得到什么 8
1.3 Spark 版本 .9
1.4 为什么是 Scala ? 9
1.4.1 成为一名 Spark 专家必须要学习一点 Scala .9
1.4.2 Spark 的 Scala API 比 Java API 更好用 10
1.4.3 Scala 比 Python 更高效 10
1.4.4 为什么不用 Scala ? 11
1.4.5 学习 Scala 11
1.5 小结 12
第2 章 Spark 运行原理 .13
2.1 Spark 如何融入大数据生态系统 14
2.2 Spark 并行计算模型:RDD 16
2.2.1 惰性求值 17
2.2.2 内存持久化和内存管理 20
2.2.3 不可变性和 RDD 接口 . 21
2.2.4 RDD 的类型 23
2.2.5 RDD 上的函数:转换与行动 24
2.2.6 宽依赖和窄依赖 25
2.3 Spark 作业调度 . 27
2.3.1 应用程序间的资源分配 27
2.3.2 Spark 应用程序 . 28
2.4 Spark Job 剖析 29
2.4.1 有向无环图(DAG) 30
2.4.2 作业(Job) 31
2.4.3 阶段(Stage) 31
2.4.4 任务(Task) 32
2.5 小结 34
第 3 章 DataFrame、Dataset 和Spark SQL 35
3.1 从 SparkSession(或者 HiveContext 和 SQLContext)入门 . 36
3.2 Spark SQL 依赖 39
3.2.1 管理 Spark 依赖 39
3.2.2 避免使用 Hive JAR 40
3.3 schema 基础 41
3.4 DataFrame API 45
3.4.1 转换 45
3.4.2 基于多个 DataFrame 的转换 . 56
3.4.3 普通的 SQL 查询以及与 Hive 数据交互 . 57
3.5 DataFrame 和 Dataset 中的数据表示 . 58
3.6 数据加载和保存函数 . 59
3.6.1 DataFrameWriter 和 DataFrameReader . 60
3.6.2 格式 60
3.6.3 保存模式 70
3.6.4 分区(发现和写入) . 70
3.7 Dataset 71
3.7.1 与 RDD、DataFrame 和本地集合的互操作性 72
3.7.2 编译时强类型 73
3.7.3 简易函数式转换操作(类似 RDD) . 74
3.7.4 关系型转换操作 74
3.7.5 多 Dataset 关系转换操作 . 75
3.7.6 Dataset 的分组操作 75
3.8 使用用户自定义的函数和聚合函数(UDF、UDAF)进行扩展 . 76
3.9 查询优化器 . 79
3.9.1 逻辑和物理计划 79
3.9.2 代码生成 79
3.9.3 大型查询计划和迭代算法 80
3.10 调试 Spark SQL 查询 80
3.11 JDBC/ODBC 服务器 81
3.12 小结 . 82
第 4 章 Join (SQL 和Spark Core) 84
4.1 Spark Core 中的 Join . 84
4.1.1 选择 Join 类型 86
4.1.2 选择执行计划 88
4.2 Spark SQL 中的 Join 91
4.2.1 DataFrame 的 Join 91
4.2.2 Dataset 的 Join 95
4.3 小结 96
第 5 章 高效的转换 .97
5.1 窄转换与宽转换 98
5.1.1 对于性能的影响 100
5.1.2 对于容错的影响 101
5.1.3 coalesce 的特殊情况 102
5.2 转换会返回什么类型的 RDD . 102
5.3 最小化对象创建成本 104
5.3.1 重用现有对象 . 104
5.3.2 使用更小的数据结构 108
5.4 mapPartitions 迭代器到迭代器的转换 111
5.4.1 什么是迭代器到迭代器的转换? 112
5.4.2 空间和时间优势 113
5.4.3 案例 . 114
5.5 集合操作 117
5.6 降低初始化开销 118
5.6.1 共享变量 119
5.6.2 广播变量 119
5.6.3 累加器 121
5.7 重用 RDD . 125
5.7.1 重用的案例 126
5.7.2 判断重新计算是否足够划算 129
5.7.3 重用类型:缓存、持久化、检查点、shuffle 文件 130
5.7.4 Alluxio(之前的 Tachyon) 135
5.7.5 LRU 缓存 . 135
5.7.6 繁忙集群的注意事项 137
5.7.7 与累加器交互 . 138
5.8 小结 . 139
第 6 章 处理键值对数据 . 140
6.1 金发女孩案例 . 142
6.1.1 金发女孩之版本 0:迭代方案 143
6.1.2 如何使用 PairRDDFunctions 和 OrderedRDDFunctions 146
6.2 键值对上的行动操作 147
6.3 groupByKey 函数有什么风险 . 148
6.3.1 金发女孩之版本 1:groupByKey 方案 148
6.3.2 为什么 groupByKey 会失败 150
6.4 选择聚合操作 . 152
6.5 涉及多个 RDD 的操作 156
6.6 分区器和键值对数据 157
6.6.1 使用 Spark 的分区器对象 . 158
6.6.2 哈希分区 158
6.6.3 范围分区 159
6.6.4 自定义分区 160
6.6.5 保留跨不同转换的分区信息 160
6.6.6 利用协同位置(Co-located)和协同分区(Co-Partitioned)
的 RDD 161
6.6.7 PairRDDFunctions 中关于映射和分区函数的字典 163
6.7 OrderedRDDFunctions 字典 165
6.8 二级排序和 repartitionAndSortWithinPartitions 167
6.8.1 在按键分组和按值排序的函数中利用
repartitionAndSortWithinPartitions 168
6.8.2 如何不按照两个排序键排序 172
6.8.3 金发女孩之版本 2:二级排序 172
6.8.4 金发女孩问题的另外一种不同解法 . 176
6.8.5 金发女孩之版本 3:对单元格值排序 . 181
6.9 掉队检测与不均衡数据 . 182
6.9.1 再次回到金发女孩问题 . 184
6.9.2 金发女孩之版本 4:在每个分区上归并为不同值 184
6.10 小结 191
第 7 章 Scala 之外 192
7.1 JVM 之内、Scala 之外 194
7.2 Scala 之外、JVM 之外 198
7.2.1 PySpark 工作原理 . 198
7.2.2 SparkR 工作原理 207
7.2.3 Spark.jl(Julia Spark) 209
7.2.4 Eclair JS 工作原理 210
7.2.5 Spark 基于公共语言运行时(CLR),C# 及类似语言 211
7.3 在 Spark 中调用其他语言 . 211
7.3.1 使用管道及类似工具 211
7.3.2 JNI 213
7.3.3 Java 本地访问(JNA) . 216
7.3.4 一切的背后都是 FORTRAN 217
7.3.5 谈谈 GPU . 218
7.4 未来 . 219
7.5 小结 . 219
第 8 章 测试和验证 221
8.1 单元测试 221
8.1.1 一般 Spark 单元测试 222
8.1.2 模拟 RDD . 227
8.2 获取测试数据 . 228
8.2.1 生成大数据集 . 229
8.2.2 抽样 . 230
8.3 用 ScalaCheck 检查属性 232
8.4 集成测试 235
8.5 性能验证 237
8.5.1 用于性能验证的 Spark 计数器 237
8.5.2 性能验证相关项目 238
8.6 作业验证 239
8.7 小结 . 240
第 9 章 Spark MLlib 和ML 241
9.1 在 Spark MLlib 和 Spark ML 之间选择 . 241
9.2 使用 MLlib 242
9.2.1 MLlib 入门(组织和导入) 242
9.2.2 MLlib 特征编码和数据准备 244
9.2.3 特征缩放和选择 248
9.2.4 MLlib 模型训练 . 249
9.2.5 预测 . 250
9.2.6 服务和持久化 . 251
9.2.7 模型评估 254
9.3 使用 Spark ML 254
9.3.1 Spark ML 组织和导入 254
9.3.2 管道阶段 256
9.3.3 参数解释 257
9.3.4 数据编码 258
9.3.5 数据清洗 261
9.3.6 Spark ML 模型 261
9.3.7 整合成管道 262
9.3.8 训练管道 263
9.3.9 访问单个阶段 . 264
9.3.10 数据持久化和 Spark ML . 264
9.3.11 使用自定义算法扩展 Spark ML 管道 267
9.3.12 模型和管道持久化与 Spark ML 服务 275
9.4 一般服务考量因素 276
9.5 小结 . 276
第 10 章 Spark 组件和包 278
10.1 基于 Spark 的流处理 280
10.1.1 Source 和 Sink . 281
10.1.2 批处理间隔 283
10.1.3 数据 checkpoint 间隔 284
10.1.4 DStream 的注意事项 284
10.1.5 Structured Streaming 的考量因素 286
10.1.6 高可用性模式(或处理 Driver 程序故障或进行 checkpoint) 294
10.2 GraphX 295
10.3 使用社区包和库 295
10.4 小结 298
附录 调优、调试以及开发者容易忽略的其他问题 301