大数据内存计算引擎Spark万字入门|从Hadoop痛点到Spark核心原理全梳理

前言

刚接触大数据的时候,我最先学的是Hadoop相关计算,早期只用MapReduce写WordCount跑任务要等半天,多轮迭代场景磁盘IO直接卡死集群。后来才知道,Spark就是为了解决MR磁盘读写慢的痛点而生。

本文完整整合Spark全套学习资料,从Spark基础、RDD核心、Spark SQL、Spark Streaming、MLlib&GraphX由浅入深讲解,配套Mermaid流程图、可运行PySpark代码、对比表格、原理示意图,零基础也能看懂,适合大数据初学者、面试复习、开发查阅。

一、Hadoop回顾:MapReduce的致命短板

1.1 Hadoop完整生态架构

Hadoop完整生态由三大核心组件共同组成,三者配合才算一套完整大数据平台:

  1. HDFS:分布式文件存储,负责海量数据持久化;
  2. YARN:资源调度框架,统一管理集群CPU、内存资源;
  3. MapReduce :第一代分布式批处理计算框架,仅负责计算逻辑。

#mermaid-svg-nbS36xN62B3epThs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nbS36xN62B3epThs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nbS36xN62B3epThs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nbS36xN62B3epThs .error-icon{fill:#552222;}#mermaid-svg-nbS36xN62B3epThs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nbS36xN62B3epThs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nbS36xN62B3epThs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nbS36xN62B3epThs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nbS36xN62B3epThs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nbS36xN62B3epThs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nbS36xN62B3epThs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nbS36xN62B3epThs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nbS36xN62B3epThs .marker.cross{stroke:#333333;}#mermaid-svg-nbS36xN62B3epThs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nbS36xN62B3epThs p{margin:0;}#mermaid-svg-nbS36xN62B3epThs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nbS36xN62B3epThs .cluster-label text{fill:#333;}#mermaid-svg-nbS36xN62B3epThs .cluster-label span{color:#333;}#mermaid-svg-nbS36xN62B3epThs .cluster-label span p{background-color:transparent;}#mermaid-svg-nbS36xN62B3epThs .label text,#mermaid-svg-nbS36xN62B3epThs span{fill:#333;color:#333;}#mermaid-svg-nbS36xN62B3epThs .node rect,#mermaid-svg-nbS36xN62B3epThs .node circle,#mermaid-svg-nbS36xN62B3epThs .node ellipse,#mermaid-svg-nbS36xN62B3epThs .node polygon,#mermaid-svg-nbS36xN62B3epThs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nbS36xN62B3epThs .rough-node .label text,#mermaid-svg-nbS36xN62B3epThs .node .label text,#mermaid-svg-nbS36xN62B3epThs .image-shape .label,#mermaid-svg-nbS36xN62B3epThs .icon-shape .label{text-anchor:middle;}#mermaid-svg-nbS36xN62B3epThs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nbS36xN62B3epThs .rough-node .label,#mermaid-svg-nbS36xN62B3epThs .node .label,#mermaid-svg-nbS36xN62B3epThs .image-shape .label,#mermaid-svg-nbS36xN62B3epThs .icon-shape .label{text-align:center;}#mermaid-svg-nbS36xN62B3epThs .node.clickable{cursor:pointer;}#mermaid-svg-nbS36xN62B3epThs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nbS36xN62B3epThs .arrowheadPath{fill:#333333;}#mermaid-svg-nbS36xN62B3epThs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nbS36xN62B3epThs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nbS36xN62B3epThs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nbS36xN62B3epThs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nbS36xN62B3epThs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nbS36xN62B3epThs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nbS36xN62B3epThs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nbS36xN62B3epThs .cluster text{fill:#333;}#mermaid-svg-nbS36xN62B3epThs .cluster span{color:#333;}#mermaid-svg-nbS36xN62B3epThs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nbS36xN62B3epThs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nbS36xN62B3epThs rect.text{fill:none;stroke-width:0;}#mermaid-svg-nbS36xN62B3epThs .icon-shape,#mermaid-svg-nbS36xN62B3epThs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nbS36xN62B3epThs .icon-shape p,#mermaid-svg-nbS36xN62B3epThs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nbS36xN62B3epThs .icon-shape .label rect,#mermaid-svg-nbS36xN62B3epThs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nbS36xN62B3epThs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nbS36xN62B3epThs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nbS36xN62B3epThs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端提交任务
YARN ResourceManager 资源总管
NodeManager 节点1
NodeManager 节点2
Map阶段任务
本地磁盘/ HDFS 落盘中间结果
Reduce阶段任务
Map阶段任务
Reduce阶段任务

1.2 MapReduce核心缺陷

MapReduce每一轮计算中间结果强制写入磁盘,举个WordCount案例:

  1. Map:读取文件,拆分单词,输出(word,1)写入本地磁盘;
  2. Shuffle:读取磁盘数据,按key分组;
  3. Reduce:聚合相同单词计数,再次落地磁盘。

多轮迭代计算(机器学习、多层聚合)会反复读写磁盘,IO开销爆炸,性能极差,这就是Spark诞生的核心背景。

二、Apache Spark 完整介绍

2.1 Spark起源与定义

2009年加州大学伯克利分校AMPLab推出,核心论文《Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing》,提出RDD弹性分布式数据集

官方定义:Apache Spark是用于大规模数据处理的统一内存分析引擎,基于内存做分布式并行计算,中间结果优先存内存,内存不足再溢写到磁盘,大幅降低磁盘IO。

2.2 Spark四大核心特点

1)快:内存计算 + DAG有向无环图调度
  • 内存中运算速度比MapReduce快100倍;磁盘运算快10倍;
  • MapReduce线性分阶段执行,Spark通过DAG合并计算阶段,减少Shuffle与磁盘读写。

#mermaid-svg-tjnHydNk5QjIP3qv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tjnHydNk5QjIP3qv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tjnHydNk5QjIP3qv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tjnHydNk5QjIP3qv .error-icon{fill:#552222;}#mermaid-svg-tjnHydNk5QjIP3qv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tjnHydNk5QjIP3qv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tjnHydNk5QjIP3qv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tjnHydNk5QjIP3qv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tjnHydNk5QjIP3qv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tjnHydNk5QjIP3qv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tjnHydNk5QjIP3qv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tjnHydNk5QjIP3qv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tjnHydNk5QjIP3qv .marker.cross{stroke:#333333;}#mermaid-svg-tjnHydNk5QjIP3qv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tjnHydNk5QjIP3qv p{margin:0;}#mermaid-svg-tjnHydNk5QjIP3qv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tjnHydNk5QjIP3qv .cluster-label text{fill:#333;}#mermaid-svg-tjnHydNk5QjIP3qv .cluster-label span{color:#333;}#mermaid-svg-tjnHydNk5QjIP3qv .cluster-label span p{background-color:transparent;}#mermaid-svg-tjnHydNk5QjIP3qv .label text,#mermaid-svg-tjnHydNk5QjIP3qv span{fill:#333;color:#333;}#mermaid-svg-tjnHydNk5QjIP3qv .node rect,#mermaid-svg-tjnHydNk5QjIP3qv .node circle,#mermaid-svg-tjnHydNk5QjIP3qv .node ellipse,#mermaid-svg-tjnHydNk5QjIP3qv .node polygon,#mermaid-svg-tjnHydNk5QjIP3qv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tjnHydNk5QjIP3qv .rough-node .label text,#mermaid-svg-tjnHydNk5QjIP3qv .node .label text,#mermaid-svg-tjnHydNk5QjIP3qv .image-shape .label,#mermaid-svg-tjnHydNk5QjIP3qv .icon-shape .label{text-anchor:middle;}#mermaid-svg-tjnHydNk5QjIP3qv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tjnHydNk5QjIP3qv .rough-node .label,#mermaid-svg-tjnHydNk5QjIP3qv .node .label,#mermaid-svg-tjnHydNk5QjIP3qv .image-shape .label,#mermaid-svg-tjnHydNk5QjIP3qv .icon-shape .label{text-align:center;}#mermaid-svg-tjnHydNk5QjIP3qv .node.clickable{cursor:pointer;}#mermaid-svg-tjnHydNk5QjIP3qv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tjnHydNk5QjIP3qv .arrowheadPath{fill:#333333;}#mermaid-svg-tjnHydNk5QjIP3qv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tjnHydNk5QjIP3qv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tjnHydNk5QjIP3qv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tjnHydNk5QjIP3qv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tjnHydNk5QjIP3qv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tjnHydNk5QjIP3qv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tjnHydNk5QjIP3qv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tjnHydNk5QjIP3qv .cluster text{fill:#333;}#mermaid-svg-tjnHydNk5QjIP3qv .cluster span{color:#333;}#mermaid-svg-tjnHydNk5QjIP3qv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tjnHydNk5QjIP3qv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tjnHydNk5QjIP3qv rect.text{fill:none;stroke-width:0;}#mermaid-svg-tjnHydNk5QjIP3qv .icon-shape,#mermaid-svg-tjnHydNk5QjIP3qv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tjnHydNk5QjIP3qv .icon-shape p,#mermaid-svg-tjnHydNk5QjIP3qv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tjnHydNk5QjIP3qv .icon-shape .label rect,#mermaid-svg-tjnHydNk5QjIP3qv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tjnHydNk5QjIP3qv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tjnHydNk5QjIP3qv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tjnHydNk5QjIP3qv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Spark DAG调度
Map1
FlatMap
ReduceByKey
Hadoop MapReduce 线性执行
Map1
落盘
Reduce1
落盘
Map2
落盘
Reduce2

2)易用:多语言API

支持Java、Scala、Python(PySpark)、R、SQL,代码简洁,示例:

python 复制代码
# PySpark DataFrame极简示例
from pyspark.sql import SparkSession
spark = SparkSession.builder.master("local[*]").appName("demo").getOrCreate()
df = spark.read.json("test.json")
df.where("age > 21").select("name").show()
3)通用:一套引擎覆盖全大数据场景

内置5大组件,批处理、SQL、实时流、机器学习、图计算无缝切换。

4)兼容性:多集群、多数据源支持
  • 运行集群:Standalone、YARN、Mesos、K8s;
  • 存储数据源:HDFS、Hive、MySQL、Cassandra、本地文件等。

2.3 Hadoop生态 VS Spark 详细对比(修正定位错误)

对比维度 Hadoop生态(HDFS+YARN+MapReduce) Spark
产品定位 完整大数据平台,包含存储、资源调度、MapReduce计算框架 统一内存分布式计算引擎,无存储/调度能力,可对接各类存储、调度系统
计算组件 MapReduce,第一代批计算框架 Spark Core/RDD,内存式计算核心
中间数据存储 MapReduce强制落地磁盘,高延迟 中间结果优先内存,溢出写磁盘,低延迟
任务调度 MapReduce线性分阶段执行,无DAG优化 DAG有向无环图规划任务,减少Shuffle次数
适用场景 海量冷数据一次性离线批处理 离线批、交互式查询、实时流、机器学习迭代计算
硬件要求 集群内存要求低,低配机器可运行 对集群内存资源要求更高,硬件成本偏高
编程范式 底层Map+Reduce,算子单一,开发繁琐 RDD/DF多层API,算子丰富,开发效率高

2.4 关键认知:Spark不能替代Hadoop生态

  1. Spark只负责计算 ,自身不提供分布式存储、集群资源调度,生产环境标配HDFS存储 + YARN调度 + Spark计算
  2. Hive数仓、传统离线任务大量基于MapReduce开发,生态稳定成熟,无法完全被Spark替换。

三、Spark完整生态(五大核心模块)

所有组件全部基于Spark Core底层引擎构建:
#mermaid-svg-RclkRr1ZPU63okxU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RclkRr1ZPU63okxU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RclkRr1ZPU63okxU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RclkRr1ZPU63okxU .error-icon{fill:#552222;}#mermaid-svg-RclkRr1ZPU63okxU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RclkRr1ZPU63okxU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RclkRr1ZPU63okxU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RclkRr1ZPU63okxU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RclkRr1ZPU63okxU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RclkRr1ZPU63okxU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RclkRr1ZPU63okxU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RclkRr1ZPU63okxU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RclkRr1ZPU63okxU .marker.cross{stroke:#333333;}#mermaid-svg-RclkRr1ZPU63okxU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RclkRr1ZPU63okxU p{margin:0;}#mermaid-svg-RclkRr1ZPU63okxU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RclkRr1ZPU63okxU .cluster-label text{fill:#333;}#mermaid-svg-RclkRr1ZPU63okxU .cluster-label span{color:#333;}#mermaid-svg-RclkRr1ZPU63okxU .cluster-label span p{background-color:transparent;}#mermaid-svg-RclkRr1ZPU63okxU .label text,#mermaid-svg-RclkRr1ZPU63okxU span{fill:#333;color:#333;}#mermaid-svg-RclkRr1ZPU63okxU .node rect,#mermaid-svg-RclkRr1ZPU63okxU .node circle,#mermaid-svg-RclkRr1ZPU63okxU .node ellipse,#mermaid-svg-RclkRr1ZPU63okxU .node polygon,#mermaid-svg-RclkRr1ZPU63okxU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RclkRr1ZPU63okxU .rough-node .label text,#mermaid-svg-RclkRr1ZPU63okxU .node .label text,#mermaid-svg-RclkRr1ZPU63okxU .image-shape .label,#mermaid-svg-RclkRr1ZPU63okxU .icon-shape .label{text-anchor:middle;}#mermaid-svg-RclkRr1ZPU63okxU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RclkRr1ZPU63okxU .rough-node .label,#mermaid-svg-RclkRr1ZPU63okxU .node .label,#mermaid-svg-RclkRr1ZPU63okxU .image-shape .label,#mermaid-svg-RclkRr1ZPU63okxU .icon-shape .label{text-align:center;}#mermaid-svg-RclkRr1ZPU63okxU .node.clickable{cursor:pointer;}#mermaid-svg-RclkRr1ZPU63okxU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RclkRr1ZPU63okxU .arrowheadPath{fill:#333333;}#mermaid-svg-RclkRr1ZPU63okxU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RclkRr1ZPU63okxU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RclkRr1ZPU63okxU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RclkRr1ZPU63okxU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RclkRr1ZPU63okxU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RclkRr1ZPU63okxU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RclkRr1ZPU63okxU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RclkRr1ZPU63okxU .cluster text{fill:#333;}#mermaid-svg-RclkRr1ZPU63okxU .cluster span{color:#333;}#mermaid-svg-RclkRr1ZPU63okxU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RclkRr1ZPU63okxU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RclkRr1ZPU63okxU rect.text{fill:none;stroke-width:0;}#mermaid-svg-RclkRr1ZPU63okxU .icon-shape,#mermaid-svg-RclkRr1ZPU63okxU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RclkRr1ZPU63okxU .icon-shape p,#mermaid-svg-RclkRr1ZPU63okxU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RclkRr1ZPU63okxU .icon-shape .label rect,#mermaid-svg-RclkRr1ZPU63okxU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RclkRr1ZPU63okxU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RclkRr1ZPU63okxU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RclkRr1ZPU63okxU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Spark Core 底层核心 RDD
Spark SQL 结构化数据
Spark Streaming 微批实时流
MLlib 分布式机器学习
GraphX 分布式图计算
Structured Streaming 流批一体

  1. Spark Core:Spark底层核心,RDD为基础数据抽象,提供多语言底层API,离线批处理基础;
  2. Spark SQL:处理结构化数据,抽象DataFrame,支持SQL/DSL双写法,兼容Hive元数据;
  3. Spark Streaming:基于DStream微批实时计算,处理日志、实时数据流;
  4. MLlib:分布式机器学习库,内置分类、回归、聚类、协同过滤、特征工程算法;
  5. GraphX:图计算组件,处理顶点、边结构数据,内置PageRank、连通分量、最短路径。

四、Spark四种运行模式

#mermaid-svg-SnUU4QWpWto0uaIF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SnUU4QWpWto0uaIF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SnUU4QWpWto0uaIF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SnUU4QWpWto0uaIF .error-icon{fill:#552222;}#mermaid-svg-SnUU4QWpWto0uaIF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SnUU4QWpWto0uaIF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SnUU4QWpWto0uaIF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SnUU4QWpWto0uaIF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SnUU4QWpWto0uaIF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SnUU4QWpWto0uaIF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SnUU4QWpWto0uaIF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SnUU4QWpWto0uaIF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SnUU4QWpWto0uaIF .marker.cross{stroke:#333333;}#mermaid-svg-SnUU4QWpWto0uaIF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SnUU4QWpWto0uaIF p{margin:0;}#mermaid-svg-SnUU4QWpWto0uaIF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-SnUU4QWpWto0uaIF .cluster-label text{fill:#333;}#mermaid-svg-SnUU4QWpWto0uaIF .cluster-label span{color:#333;}#mermaid-svg-SnUU4QWpWto0uaIF .cluster-label span p{background-color:transparent;}#mermaid-svg-SnUU4QWpWto0uaIF .label text,#mermaid-svg-SnUU4QWpWto0uaIF span{fill:#333;color:#333;}#mermaid-svg-SnUU4QWpWto0uaIF .node rect,#mermaid-svg-SnUU4QWpWto0uaIF .node circle,#mermaid-svg-SnUU4QWpWto0uaIF .node ellipse,#mermaid-svg-SnUU4QWpWto0uaIF .node polygon,#mermaid-svg-SnUU4QWpWto0uaIF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SnUU4QWpWto0uaIF .rough-node .label text,#mermaid-svg-SnUU4QWpWto0uaIF .node .label text,#mermaid-svg-SnUU4QWpWto0uaIF .image-shape .label,#mermaid-svg-SnUU4QWpWto0uaIF .icon-shape .label{text-anchor:middle;}#mermaid-svg-SnUU4QWpWto0uaIF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SnUU4QWpWto0uaIF .rough-node .label,#mermaid-svg-SnUU4QWpWto0uaIF .node .label,#mermaid-svg-SnUU4QWpWto0uaIF .image-shape .label,#mermaid-svg-SnUU4QWpWto0uaIF .icon-shape .label{text-align:center;}#mermaid-svg-SnUU4QWpWto0uaIF .node.clickable{cursor:pointer;}#mermaid-svg-SnUU4QWpWto0uaIF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SnUU4QWpWto0uaIF .arrowheadPath{fill:#333333;}#mermaid-svg-SnUU4QWpWto0uaIF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SnUU4QWpWto0uaIF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SnUU4QWpWto0uaIF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SnUU4QWpWto0uaIF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SnUU4QWpWto0uaIF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SnUU4QWpWto0uaIF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SnUU4QWpWto0uaIF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SnUU4QWpWto0uaIF .cluster text{fill:#333;}#mermaid-svg-SnUU4QWpWto0uaIF .cluster span{color:#333;}#mermaid-svg-SnUU4QWpWto0uaIF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SnUU4QWpWto0uaIF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SnUU4QWpWto0uaIF rect.text{fill:none;stroke-width:0;}#mermaid-svg-SnUU4QWpWto0uaIF .icon-shape,#mermaid-svg-SnUU4QWpWto0uaIF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SnUU4QWpWto0uaIF .icon-shape p,#mermaid-svg-SnUU4QWpWto0uaIF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SnUU4QWpWto0uaIF .icon-shape .label rect,#mermaid-svg-SnUU4QWpWto0uaIF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SnUU4QWpWto0uaIF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SnUU4QWpWto0uaIF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SnUU4QWpWto0uaIF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Spark运行模式
Local本地模式
Standalone独立集群
YARN集群 生产主流
Kubernetes云原生容器

  1. Local本地模式:单机多线程模拟集群,仅用于开发、测试,线上禁止使用;
  2. Standalone:Spark自研资源调度,无需依赖Hadoop,小型离线集群使用;
  3. YARN模式:企业生产标准方案,Spark任务运行在YARN容器,集群资源复用率最高;
  4. K8s模式:Spark2.3后支持,云原生容器化部署,云上大数据平台专用。

五、Spark集群核心架构与角色

5.1 四大核心角色:Driver、Master、Worker、Executor

#mermaid-svg-EpXlQmuweyFgTQmw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EpXlQmuweyFgTQmw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EpXlQmuweyFgTQmw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EpXlQmuweyFgTQmw .error-icon{fill:#552222;}#mermaid-svg-EpXlQmuweyFgTQmw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EpXlQmuweyFgTQmw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EpXlQmuweyFgTQmw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EpXlQmuweyFgTQmw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EpXlQmuweyFgTQmw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EpXlQmuweyFgTQmw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EpXlQmuweyFgTQmw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EpXlQmuweyFgTQmw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EpXlQmuweyFgTQmw .marker.cross{stroke:#333333;}#mermaid-svg-EpXlQmuweyFgTQmw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EpXlQmuweyFgTQmw p{margin:0;}#mermaid-svg-EpXlQmuweyFgTQmw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EpXlQmuweyFgTQmw .cluster-label text{fill:#333;}#mermaid-svg-EpXlQmuweyFgTQmw .cluster-label span{color:#333;}#mermaid-svg-EpXlQmuweyFgTQmw .cluster-label span p{background-color:transparent;}#mermaid-svg-EpXlQmuweyFgTQmw .label text,#mermaid-svg-EpXlQmuweyFgTQmw span{fill:#333;color:#333;}#mermaid-svg-EpXlQmuweyFgTQmw .node rect,#mermaid-svg-EpXlQmuweyFgTQmw .node circle,#mermaid-svg-EpXlQmuweyFgTQmw .node ellipse,#mermaid-svg-EpXlQmuweyFgTQmw .node polygon,#mermaid-svg-EpXlQmuweyFgTQmw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EpXlQmuweyFgTQmw .rough-node .label text,#mermaid-svg-EpXlQmuweyFgTQmw .node .label text,#mermaid-svg-EpXlQmuweyFgTQmw .image-shape .label,#mermaid-svg-EpXlQmuweyFgTQmw .icon-shape .label{text-anchor:middle;}#mermaid-svg-EpXlQmuweyFgTQmw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EpXlQmuweyFgTQmw .rough-node .label,#mermaid-svg-EpXlQmuweyFgTQmw .node .label,#mermaid-svg-EpXlQmuweyFgTQmw .image-shape .label,#mermaid-svg-EpXlQmuweyFgTQmw .icon-shape .label{text-align:center;}#mermaid-svg-EpXlQmuweyFgTQmw .node.clickable{cursor:pointer;}#mermaid-svg-EpXlQmuweyFgTQmw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EpXlQmuweyFgTQmw .arrowheadPath{fill:#333333;}#mermaid-svg-EpXlQmuweyFgTQmw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EpXlQmuweyFgTQmw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EpXlQmuweyFgTQmw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EpXlQmuweyFgTQmw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EpXlQmuweyFgTQmw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EpXlQmuweyFgTQmw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EpXlQmuweyFgTQmw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EpXlQmuweyFgTQmw .cluster text{fill:#333;}#mermaid-svg-EpXlQmuweyFgTQmw .cluster span{color:#333;}#mermaid-svg-EpXlQmuweyFgTQmw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EpXlQmuweyFgTQmw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EpXlQmuweyFgTQmw rect.text{fill:none;stroke-width:0;}#mermaid-svg-EpXlQmuweyFgTQmw .icon-shape,#mermaid-svg-EpXlQmuweyFgTQmw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EpXlQmuweyFgTQmw .icon-shape p,#mermaid-svg-EpXlQmuweyFgTQmw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EpXlQmuweyFgTQmw .icon-shape .label rect,#mermaid-svg-EpXlQmuweyFgTQmw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EpXlQmuweyFgTQmw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EpXlQmuweyFgTQmw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EpXlQmuweyFgTQmw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Standalone集群
Driver 驱动程序
Master 集群资源管理者
Worker 节点进程1
Worker 节点进程2
Executor 执行器1
Task 计算任务
内存缓存RDD
Executor 执行器2
Task 计算任务

  1. Driver :程序主入口,创建SparkContext/SparkSession,封装任务、生成DAG、调度任务;
  2. Master(仅Standalone模式):集群资源总管,分配内存CPU给Worker节点;
  3. Worker:每台服务器守护进程,接收Master指令,启动Executor;
  4. Executor:运行在节点的执行进程,执行Task,缓存RDD数据,负责实际计算。

第二章 Spark RDD 核心(Spark底层基石)

2.1 RDD定义与三大特性

RDD全称Resilient Distributed Dataset 弹性分布式数据集,Spark最基础数据抽象,代表不可变、可分区、支持并行计算的分布式集合。

  • Resilient弹性:数据可存内存/磁盘,分区丢失可依赖血缘自动重算;
  • Distributed分布式:数据拆分多分区,跨多节点并行运算;
  • Dataset数据集:承载批量结构化/非结构化数据。

三大核心特性:不可变、分区存储、并行计算
#mermaid-svg-BcZuMog3JOG8YIbp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BcZuMog3JOG8YIbp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BcZuMog3JOG8YIbp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BcZuMog3JOG8YIbp .error-icon{fill:#552222;}#mermaid-svg-BcZuMog3JOG8YIbp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BcZuMog3JOG8YIbp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BcZuMog3JOG8YIbp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BcZuMog3JOG8YIbp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BcZuMog3JOG8YIbp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BcZuMog3JOG8YIbp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BcZuMog3JOG8YIbp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BcZuMog3JOG8YIbp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BcZuMog3JOG8YIbp .marker.cross{stroke:#333333;}#mermaid-svg-BcZuMog3JOG8YIbp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BcZuMog3JOG8YIbp p{margin:0;}#mermaid-svg-BcZuMog3JOG8YIbp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BcZuMog3JOG8YIbp .cluster-label text{fill:#333;}#mermaid-svg-BcZuMog3JOG8YIbp .cluster-label span{color:#333;}#mermaid-svg-BcZuMog3JOG8YIbp .cluster-label span p{background-color:transparent;}#mermaid-svg-BcZuMog3JOG8YIbp .label text,#mermaid-svg-BcZuMog3JOG8YIbp span{fill:#333;color:#333;}#mermaid-svg-BcZuMog3JOG8YIbp .node rect,#mermaid-svg-BcZuMog3JOG8YIbp .node circle,#mermaid-svg-BcZuMog3JOG8YIbp .node ellipse,#mermaid-svg-BcZuMog3JOG8YIbp .node polygon,#mermaid-svg-BcZuMog3JOG8YIbp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BcZuMog3JOG8YIbp .rough-node .label text,#mermaid-svg-BcZuMog3JOG8YIbp .node .label text,#mermaid-svg-BcZuMog3JOG8YIbp .image-shape .label,#mermaid-svg-BcZuMog3JOG8YIbp .icon-shape .label{text-anchor:middle;}#mermaid-svg-BcZuMog3JOG8YIbp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BcZuMog3JOG8YIbp .rough-node .label,#mermaid-svg-BcZuMog3JOG8YIbp .node .label,#mermaid-svg-BcZuMog3JOG8YIbp .image-shape .label,#mermaid-svg-BcZuMog3JOG8YIbp .icon-shape .label{text-align:center;}#mermaid-svg-BcZuMog3JOG8YIbp .node.clickable{cursor:pointer;}#mermaid-svg-BcZuMog3JOG8YIbp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BcZuMog3JOG8YIbp .arrowheadPath{fill:#333333;}#mermaid-svg-BcZuMog3JOG8YIbp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BcZuMog3JOG8YIbp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BcZuMog3JOG8YIbp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BcZuMog3JOG8YIbp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BcZuMog3JOG8YIbp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BcZuMog3JOG8YIbp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BcZuMog3JOG8YIbp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BcZuMog3JOG8YIbp .cluster text{fill:#333;}#mermaid-svg-BcZuMog3JOG8YIbp .cluster span{color:#333;}#mermaid-svg-BcZuMog3JOG8YIbp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BcZuMog3JOG8YIbp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BcZuMog3JOG8YIbp rect.text{fill:none;stroke-width:0;}#mermaid-svg-BcZuMog3JOG8YIbp .icon-shape,#mermaid-svg-BcZuMog3JOG8YIbp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BcZuMog3JOG8YIbp .icon-shape p,#mermaid-svg-BcZuMog3JOG8YIbp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BcZuMog3JOG8YIbp .icon-shape .label rect,#mermaid-svg-BcZuMog3JOG8YIbp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BcZuMog3JOG8YIbp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BcZuMog3JOG8YIbp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BcZuMog3JOG8YIbp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RDD弹性分布式数据集
不可变Immutable
分区Partition 数据分片
并行计算 1分区对应1个Task

2.2 RDD创建两种方式

方式1:并行化本地集合(本地数据转分布式RDD)

python 复制代码
from pyspark import SparkConf, SparkContext
if __name__ == '__main__':
    conf = SparkConf().setAppName("createRDD").setMaster("local[*]")
    sc = SparkContext(conf=conf)
    # 本地列表转为RDD,numslices指定分区数量
    data = [1,2,3,4,5,6,7,8,9]
    rdd = sc.parallelize(data, numSlices=3)
    print(rdd.collect())

方式2:读取外部文件(本地/HDFS文件)

python 复制代码
from pyspark import SparkConf, SparkContext
if __name__ == '__main__':
    conf = SparkConf().setAppName("fileRDD").setMaster("local[*]")
    sc = SparkContext(conf=conf)
    # 读取本地文件
    rdd_local = sc.textFile("../data/words.txt")
    # 读取HDFS分布式文件
    rdd_hdfs = sc.textFile("hdfs://node1:8020/input/words.txt")
    print("RDD分区数:", rdd_hdfs.getNumPartitions())

2.3 RDD算子分类:Transformation(转换)、Action(行动)

核心规则

  1. Transformation转换算子 :返回全新RDD,懒加载机制,仅记录数据依赖关系,不执行真实计算;
  2. Action行动算子:返回非RDD类型结果,触发Job提交,执行完整计算链路。

#mermaid-svg-RqBbuHTqyLi0UcMG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RqBbuHTqyLi0UcMG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RqBbuHTqyLi0UcMG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RqBbuHTqyLi0UcMG .error-icon{fill:#552222;}#mermaid-svg-RqBbuHTqyLi0UcMG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RqBbuHTqyLi0UcMG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RqBbuHTqyLi0UcMG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RqBbuHTqyLi0UcMG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RqBbuHTqyLi0UcMG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RqBbuHTqyLi0UcMG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RqBbuHTqyLi0UcMG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RqBbuHTqyLi0UcMG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RqBbuHTqyLi0UcMG .marker.cross{stroke:#333333;}#mermaid-svg-RqBbuHTqyLi0UcMG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RqBbuHTqyLi0UcMG p{margin:0;}#mermaid-svg-RqBbuHTqyLi0UcMG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RqBbuHTqyLi0UcMG .cluster-label text{fill:#333;}#mermaid-svg-RqBbuHTqyLi0UcMG .cluster-label span{color:#333;}#mermaid-svg-RqBbuHTqyLi0UcMG .cluster-label span p{background-color:transparent;}#mermaid-svg-RqBbuHTqyLi0UcMG .label text,#mermaid-svg-RqBbuHTqyLi0UcMG span{fill:#333;color:#333;}#mermaid-svg-RqBbuHTqyLi0UcMG .node rect,#mermaid-svg-RqBbuHTqyLi0UcMG .node circle,#mermaid-svg-RqBbuHTqyLi0UcMG .node ellipse,#mermaid-svg-RqBbuHTqyLi0UcMG .node polygon,#mermaid-svg-RqBbuHTqyLi0UcMG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RqBbuHTqyLi0UcMG .rough-node .label text,#mermaid-svg-RqBbuHTqyLi0UcMG .node .label text,#mermaid-svg-RqBbuHTqyLi0UcMG .image-shape .label,#mermaid-svg-RqBbuHTqyLi0UcMG .icon-shape .label{text-anchor:middle;}#mermaid-svg-RqBbuHTqyLi0UcMG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RqBbuHTqyLi0UcMG .rough-node .label,#mermaid-svg-RqBbuHTqyLi0UcMG .node .label,#mermaid-svg-RqBbuHTqyLi0UcMG .image-shape .label,#mermaid-svg-RqBbuHTqyLi0UcMG .icon-shape .label{text-align:center;}#mermaid-svg-RqBbuHTqyLi0UcMG .node.clickable{cursor:pointer;}#mermaid-svg-RqBbuHTqyLi0UcMG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RqBbuHTqyLi0UcMG .arrowheadPath{fill:#333333;}#mermaid-svg-RqBbuHTqyLi0UcMG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RqBbuHTqyLi0UcMG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RqBbuHTqyLi0UcMG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RqBbuHTqyLi0UcMG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RqBbuHTqyLi0UcMG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RqBbuHTqyLi0UcMG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RqBbuHTqyLi0UcMG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RqBbuHTqyLi0UcMG .cluster text{fill:#333;}#mermaid-svg-RqBbuHTqyLi0UcMG .cluster span{color:#333;}#mermaid-svg-RqBbuHTqyLi0UcMG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RqBbuHTqyLi0UcMG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RqBbuHTqyLi0UcMG rect.text{fill:none;stroke-width:0;}#mermaid-svg-RqBbuHTqyLi0UcMG .icon-shape,#mermaid-svg-RqBbuHTqyLi0UcMG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RqBbuHTqyLi0UcMG .icon-shape p,#mermaid-svg-RqBbuHTqyLi0UcMG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RqBbuHTqyLi0UcMG .icon-shape .label rect,#mermaid-svg-RqBbuHTqyLi0UcMG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RqBbuHTqyLi0UcMG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RqBbuHTqyLi0UcMG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RqBbuHTqyLi0UcMG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 原始RDD
map转换算子
flatMap转换算子
reduceByKey转换算子
collect Action算子 触发Job

2.4 常用Transformation转换算子代码示例

1)map:逐条处理单个元素
python 复制代码
rdd = sc.parallelize([1,2,3,4,5])
map_rdd = rdd.map(lambda x: x * 3)
print(map_rdd.collect()) # [3,6,9,12,15]
2)flatMap:映射 + 扁平化拆解
python 复制代码
rdd = sc.parallelize(["hello spark", "hello hadoop"])
flat_rdd = rdd.flatMap(lambda line: line.split(" "))
print(flat_rdd.collect()) # ['hello','spark','hello','hadoop']
3)reduceByKey:KV键值对按Key聚合
python 复制代码
rdd = sc.parallelize([("a",1),("a",1),("b",1),("b",1),("b",1)])
res = rdd.reduceByKey(lambda a,b: a+b)
print(res.collect()) # [('a', 2), ('b', 3)]
4)filter、distinct、join、groupByKey、sortByKey等算子原理一致,可自行测试

2.5 常用Action行动算子代码示例

python 复制代码
rdd = sc.parallelize([1,2,3,4,5])
print(rdd.count()) # count:统计总元素 5
print(rdd.first()) # first:取首个元素 1
print(rdd.reduce(lambda a,b: a+b)) # reduce全局求和 15
rdd.saveAsTextFile("./output") # 结果写入文件

2.6 分区操作算子

  1. mapPartitions:按分区批量处理,每个分区仅执行一次逻辑,适合数据库连接等重量级初始化;
  2. repartition:强制Shuffle,增加/减少分区;
  3. coalesce:默认无Shuffle,多用于减少分区;
  4. partitionBy:仅KV型RDD可用,自定义分区分发规则。

2.7 RDD持久化(缓存)

为什么需要缓存?

RDD惰性求值,多次复用同一RDD时,会重复完整重算上游所有依赖,迭代计算性能损耗巨大。缓存将计算结果持久化内存/磁盘,复用无需重复计算。

缓存API

python 复制代码
rdd.cache() # 等价于 StorageLevel.MEMORY_ONLY
# 自定义存储级别(内存放不下自动落盘,推荐生产使用)
rdd.persist(StorageLevel.MEMORY_AND_DISK)
# 手动释放缓存资源
rdd.unpersist()

主流存储级别:MEMORY_ONLY、MEMORY_AND_DISK、DISK_ONLY、_2副本、堆外内存OFF_HEAP。

2.8 Spark共享变量(修复累加器global冗余问题)

1)广播变量 Broadcast

普通变量会拷贝到每一个Task,内存大量冗余;广播变量每个Executor仅保存一份副本,节点内所有Task共享,只读不可修改。

python 复制代码
# 小型映射字典广播
dict_map = {101:"广东",102:"北京",103:"上海"}
bc = sc.broadcast(dict_map)
user_rdd = sc.parallelize([101,102,103])
res = user_rdd.map(lambda x: (x, bc.value.get(x)))

2)累加器 Accumulator(删除多余global关键字)

普通本地变量无法跨Executor分布式累加,累加器专为分布式计数设计,仅Driver端可读取最终值。

python 复制代码
acc = sc.accumulator(0)
rdd = sc.parallelize([1,15,8,22])
# 移除多余global,直接调用acc.add()
def count_big(x):
    if x > 10:
        acc.add(1)
    return x
rdd.map(count_big).collect()
print("大于10的数字数量:", acc.value)

说明:累加器通过闭包序列化传递对象引用,无需global声明,官方标准示例均无此关键字,避免误导初学者。

2.9 RDD依赖:窄依赖 & 宽依赖(Shuffle)

#mermaid-svg-qo8OQzX635e6HLEH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qo8OQzX635e6HLEH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qo8OQzX635e6HLEH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qo8OQzX635e6HLEH .error-icon{fill:#552222;}#mermaid-svg-qo8OQzX635e6HLEH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qo8OQzX635e6HLEH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qo8OQzX635e6HLEH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qo8OQzX635e6HLEH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qo8OQzX635e6HLEH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qo8OQzX635e6HLEH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qo8OQzX635e6HLEH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qo8OQzX635e6HLEH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qo8OQzX635e6HLEH .marker.cross{stroke:#333333;}#mermaid-svg-qo8OQzX635e6HLEH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qo8OQzX635e6HLEH p{margin:0;}#mermaid-svg-qo8OQzX635e6HLEH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qo8OQzX635e6HLEH .cluster-label text{fill:#333;}#mermaid-svg-qo8OQzX635e6HLEH .cluster-label span{color:#333;}#mermaid-svg-qo8OQzX635e6HLEH .cluster-label span p{background-color:transparent;}#mermaid-svg-qo8OQzX635e6HLEH .label text,#mermaid-svg-qo8OQzX635e6HLEH span{fill:#333;color:#333;}#mermaid-svg-qo8OQzX635e6HLEH .node rect,#mermaid-svg-qo8OQzX635e6HLEH .node circle,#mermaid-svg-qo8OQzX635e6HLEH .node ellipse,#mermaid-svg-qo8OQzX635e6HLEH .node polygon,#mermaid-svg-qo8OQzX635e6HLEH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qo8OQzX635e6HLEH .rough-node .label text,#mermaid-svg-qo8OQzX635e6HLEH .node .label text,#mermaid-svg-qo8OQzX635e6HLEH .image-shape .label,#mermaid-svg-qo8OQzX635e6HLEH .icon-shape .label{text-anchor:middle;}#mermaid-svg-qo8OQzX635e6HLEH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qo8OQzX635e6HLEH .rough-node .label,#mermaid-svg-qo8OQzX635e6HLEH .node .label,#mermaid-svg-qo8OQzX635e6HLEH .image-shape .label,#mermaid-svg-qo8OQzX635e6HLEH .icon-shape .label{text-align:center;}#mermaid-svg-qo8OQzX635e6HLEH .node.clickable{cursor:pointer;}#mermaid-svg-qo8OQzX635e6HLEH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qo8OQzX635e6HLEH .arrowheadPath{fill:#333333;}#mermaid-svg-qo8OQzX635e6HLEH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qo8OQzX635e6HLEH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qo8OQzX635e6HLEH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qo8OQzX635e6HLEH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qo8OQzX635e6HLEH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qo8OQzX635e6HLEH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qo8OQzX635e6HLEH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qo8OQzX635e6HLEH .cluster text{fill:#333;}#mermaid-svg-qo8OQzX635e6HLEH .cluster span{color:#333;}#mermaid-svg-qo8OQzX635e6HLEH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qo8OQzX635e6HLEH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qo8OQzX635e6HLEH rect.text{fill:none;stroke-width:0;}#mermaid-svg-qo8OQzX635e6HLEH .icon-shape,#mermaid-svg-qo8OQzX635e6HLEH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qo8OQzX635e6HLEH .icon-shape p,#mermaid-svg-qo8OQzX635e6HLEH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qo8OQzX635e6HLEH .icon-shape .label rect,#mermaid-svg-qo8OQzX635e6HLEH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qo8OQzX635e6HLEH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qo8OQzX635e6HLEH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qo8OQzX635e6HLEH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 宽依赖 WideDependency 触发Shuffle
父分区1
子分区1
子分区2
父分区2
窄依赖 NarrowDependency
父分区1
子分区1
父分区2
子分区2

  1. 窄依赖:一个父分区数据仅供给单个子分区,无跨节点Shuffle,如map、filter、union;
  2. 宽依赖:单个父分区数据分发至多个子分区,触发跨节点Shuffle,如reduceByKey、groupByKey;
  3. Stage划分规则:DAG从后往前遍历,遇到宽依赖切割Stage,同一个Stage内所有Task并行执行。

第三章 Spark SQL 结构化数据处理

3.1 Spark SQL概述

Spark SQL是Spark处理结构化数据的专用模块,支持SQL、DSL两套开发语法,内置Catalyst自动优化器,兼容Hive元数据,是企业离线数仓主流技术。

3.2 DataFrame与RDD区别

维度 RDD DataFrame
数据结构 无固定Schema,任意混合数据 标准二维表,自带Schema(列名、数据类型、是否为空)
执行优化 无内置优化,完全依赖开发人员 Catalyst自动优化(谓词下推、列裁剪)
开发语法 底层算子,代码冗长 简洁SQL/DSL API,易上手
底层抽象 分布式数据集合 带元数据的分布式数据表

3.3 统一入口:SparkSession(Spark2.0+标准入口)

python 复制代码
from pyspark.sql import SparkSession
spark = SparkSession.builder \
    .appName("SparkSQLDemo") \
    .master("local[*]") \
    .config("spark.sql.shuffle.partitions", "4") \
    .getOrCreate()
# 获取底层SparkContext对象
sc = spark.sparkContext

3.4 DataFrame四种创建方式

  1. 已有RDD转换为DataFrame;
  2. Pandas单机DataFrame转为分布式Spark DataFrame;
  3. 读取外部文件:csv/json/parquet/text;
  4. JDBC读取MySQL、Oracle等数据库;

读取CSV文件示例

python 复制代码
df = spark.read.csv(
    "./stu_score.txt",
    sep=",",
    header=False,
    inferSchema=True
).toDF("id", "subject", "score")
df.printSchema()
df.show()

3.5 两种开发风格:SQL & DSL

DSL风格(链式API调用)

python 复制代码
# 过滤语文成绩数据
df.where("subject = '语文'").limit(5).show()
# 按学科分组求平均分
df.groupBy("subject").avg("score").show()

SQL风格(标准SQL语句)

python 复制代码
# 注册临时视图(仅当前SparkSession生效)
df.createOrReplaceTempView("score")
# 执行SQL查询
spark.sql("SELECT * FROM score WHERE subject='语文' LIMIT 5").show()

3.6 数据清洗高频API

python 复制代码
df.dropDuplicates(["id"]) # 指定字段去重
df.dropna(how="any") # 任意字段为空则删除整行
df.fillna(0, subset=["score"]) # 指定列空值填充0

3.7 数据写出四种模式

写出mode可选:overwrite覆盖、append追加、ignore忽略、errorifexists(默认报错)

python 复制代码
# 写出parquet列式文件(Spark默认存储格式)
df.write.mode("overwrite").format("parquet").save("./output/parquet")
# JDBC写入MySQL数据表
df.write.format("jdbc") \
.option("url", "jdbc:mysql://node1:3306/test") \
.option("dbtable", "score") \
.option("user", "root") \
.option("password", "123456") \
.save()

3.8 Catalyst优化器完整执行流程

#mermaid-svg-kG5oHSHAfrj56ZH9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kG5oHSHAfrj56ZH9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kG5oHSHAfrj56ZH9 .error-icon{fill:#552222;}#mermaid-svg-kG5oHSHAfrj56ZH9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kG5oHSHAfrj56ZH9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kG5oHSHAfrj56ZH9 .marker.cross{stroke:#333333;}#mermaid-svg-kG5oHSHAfrj56ZH9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kG5oHSHAfrj56ZH9 p{margin:0;}#mermaid-svg-kG5oHSHAfrj56ZH9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kG5oHSHAfrj56ZH9 .cluster-label text{fill:#333;}#mermaid-svg-kG5oHSHAfrj56ZH9 .cluster-label span{color:#333;}#mermaid-svg-kG5oHSHAfrj56ZH9 .cluster-label span p{background-color:transparent;}#mermaid-svg-kG5oHSHAfrj56ZH9 .label text,#mermaid-svg-kG5oHSHAfrj56ZH9 span{fill:#333;color:#333;}#mermaid-svg-kG5oHSHAfrj56ZH9 .node rect,#mermaid-svg-kG5oHSHAfrj56ZH9 .node circle,#mermaid-svg-kG5oHSHAfrj56ZH9 .node ellipse,#mermaid-svg-kG5oHSHAfrj56ZH9 .node polygon,#mermaid-svg-kG5oHSHAfrj56ZH9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kG5oHSHAfrj56ZH9 .rough-node .label text,#mermaid-svg-kG5oHSHAfrj56ZH9 .node .label text,#mermaid-svg-kG5oHSHAfrj56ZH9 .image-shape .label,#mermaid-svg-kG5oHSHAfrj56ZH9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-kG5oHSHAfrj56ZH9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kG5oHSHAfrj56ZH9 .rough-node .label,#mermaid-svg-kG5oHSHAfrj56ZH9 .node .label,#mermaid-svg-kG5oHSHAfrj56ZH9 .image-shape .label,#mermaid-svg-kG5oHSHAfrj56ZH9 .icon-shape .label{text-align:center;}#mermaid-svg-kG5oHSHAfrj56ZH9 .node.clickable{cursor:pointer;}#mermaid-svg-kG5oHSHAfrj56ZH9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kG5oHSHAfrj56ZH9 .arrowheadPath{fill:#333333;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kG5oHSHAfrj56ZH9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kG5oHSHAfrj56ZH9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kG5oHSHAfrj56ZH9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kG5oHSHAfrj56ZH9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kG5oHSHAfrj56ZH9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kG5oHSHAfrj56ZH9 .cluster text{fill:#333;}#mermaid-svg-kG5oHSHAfrj56ZH9 .cluster span{color:#333;}#mermaid-svg-kG5oHSHAfrj56ZH9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kG5oHSHAfrj56ZH9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kG5oHSHAfrj56ZH9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-kG5oHSHAfrj56ZH9 .icon-shape,#mermaid-svg-kG5oHSHAfrj56ZH9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kG5oHSHAfrj56ZH9 .icon-shape p,#mermaid-svg-kG5oHSHAfrj56ZH9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kG5oHSHAfrj56ZH9 .icon-shape .label rect,#mermaid-svg-kG5oHSHAfrj56ZH9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kG5oHSHAfrj56ZH9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kG5oHSHAfrj56ZH9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kG5oHSHAfrj56ZH9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入SQL语句
抽象语法树
绑定表元数据、字段类型
未优化原始逻辑计划
优化器:谓词下推、列裁剪
最优逻辑执行计划
生成物理执行计划
动态代码生成,转为RDD任务

两大核心优化手段:

  1. 谓词下推:Filter过滤逻辑提前执行,减少上下游传输数据量;
  2. 列裁剪:仅读取SQL中用到的字段,避免全表扫描浪费IO。

第四章 Spark Streaming & Structured Streaming 实时流计算

4.1 流数据特点

无限持续生成、实时到达,典型业务场景:电商实时大屏、物联网设备监控、日志实时分析。

4.2 两种主流流式计算模型

  1. 原生单条流处理:Flink/Storm,逐条处理数据,毫秒级低延迟;
  2. 微批处理:Spark Streaming/Structured Streaming,按固定时间切片生成小批量数据,秒级延迟。

#mermaid-svg-hVZrCkDTh9hXjqaB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hVZrCkDTh9hXjqaB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hVZrCkDTh9hXjqaB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hVZrCkDTh9hXjqaB .error-icon{fill:#552222;}#mermaid-svg-hVZrCkDTh9hXjqaB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hVZrCkDTh9hXjqaB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hVZrCkDTh9hXjqaB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hVZrCkDTh9hXjqaB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hVZrCkDTh9hXjqaB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hVZrCkDTh9hXjqaB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hVZrCkDTh9hXjqaB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hVZrCkDTh9hXjqaB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hVZrCkDTh9hXjqaB .marker.cross{stroke:#333333;}#mermaid-svg-hVZrCkDTh9hXjqaB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hVZrCkDTh9hXjqaB p{margin:0;}#mermaid-svg-hVZrCkDTh9hXjqaB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hVZrCkDTh9hXjqaB .cluster-label text{fill:#333;}#mermaid-svg-hVZrCkDTh9hXjqaB .cluster-label span{color:#333;}#mermaid-svg-hVZrCkDTh9hXjqaB .cluster-label span p{background-color:transparent;}#mermaid-svg-hVZrCkDTh9hXjqaB .label text,#mermaid-svg-hVZrCkDTh9hXjqaB span{fill:#333;color:#333;}#mermaid-svg-hVZrCkDTh9hXjqaB .node rect,#mermaid-svg-hVZrCkDTh9hXjqaB .node circle,#mermaid-svg-hVZrCkDTh9hXjqaB .node ellipse,#mermaid-svg-hVZrCkDTh9hXjqaB .node polygon,#mermaid-svg-hVZrCkDTh9hXjqaB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hVZrCkDTh9hXjqaB .rough-node .label text,#mermaid-svg-hVZrCkDTh9hXjqaB .node .label text,#mermaid-svg-hVZrCkDTh9hXjqaB .image-shape .label,#mermaid-svg-hVZrCkDTh9hXjqaB .icon-shape .label{text-anchor:middle;}#mermaid-svg-hVZrCkDTh9hXjqaB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hVZrCkDTh9hXjqaB .rough-node .label,#mermaid-svg-hVZrCkDTh9hXjqaB .node .label,#mermaid-svg-hVZrCkDTh9hXjqaB .image-shape .label,#mermaid-svg-hVZrCkDTh9hXjqaB .icon-shape .label{text-align:center;}#mermaid-svg-hVZrCkDTh9hXjqaB .node.clickable{cursor:pointer;}#mermaid-svg-hVZrCkDTh9hXjqaB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hVZrCkDTh9hXjqaB .arrowheadPath{fill:#333333;}#mermaid-svg-hVZrCkDTh9hXjqaB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hVZrCkDTh9hXjqaB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hVZrCkDTh9hXjqaB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hVZrCkDTh9hXjqaB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hVZrCkDTh9hXjqaB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hVZrCkDTh9hXjqaB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hVZrCkDTh9hXjqaB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hVZrCkDTh9hXjqaB .cluster text{fill:#333;}#mermaid-svg-hVZrCkDTh9hXjqaB .cluster span{color:#333;}#mermaid-svg-hVZrCkDTh9hXjqaB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hVZrCkDTh9hXjqaB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hVZrCkDTh9hXjqaB rect.text{fill:none;stroke-width:0;}#mermaid-svg-hVZrCkDTh9hXjqaB .icon-shape,#mermaid-svg-hVZrCkDTh9hXjqaB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hVZrCkDTh9hXjqaB .icon-shape p,#mermaid-svg-hVZrCkDTh9hXjqaB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hVZrCkDTh9hXjqaB .icon-shape .label rect,#mermaid-svg-hVZrCkDTh9hXjqaB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hVZrCkDTh9hXjqaB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hVZrCkDTh9hXjqaB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hVZrCkDTh9hXjqaB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 无限数据流
按时间切片生成微批
单批次对应1个RDD
连续RDD序列组成DStream

4.3 Spark Streaming核心抽象:DStream

DStream = 时间有序的连续RDD集合,每一个批间隔生成独立RDD;对DStream的所有操作,底层等价操作对应批次RDD。

支持主流数据源

Socket套接字、HDFS文件流、Kafka、Flume、RDD队列流。

DStream算子三大分类

  1. 无状态算子:仅处理当前批次,不保存历史数据 map/flatMap/filter/join;
  2. 有状态算子 :跨批次复用历史数据
    • window窗口操作:窗口长度、滑动间隔双参数;
    • updateStateByKey:全局累计统计;
  3. 输出算子:print、saveAsTextFiles、foreachRDD(通用自定义输出)。

窗口计算示例

python 复制代码
# 窗口时长3秒,滑动间隔1秒,实时统计单词数量
words = lines.flatMap(lambda x: x.split(" "))
window_words = words.window(windowDuration=3, slideDuration=1)
window_words.count().pprint()

4.4 Structured Streaming 流批一体(修复complete模式报错问题)

基于Spark SQL DataFrame构建,将无限数据流视为持续追加的动态表,同一套API兼容批/流计算,自动管理计算状态,支持Exactly-Once精确一次语义。

修正后Socket词频代码(解决complete异常)

python 复制代码
from pyspark.sql import SparkSession
from pyspark.sql.functions import split, explode

spark = SparkSession.builder \
    .master("local[2]") \
    .appName("StructuredStreamingWordCountSocket") \
    .getOrCreate()

# 读取Socket实时流数据源
df = spark.readStream.format("socket")\
.option("host", "localhost")\
.option("port", 9999).load()

# 拆分单词并分组计数
word_df = df.select(explode(split("value", " ")).alias("word")) \
    .groupBy("word").count()

# 修改outputMode为update,适配Socket无界聚合场景
query = word_df.writeStream \
    .outputMode("update") \
    .format("console") \
    .trigger(processingTime="5 seconds") \
    .start()

query.awaitTermination()

补充说明:

  1. update模式:仅输出当前批次发生变化的聚合结果,适配Socket无界无水印数据源;
  2. complete完整模式:输出全量历史聚合数据,仅支持有界文件源、带水印窗口聚合,Socket直接使用会抛出AnalysisException;
  3. append追加模式:仅输出新增原始数据,聚合类查询无法使用。

第五章 Spark MLlib & GraphX

5.1 MLlib分布式机器学习库

基于Spark Core构建分布式机器学习工具包,解决单机sklearn无法处理TB级海量样本的痛点:

  • 支持任务:分类、回归、聚类、协同过滤、特征工程、Pipeline训练流水线;
  • 优势:分布式并行训练,支持海量数据离线建模。

5.2 GraphX图计算组件

Spark提供两套图计算API,分别适配不同开发场景:

  1. GraphX:底层基于RDD实现,内置PageRank、连通分量、三角形计数、最短路径经典图算法;
  2. GraphFrames:基于DataFrame封装,无缝对接Spark SQL,语法更简洁易读。

文末总结

  1. Spark依靠内存计算+DAG调度解决MapReduce磁盘IO瓶颈,五大生态组件覆盖批、SQL、实时、机器学习、图计算全大数据场景;
  2. RDD是Spark底层核心,吃透懒加载、宽窄依赖、缓存、共享变量是调优基础;
  3. Spark SQL基于DataFrame+Catalyst优化器,企业离线数仓主流开发框架;
  4. Spark Streaming为传统微批实时方案,Structured Streaming新一代流批一体框架;
  5. MLlib、GraphX分别解决分布式机器学习、大规模图结构数据分析场景。

互动&收藏

本文配套Mermaid原理图、可直接运行PySpark代码,零基础友好,适合收藏反复复习。

后续更新Spark性能调优、YARN集群部署、Kafka实时数仓实战项目,有疑问欢迎评论区留言交流!