中间件速查手册
大数据计算 · spark

Spark

把中间结果放内存,比 MapReduce 快一个数量级

大数据计算Apache-2.0Scala / Java / Python / R学习难度:较难

Spark 把“读数据 → 变换 → 输出”描述成一张 DAG,先不执行,等遇到 action 才整体优化、切成 Stage 并行跑。中间结果留在内存而不是写回磁盘,所以迭代计算(机器学习、图计算)比 MapReduce 快 10 倍以上。

01

它解决什么问题

MapReduce 每一步都要把结果写 HDFS 再读回来,一个十步的作业要读写十次磁盘;而且只会批处理,实时场景没法用。

真实场景:典型场景:每天凌晨用 Spark SQL 跑几千个离线指标,读 Hive 表、join 十几张维表、写回数仓,两小时内跑完。

02

核心概念

每个概念一句话 + 一个类比。点击卡片看更详细的解释。

03

数据流转动画

跟着步骤看一条数据从进入系统到被处理完的完整路径,可以暂停、重播和调速。

Flow animation

一个 Spark 作业从提交到出结果的路径

Drivermain() / SparkSessionDAG Scheduler切 Stage / 分配 TaskExecutor 1task × NExecutor 2task × NHDFS / S3Parquet / ORC

← 左右滑动查看完整流程图 →

01 / 05
1. 提交作业

代码里的 map / filter / join 都是懒执行,只是往 DAG 上加节点,直到遇到 count、write 这类 action。

提示:注意 shuffle:它是 Stage 的分界线,也是绝大多数性能问题的来源。 悬停图中的节点可以看概念解释。

04

优劣势

短句说清适合什么、不适合什么,选型时先看这一栏。

适合什么
  • 内存计算 + DAG 优化,迭代任务比 MapReduce 快一个数量级
  • 一套引擎覆盖 SQL、流(Structured Streaming)、MLlib、GraphX
  • API 友好,Python / SQL 都能写,门槛比 MapReduce 低太多
  • 生态最好,和 Hive、HDFS、Kafka、Delta / Iceberg 全打通
不适合什么
  • 不是纯流处理,Structured Streaming 的延迟在秒级,做不到毫秒
  • shuffle 依然要落盘,数据倾斜会让个别 Task 拖垮整个作业
  • 内存吃得多,参数没调好容易 OOM
  • 小作业启动开销大(几十秒),不适合交互式即席查询
05

常见使用场景

每个场景都配一句「为什么用它」。

01

离线数仓 ETL

每天把 ODS 层原始数据清洗、join、聚合,写到 DWD / DWS 层。

为什么用它:Spark SQL 兼容 Hive 语法,迁移成本低,跑批稳定。

02

机器学习特征工程

用 MLlib 做特征抽取、模型训练,中间结果反复迭代。

为什么用它:迭代计算正是内存计算的强项,比 MapReduce 快十倍。

03

日志清洗与入湖

读 Kafka / HDFS 的原始日志,解析、去重、打成 Parquet 入湖。

为什么用它:批流一套代码,白天微批、晚上全量,维护成本低。

06

同类对比

和同赛道的组件并排看,差异一目了然。

SparkFlink

一句话:离线与准实时选 Spark,真实时选 Flink。两者不是替代关系,很多公司是 Spark 跑批、Flink 跑流,共用一套 Kafka 和数仓。

打开对比页
07

常见问题

上手第一个月最容易卡住的地方。

Q1Spark 一定比 MapReduce 快吗?

单次简单作业不一定,Spark 启动本身要几十秒;但迭代型(机器学习、图计算)和多次 shuffle 的作业,Spark 快 5~10 倍是常态,因为中间结果不落 HDFS。数据量很小(几 GB)时,用 Spark 反而更慢。

Q2数据倾斜怎么处理?

先看 Spark UI 里 Task 的耗时分布,某个 Task 跑几小时、其他几分钟就是倾斜。常用手段:加盐打散热点 key、把大表 broadcast 掉小表、两阶段聚合(先局部聚合再加随机前缀)、开启 AQE 的 skew join 处理。

Q3Spark 和 Flink 怎么选?

离线批处理、机器学习、已有 Hive 体系,选 Spark;要求毫秒到秒级实时、事件驱动、状态复杂(CEP、风控),选 Flink。现在两家都在做流批一体,但基因不同:Spark 是批为主,Flink 是流为主。

Q4为什么我的作业总是 OOM?

常见三个原因:collect 把大结果拉回 Driver、broadcast 了大表、shuffle 分区数太少导致单分区数据过大。先调 spark.sql.shuffle.partitions(默认 200 往往偏小),再检查是否用了 collect。