内容简介
本书描述了减少数据基础设施成本和开发时间的技巧,适用于软件工程师、数据工程师、开发者和系统管理员。你不仅可以从中获得关于Spark的全面理解,也将学会如何让它运转自如。
在本书中你将发现:
* Spark SQL的新接口如何在SQL的RDD数据结构上改善性能
* Core Spark和Spark SQL之间的数据拼接选择
* 充分发挥标准RDD转换功能的技巧
* 如何处理Spark的键/值对范式的相关性能问题
* 编写高性能Spark代码,不使用Scala或JVM
* 如何在应用建议的改进措施时测试功能和性能
* 使用Spark MLlib和Spark ML机器学习库
* Spark的流组件和外部社区软件包
作者简介
Holden Karau是一位跨性别加拿大人,在IBM Spark技术中心担任软件开发工程师。她是Spark代码贡献者,并且经常提交贡献代码,特别是PySpark和机器学习部分。Holden在多个国际活动中演讲Spark相关话题。
Rachel Warren是Alpine Data的软件工程师和数据科学家。在日常工作中,她使用Spark来处理真实世界的数据和机器学习问题。她也曾在工业界和学术界担任分析师和导师。
精彩书评
“《高性能Spark》是帮助你实现Apache Spark产品级解决方案的重要资源。由此不仅可以理解重要的Spark优化方法,还有底层的内部细节。”
—— Denny Lee(微软资深项目经理,Azure DocumentDB团队)
目录
Preface
1.Introduction to High Performance Spark
What Is Spark and Why Performance Matters
What You Can Expect to Get from This Book
Spark Versions
Why Scala?
To Be a Spark Expert You Have to Learn a Little Scala Anyway
The Spark Scala API Is Easier to Use Than the lava API
Scala Is More Performant Than Python
Why Not Scala?
Learning Scala
Conclusion
2.How Spark Works
How Spark Fits into the Big Data Ecosystem
Spark Components
Spark Model of Parallel Computing: RDDs
Lazy Evaluation
In-Memory Persistence and Memory Management
Immutability and the RDD Interface
Types of RDDs
Functions on RDDs: Transformations Versus Actions
Wide Versus Narrow Dependencies
Spark Job Scheduling
Resource Allocation Across Applications
The Spark Application
The Anatomy of a Spark lob
The DAG
Jobs
Stages
Tasks
Conclusion
3.DataFrames, Datasets, and Spark SQL
Getting Started with the SparkSession (or HiveContext or SQLContext)
Spark SQL Dependencies
Managing Spark Dependencies
Avoiding Hive JARs
Basics of Schemas
DataFrame API
Transformations
Multi-DataFrame Transformations
Plain Old SQL Queries and Interacting with Hive Data
Data Representation in DataFrames and Datasets
Tungsten
Data Loading and Saving Functions
DataFrameWriter and DataFrameReader
Formats
Save Modes
Partitions (Discovery and Writing)
Datasets
Interoperability with RDDs, DataFrames, and Local Collections
Compile-Time Strong Typing
Easier Functional (RDD "like") Transformations
Relational Transformations
Multi-Dataset Relational Transformations
Grouped Operations on Datasets
Extending with User-Defined Functions and Aggregate Functions (UDFs,UDAFs)
Query Optimizer
Logical and Physical Plans
Code Generation
Large Query Plans and Iterative Algorithms
Debugging Spark SQL Queries
JDBC/ODBC Server
Conclusion
4.Joins (SQL and Core)
Core Spark Joins
Choosing a Join Type
Choosing an Execution Plan
Spark SQL Joins
DataFrame Joins
Dataset Joins
Conclusion
5.Effective Transformations
Narrow Versus Wide Transformations
Implications for Performance
Implications for Fault Tolerance
The Special Case of coalesce
What Type of RDD Does Your Transformation Return?
Minimizing Object Creation
Reusing Existing Objects
Using Smaller Data Structures
Iterator-to-Iterator Transformations with mapPartitions
What Is an Iterator-to-Iterator Transformation?
Space and Time Advantages
An Example
Set Operations
Reducing Setup Overhead
Shared Variables
Broadcast Variables
Accumulators
Reusing RDDs
Cases for Reuse
Deciding if Recompute Is Inexpensive Enough
Types of Reuse: Cache, Persist, Checkpoint, Shuffle Files
Alluxio (nee Tachyon)
LRU Caching
Noisy Cluster Considerations
Interaction with Accumulators
Conclusion
6.Working with Key/Value Data
The Goldilocks Example
Goldilocks Version 0: Iterative Solution
How to Use PairRDDFunctions and OrderedRDDFunctions
Actions on Key/Value Pairs
What's So Dangerous About the groupByKey Function
Goldilocks Version 1: groupByKey Solution
Choosing an Aggregation Operation
Dictionary of Aggregation Operations with Performance Considerations
Multiple RDD Operations
Co-Grouping
Partitioners and Key/Value Data
Using the Spark Partitioner Object
Hash Partitioning
Range Partitioning
Custom Partitioning
Preserving Partitioning Information Across Transformations
Leveraging Co-Located and Co-Partitioned RDDs
Dictionary of Mapping and Partitioning Functions PairRDDFunctions
Dictionary of OrderedRDDOperations
Sorting by Two Keys with SortByKey
Secondary Sort and repartitionAndSortWithinPartitions
Leveraging repartitionAndSortWithinPartitions for a Group by Key and Sort Values Function
How Not to Sort by Two Orderings
Goldilocks Version 2: Secondary Sort
A Different Approach to Goldilocks
Goldilocks Version 3: Sort on Cell Values
Straggler Detection and Unbalanced Data
Back to Goldilocks (Again)
Goldilocks Version 4: Reduce to Distinct on Each Partition
Conclusion
7.Going Beyond Scala
Beyond Scala within the JVM
Beyond Scala, and Beyond the JVM
How PySpark Works
How SparkR Works
Spark.jl (Julia Spark)
How Eclair JS Works
Spark on the Common Language Runtime (CLR)——C# and Friends
Calling Other Languages from Spark
Using Pipe and Friends
JNI
Java Native Access (JNA)
Underneath Everything Is FORTRAN
Getting to the GPU
The Future
Conclusion
8.Testing and Validation
Unit Testing
General Spark Unit Testing
Mocking RDDs
Getting Test Data
Generating Large Datasets
Sampling
Property Checking with ScalaCheck
Computing RDD Difference
Integration Testing
Choosing Your Integration Testing Environment
Verifying Performance
Spark Counters for Verifying Performance
Projects for Verifying Performance
Job Validation
Conclusion
9.Spark MLlib and ML
Choosing Between Spark MLlib and Spark ML
Working with MLlib
Getting Started with MLlib (Organization and Imports)
MLlib Feature Encoding and Data Preparation
Feature Scaling and Selection
MLlib Model Training
Predicting
Serving and Persistence
Model Evaluation
Working with Spark ML
Spark ML Organization and Imports
Pipeline Stages
Explain Params
Data Encoding
Data Cleaning
Spark ML Models
Putting It All Together in a Pipeline
Training a Pipeline
Accessing Individual Stages
Data Persistence and Spark ML
Extending Spark ML Pipelines with Your Own Algorithms
Model and Pipeline Persistence and Serving with Spark ML
General Serving Considerations
Conclusion
10.Spark Components and Packages
Stream Processing with Spark
Sources and Sinks
Batch Intervals
Data Checkpoint Intervals
Considerations for DStreams
Considerations for Structured Streaming
High Availability Mode (or Handling Driver Failure or Checkpointing)
GraphX
Using Community Packages and Libraries
Creating a Spark Package
Conclusion
A.Tuning, Debugging, and Other Things Developers Like to Pretend Don't Exist
Index
深入剖析分布式计算的基石:以卓越性能驱动大数据革命 本书并非一本单纯的技术手册,而是一次深刻的分布式计算之旅,旨在揭示现代大数据处理的深层机制,并提供一套系统性的方法论,以构建和优化高性能的Spark应用程序。它不仅仅是传授API的使用技巧,更侧重于理解Spark底层原理,从而在面对海量数据和复杂计算任务时,能够游刃有余地设计出高效、可扩展且健壮的解决方案。 第一部分:理解Spark的核心——性能的基石 本部分将带领读者从宏观到微观,逐步揭开Spark的神秘面纱。我们将首先建立对Spark整体架构的深刻理解,包括Master、Worker、Driver、Executor等核心组件的职责和交互方式。在此基础上,我们将深入探讨Spark的执行模型,特别是其革命性的RDD(弹性分布式数据集)抽象。读者将了解到RDD的惰性求值、容错机制(Lineage)以及其作为数据处理基础的强大之处。 随后的章节将重点关注Spark的核心执行引擎——DAG(有向无环图)调度器。我们将详细解析Spark如何将用户的操作转化为一系列的Stage和Task,以及Task是如何在Executor上并行执行的。理解DAG调度器的内部工作原理,对于诊断性能瓶颈、优化任务执行顺序至关重要。 数据分区(Partitioning)是分布式计算中的关键概念,也是Spark性能的重中之重。我们将深入探讨Spark中数据分区的概念、不同的分区策略(如Hash Partitioning、Range Partitioning),以及它们如何直接影响数据shuffle的效率和计算的并行度。读者将学会如何根据数据特性和计算需求,选择最合适的分区方式,从而最大程度地减少数据移动和网络开销。 Shuffle是Spark中成本最高的操作之一,它涉及到数据的重新分布和聚合。本部分将对Shuffle的内部机制进行详尽的剖析,包括Shuffle Map Task和Shuffle Reduce Task的交互过程,以及Spark如何通过各种优化技术(如Tungsten、Catalyst优化器)来提升Shuffle的性能。掌握Shuffle的细节,意味着掌握了Spark性能调优的“牛鼻子”。 第二部分:精进Spark应用程序——性能优化的实践之道 在建立了对Spark底层原理的扎实理解后,本部分将把焦点转向如何将这些知识转化为实际的应用程序优化。我们将从数据读取和写入的效率入手,探讨如何选择合适的数据源格式(如Parquet、ORC),以及如何配置Spark的输入/输出参数以获得最佳性能。 内存管理是Spark性能优化的另一大核心。我们将深入解析Spark的内存模型,包括Executor内存的划分(Storage Memory、Execution Memory、User Memory)、内存溢出(OOM)的成因以及各种规避和处理策略。读者将学会如何有效地利用内存,将关键数据缓存(Caching)到内存中,避免不必要的磁盘I/O,从而显著提升计算速度。 数据序列化是Spark在节点间传输数据时必不可少的一环,其效率直接影响着网络的吞吐量。本部分将深入比较Kryo、Java序列化等不同的序列化机制,并指导读者如何选择并配置最适合自身应用场景的序列化器,以最小化数据传输的开销。 Spark SQL是Spark生态中最受欢迎的模块之一,它提供了强大的声明式查询能力。本部分将深入解析Spark SQL的Catalyst优化器。读者将了解到Catalyst是如何解析SQL语句,生成逻辑计划和物理计划,以及如何通过各种优化规则(如常量折叠、谓词下推、列裁剪)来显著提升查询性能。掌握Catalyst的原理,意味着掌握了SQL查询优化的“秘密武器”。 缓存(Caching)和持久化(Persistence)是Spark中提升重复计算效率的关键手段。本部分将详细讲解`cache()`、`persist()`等方法的用法,并深入探讨不同持久化级别(如`MEMORY_ONLY`、`MEMORY_AND_DISK`)的权衡,以及何时使用它们才能最大化收益。 第三部分:高级主题与最佳实践——构建健壮高效的分布式系统 在掌握了Spark的基础和优化技巧后,本部分将进一步深入到更高级的主题,以帮助读者构建真正健壮且高性能的分布式应用程序。 流式计算是大数据领域日益重要的一个方向,Spark Streaming(以及其演进版本Spark Structured Streaming)提供了强大的流处理能力。本部分将深入探讨Spark Streaming的微批处理模型,以及如何理解和优化其延迟和吞吐量。读者将学习到如何处理事件时间、窗口操作以及如何应对流数据中的异常情况。 对于那些需要处理海量数据并对延迟有极致要求的应用,广播(Broadcasting)变量和累加器(Accumulators)是不可或缺的工具。本部分将详细讲解它们的原理、使用场景以及最佳实践,帮助读者在分布式环境中高效地共享和聚合数据。 性能调优是一个持续迭代的过程。本部分将指导读者如何有效地利用Spark的监控工具(如Web UI、Metrics)来识别性能瓶颈。我们将学习如何解读执行计划、查看任务执行详情、分析GC(垃圾回收)情况,并根据监控结果制定相应的优化策略。 最后,本部分还将探讨Spark在生产环境中的部署、监控和故障排除的最佳实践。我们将讨论如何配置Spark集群以适应不同的工作负载,如何处理常见的性能问题和稳定性挑战,以及如何构建一个可维护、可扩展的Spark数据处理管道。 总结 本书通过深入剖析Spark的底层原理,结合大量的实际应用场景和优化技巧,旨在为读者提供一套完整的、体系化的高性能Spark开发指南。它不仅仅教会你“如何做”,更重要的是让你理解“为什么这样做”,从而赋能你构建出真正能够应对大数据挑战的卓越应用程序。无论你是希望提升现有Spark应用的性能,还是计划从零开始构建高性能的数据处理解决方案,本书都将是你不可或缺的宝贵资源。它将引导你穿越复杂的技术细节,抵达性能优化的彼岸,让你成为一名真正意义上的Spark性能专家。