前哨站/第9章 Spark实战
第9章 Spark实战

第9章 Spark实战

内存计算框架:RDD 是什么、算子怎么选、一个 WordCount 怎么用 Spark 写得比 MapReduce 短十倍。

内存计算RDD算子

本章学习目标

  • 能说出 Spark 的定位、主要组件与相对 MapReduce 的优势
  • 能安装配置 Spark(含 Scala 环境)
  • 能理解 RDD 的转化算子、行动算子与依赖关系
  • 能用 Java API 完成一个 Spark 统计程序

本章导览

核心内容

9.1

Spark概述

Spark 是基于内存的分布式计算框架,把中间结果放在内存而不是落盘,因此迭代计算与交互式查询快得多。

9.1.2

Spark的主要组件

组件作用
Spark CoreRDD、任务调度、内存管理,其他组件的基础
Spark SQL结构化数据处理,可用 SQL 查询
Spark Streaming微批流处理
Structured Streaming基于 DataFrame 的流处理(新)
MLlib机器学习算法库
GraphX图计算
Spark 通常运行在 YARN 上,数据仍存放在 HDFS/HBase 中——它替换的是 MapReduce 计算层,不是存储层。
9.2

安装Spark

SHELL
# 1) 安装 Scala(Spark 用 Scala 编写)
tar -zxvf scala-2.12.15.tgz -C /export/servers/
vi ~/.bashrc
export SCALA_HOME=/export/servers/scala-2.12.15
export PATH=$SCALA_HOME/bin:$PATH

# 2) 解压 Spark 并配置
tar -zxvf spark-3.3.1-bin-hadoop3.tgz -C /export/servers/
cd $SPARK_HOME/conf
cp spark-env.sh.template spark-env.sh
vi spark-env.sh
export JAVA_HOME=/export/servers/jdk1.8.0_141
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
export SPARK_MASTER_HOST=hadoop1

# 3) 启动
start-all.sh          # 在 $SPARK_HOME/sbin 下(注意与 Hadoop 的 start-all.sh 重名)
# Web:http://hadoop1:8080

# 4) 提交流程
spark-submit --master yarn --class com.demo.Wc \
  --jars wc.jar wc.jar hdfs:///input hdfs:///output
9.3

Spark RDD

RDD(Resilient Distributed Dataset)是 Spark 的核心抽象:不可变、可分区、可并行计算,并靠"血缘"实现容错。

9.3.1

转化算子

算子作用是否触发计算
map / flatMap逐条转换 / 展开成多条否(惰性)
filter过滤否
groupByKey按 key 分组否(Shuffle)
reduceByKey按 key 聚合(先本地聚合)否(Shuffle)
join / union / distinct关联、合并、去重否
9.3.2

行动算子

算子作用
count / collect计数 / 收集到驱动端
first / take(n)取第一个 / 前 n 个
reduce整体聚合
foreach逐条处理(常用于写入外部系统)
saveAsTextFile保存为文件
Spark 是惰性执行:转化算子只记录血缘,遇到行动算子才真正提交任务。
9.3.3

RDD依赖关系

  • 窄依赖:父 RDD 的一个分区只对应子 RDD 的一个分区(map/filter),无需 Shuffle,快
  • 宽依赖:子 RDD 的分区依赖父 RDD 的多个分区(groupByKey/reduceByKey),需要 Shuffle
  • DAG 按宽依赖切分 Stage,Stage 内流水线执行
9.4

Spark Java API操作

JAVA
SparkConf conf = new SparkConf().setAppName("wc").setMaster("local[*]");
JavaSparkContext sc = new JavaSparkContext(conf);

JavaRDD<String> lines = sc.textFile("hdfs://hadoop1:9000/wc/input/w.txt");
JavaRDD<String> words = lines.flatMap(l -> Arrays.asList(l.split("\s+")).iterator());
JavaPairRDD<String, Integer> pairs = words.mapToPair(w -> new Tuple2<>(w, 1));
JavaPairRDD<String, Integer> counts = pairs.reduceByKey((a, b) -> a + b);

counts.saveAsTextFile("hdfs://hadoop1:9000/wc/out-spark");
sc.close();
9.5

案例解析——单词统计编程

同一个 WordCount,MapReduce 要写 Mapper、Reducer、Driver 三个类;Spark 用 6 行算子就写完,这就是"表达力"的差别。

环节MapReduceSpark
代码量3 个类、约 80 行6 行算子
中间结果落磁盘留内存
执行速度基准 1×通常 10× 以上

本章小结

本章讲清 Spark 的定位(内存计算)与组件构成,完成 Scala/Spark 的安装与提交方式,重点讲 RDD 的转化算子、行动算子与窄宽依赖,最后用 Java API 写出 Spark 版 WordCount 并与 MapReduce 版对比。

思考与练习 先自己做,再点开答案

01

转化算子与行动算子的区别?

查看参考答案

转化算子(map/filter/reduceByKey)只构建执行计划、不立即计算,返回新的 RDD;行动算子(count/collect/saveAsTextFile)触发真正的任务提交与计算。

02

窄依赖与宽依赖的区别,为什么宽依赖更贵?

查看参考答案

窄依赖一个子分区只依赖一个父分区,可流水线执行;宽依赖需要 Shuffle,父分区数据要跨节点重分布,涉及磁盘/网络 IO,是性能瓶颈所在。

03

reduceByKey 与 groupByKey 该怎么选?

查看参考答案

优先 reduceByKey:它会在 Map 端先做局部聚合(相当于 Combiner)再 Shuffle,数据量小;groupByKey 把同 key 的所有 value 拉到一个节点,易 OOM。