Spark SQL 比 Hadoop Hive 快,是有一定条件的,而且不是 Spark SQL 的引擎比 Hive 的引擎快,相反,Hive 的 HQL 引擎还比 Spark SQL 的引擎更快。其实,关键还是在于 Spark 本身快。
不过凡事都没有绝对,考虑一种极端查询:
select month_id, sum(sales) from T group by month_id;
这个查询只有一次 shuffle 操作,此时,也许 Hive HQL 的运行时间也许比 Spark 还快,反正 shuffle 完了都会落一次盘,或者都不落盘。
结论 Spark 快不是绝对的,但是绝大多数,Spark 都比 Hadoop 计算要快。这主要得益于其对 mapreduce 操作的优化以及对 JVM 使用的优化。
RDD RDD 是 Spark 的灵魂,也称为弹性分布式数据集。一个 RDD 代表一个可以被分区的只读数据集。RDD 内部可以有许多分区(partitions),每个分区又拥有大量的记录(records)。
DAG Spark 中使用 DAG 对 RDD 的关系进行建模,描述了 RDD 的依赖关系,这种关系也被称之为 lineage(血缘),RDD 的依赖关系使用 Dependency 维护。
Stage 在 DAG 中又进行 Stage 的划分,划分的依据是依赖是否是 shuffle 的,每个 Stage 又可以划分成若干 Task。接下来的事情就是 Driver 发送 Task 到 Executor,Executor 线程池去执行这些 task,完成之后将结果返回给 Driver。
Job Spark 的 Job 来源于用户执行 action 操作(这是 Spark 中实际意义的 Job),就是从 RDD 中获取结果的操作,而不是将一个 RDD 转换成另一个 RDD 的 transformation 操作。
Task 一个 Stage 内,最终的 RDD 有多少个 partition,就会产生多少个 task。
RDD 作为数据结构,本质上是一个只读的分区记录集合。一个 RDD 可以包含多个分区,每个分区就是一个数据集片段。
首先,窄依赖可以支持在同一个节点上,以 pipeline 形式执行多条命令(也叫同一个 Stage 的操作),例如在执行了 map 后,紧接着执行 filter。相反,宽依赖需要所有的父分区都是可用的,可能还需要调用类似 MapReduce 之类的操作进行跨节点传递。
其次,则是从失败恢复的角度考虑。窄依赖的失败恢复更有效,因为它只需要重新计算丢失的 parent partition 即可,而且可以并行地在不同节点进行重计算(一台机器太慢就会重新调度到多个节点进行)。
new SparkContext()
,在 SparkContext 里构造 DAGScheduler 和 TaskScheduler。因为 Yarn 支持动态资源配置。Standalone 模式只支持简单的固定资源分配策略,每个任务固定数量的 core,各 Job 按顺序依次分配在资源,资源不够的时候就排队。
这种模式比较适合单用户的情况,多用户的情境下,会有可能有些用户的任务得不到资源。
Yarn 作为通用的资源调度平台,除了 Spark 提供调度服务之外,还可以为其他系统提供调度,如 Hadoop MapReduce, Hive 等。
目前来说 Spark 的 Cluster Mode,Yarn 还是主流,K8S 则迎头赶上。
Worker 是指每个工作节点,启动的一个进程,负责管理本节点,jps 可以看到 Worker 进程在运行,对应的概念是 Master 节点。 Executor 每个 Spark 程序在每个节点上启动的一个进程,专属于一个 Spark 程序,与 Spark 程序有相同的生命周期,负责 Spark 在节点上启动的 Task,管理内存和磁盘。如果一个节点上有多个 Spark 程序,那么相应就会启动多个执行器。所以说一个 Worker 节点可以有多个 Executor 进程。
Spark一共有6种运行模式:Local,Standalone,Yarn-Cluster,Yarn-Client, Mesos, Kubernetes
new SparkConf.setManager(“spark://master:7077”)
方式运行 Spark 任务时,Driver 是运行在本地 Client 端上的。Standalone 模式的部署比较繁琐,不过官方有提供部署脚本,需要把 Spark 的部署包安装到每一台节点机器上,并且部署的目录也必须相同,而且需要 Master 节点和其他节点实现 SSH 无密码登录。启动时,需要先启动 Spark 的 Master 和 Slave 节点。提交命令类似于:
./bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://Oscar-2.local:7077 \
/tmp/spark-2.2.0-bin-hadoop2.7/examples/jars/spark-examples_2.11-2.2.0.jar \
100
其中 master:7077是 Spark 的 Master 节点的主机名和端口号,当然集群是需要提前启动。
一般上来说有多少个 Partition,就有多少个 Task,Repartition 的理解其实很简单,就是把原来 RDD 的分区重新安排。这样做有什么好坏呢?
我面试中,就曾经被面试官要求过手写一段 WordCount,别看好像很简单,实际上如果常年在做 Spark 内核的开发,而不是业务开发,也许你就想不起来了。
sc.textFile("/path/to/spark/README.md")
.flatMap(_.split(" "))
.map(x => (x, 1))
.reduceByKey(_ + _)
.map(x => (x._2, x._1))
.sortByKey(false)
.map(x => (x._2, x._1))
.take(10)
# 结果
Array[(String, Int)] = Array(("",71), (the,24), (to,17), (Spark,16), (for,12), (##,9), (and,9), (a,8), (can,7), (run,7))