Spark+Hive中间件

发布于:2025-09-12 ⋅ 阅读:(14) ⋅ 点赞:(0)

Spark

Spark入门教程(非常详细)从零基础入门到精通,看完这一篇就够了-CSDN博客

基础

Spark是用来代替Hadoop中的MapReduce,其存储依然用的是Hadoop,但中间结果可以存放在内存中。MapReduce仅支持Map+Reduce且不适合迭代计算、交互计算、实时流处理。

提出了RDD模型:容错并行的数据结构,运行用户将中间结果数据集保存在 内存 中,并且通过控制数据集的分区来达到数据存放处理最优化

类型 Hadoop Spark
定位 分布式基础平台,包含计算、存储、调度 分布式计算工具
适用场景 大规模数据集上的批处理 迭代计算、交互式计算、流计算
成本 对机器要求低,便宜 对内存有要求,相对较贵
编程范式 Map+Reduce, API 较为底层,算法适应性差 RDD 组成 DAG 有向无环图,API 较为顶层,方便使用
数据存储结构 中间计算结果存在 HDFS 磁盘上,延迟大 中间运算结果存在内存中,延迟小
任务运行方式 Task 以进程方式维护,任务启动慢 Task 以线程方式维护,任务启动快

结构:Spark Core 核心计算框架、Spark SQL:结构化数据查询、Spark Streaming:实时流处理、Spark MLib机械学习、Spark GraphX:图计算

Sprak Core:RDD

(Resilient Distributed Dataset)叫做弹性分布式数据集,是 Spark 中最基本的数据抽象,代表一个不可变、可分区、里面的元素可并行计算的集合

创建方式:

  • 外部存储系统的数据集创建
  • 已有的RDD经过算子转化
  • Scala集合创建

算子:

  • Transformation 转化操作:返回一个新的RDD
  • Action 动作操作:返回值并不是RDD

持久化:

persist方法或cache方法将计算结果缓存,这两种方法并不是调用会被立即缓存,而是会出触发action才会缓存。注意:通过查看 RDD 的源码发现 cache 最终也是调用了 persist 无参方法(默认存储只存在内存中):

存储级别:

  • 默认:将RDD以非序列化的java对象存储在JVM中,如果没有足够内存,则某些分区不会被缓存
  • MORY_AND_DISK:在默认条件下,将溢出的数据写入磁盘
  • 将RDD以序列化的java对象存储

容错机制:重点

持久化局限性:将缓存放在内存,虽然快但数据容易丢失;放在磁盘也有可能损坏

容错机制就是未了解决上述问题,直接将数据放在HDFS里面。这样程序运行结束后,其处理的数据依然存在。持久化方法会删除。

依赖关系:

  • 宽依赖:父 RDD 的一个分区只会被子 RDD 的一个分区依赖;必须等到上个阶段计算完成才能计算下一个阶段。
  • 窄依赖:父 RDD 的一个分区会被子 RDD 的多个分区依赖(涉及到 shuffle);多个分区可以并行计算;分区数据丢失只需要重新计算就行。

DAG:有向无环图

数据转换执行的过程,有方向,无闭环(其实就是 RDD 执行的流程)

DAG 的边界:

  • 开始:通过 SparkContext 创建的 RDD;
  • 结束:触发 Action,一旦触发 Action 就形成了一个完整的 DAG

一个 Spark 程序可以有多个 DAG,一个 DAG 可以有多个 Stag,同一个 Stage 可以有多个 Task 并行执行,只 reduceByKey 操作是一个宽依赖,从 textFile 到 flatMap 到 map 都是窄依赖。

Spark SQL

Hive 是将 SQL 转为 MapReduce。

SparkSQL 可以理解成是将 SQL 解析成:“RDD + 优化” 再执行

数据分类:

  • 结构化数据:有固定的schema、 如:表格
  • 半结构化数据:无固定的schema,但有结构 如:文件格式JSON
  • 非结构化数据:无固定的schema,无结构、如:图片音频

RDD 主要用于处理非结构化数据 、半结构化数据、结构化;

SparkSQL 主要用于处理结构化数据(较为规范的半结构化数据也可以处理)。

抽象数据:

特性 Spark RDD Spark DataFrame Spark Dataset
本质 弹性分布式数据集 基于 RDD 的分布式数据集合,按命名的列组织 DataFrame API 的扩展,强类型
数据表示 JVM 对象的集合 Row 对象的集合(可理解为无类型的 JVM 对象) 强类型 JVM 对象的集合(如 Dataset[Person]
序列化效率 较低(Java 序列化或 Kryo) 高(Tungsten 二进制格式 + off-heap) 高(同 DataFrame)
优化方式 ,开发者需自行优化 ,Catalyst 查询优化器(逻辑/物理优化) (同 DataFrame)
执行效率 较低 高(Tungsten 优化执行引擎) 高(同 DataFrame)
API 函数式转换(mapfilterreduce 类似 SQL 的结构化操作(selectfiltergroupBy 强类型 API + 类 DataFrame 的无类型 API

Spark Streaming

基于 Spark Core 之上的实时计算框架,可以从很多数据源消费数据并对数据进行实时的处理,具有高吞吐量和容错能力强等

数据抽象:

 DStream(Discretized Stream,离散化数据流,连续不断的数据流),代表持续性的数据流和经过各种 Spark 算子操作后的结果数据流。

① DStream 本质上就是一系列时间上连续的 RDD

② 对 DStream 的数据的进行操作也是按照 RDD 为单位来进行的

③ 容错性,底层 RDD 之间存在依赖关系,DStream 直接也有依赖关系,RDD 具有容错性,那么 DStream 也具有容错性。

总结: 简单来说 DStream 就是对 RDD 的封装,你对 DStream 进行操作,就是对 RDD 进行操作。对于 DataFrame/DataSet/DStream 来说本质上都可以理解成 RD

Structured Streaming

基于 Spark SQL 引擎的可扩展、容错的流处理引擎。统一了流、批的编程模型,你可以使用静态数据批处理一样的方式来编写流式计算操作。并且支持基于 event_time 的时间窗口的处理逻辑。

Spark 两种核心 Shuffle

在 MapReduce 框架中,Shuffle 阶段是连接 Map 与 Reduce 之间的桥梁, Map 阶段通过 Shuffle 过程将数据输出到 Reduce 阶段中。由于 Shuffle 涉及磁盘的读写和网络 I/O,因此 Shuffle 性能的高低直接影响整个程序的性能。Spark 也有 Map 阶段和 Reduce 阶段,因此也会出现Shuffle。

Hash Shuffle

Sort Shuffle

Spark 底层执行原理

申请资源

  1. SparkContext 向资源管理器注册并向资源管理器申请运行 Executor线程
  2. 资源管理器分配 Executor,然后资源管理器启动 Executor
  3. Executor 发送心跳至资源管理器

任务调度和执行

  1. SparkContext 构建 DAG 有向无环图
  2. 将 DAG 分解成 Stage(TaskSet)
  3. 把 Stage 发送给 TaskScheduler任务调度器
  4. Executor 向 SparkContext 申请 Task
  5. TaskScheduler 将 Task 发送给 Executor 运行
  6. 同时 SparkContext 将应用程序代码发放给 Executor
  7. Task 在 Executor 上运行,运行完毕释放所有资源

提问

1. 讲讲spark的数据倾斜

主要是在shuffle阶段,某个或某几个分区的数据量远远超过其他分区,导致“少数几个Task干活特别慢,拖慢了整个Stage甚至整个作业”的现象。其本质是数据分布不均。

产生原因 典型场景 解决方案
Key 分布不均 reduceByKey / groupByKey 某些 key 特别大 - Key 加盐(Salting) 打散大 key- 抽取热点 key 单独处理- 自定义分区器
数据热点(业务本身不均) 日志类数据:某个用户/商品访问量特别高 - map 端局部聚合combineByKey)减少 shuffle- 广播小表(broadcast join)替代 reduce-side join
算子使用不当 使用 groupByKey 导致所有数据拉到 reduce 端 - 改为 reduceByKey(map 端预聚合)- 使用 aggregateByKeycombineByKey
分区器设计不合理 默认 HashPartitioner 导致分布不均 - 自定义分区器,按业务字段规则分区- 增加 spark.sql.shuffle.partitions 并行度
单点热点数据过大 某些 key 的数据量占比极大(如超过 50%) - 单独抽取该 key 走独立逻辑- 其他数据正常走 shuffle

常见原因:

1、key分布不均匀:某些 key 的数据量远大于其他 key,导致部分 task 处理数据过多,运行时间远超其他 task。

2、数据热点:数据本身分布不均匀,大部分落在同一个分区,造成执行缓慢

3、业务逻辑导致单点放大:groupByKey 会把相同 key 的数据收集到同一个 reducer,导致内存溢出或 OOM

4、分区器设计不合理

解决方案

1、数据预处理:剔除异常key,并在map端进行combineByKey或reduceByKey聚合,减少shuffle数据量

2、调优算子选择:将groupByKey改为reduceByKey,因为groupByKey会将所有数据拉到内存,而 reduceByKey 在 map 端可预聚合,减少网络 IO 和数据倾斜风险。

3、Key 加盐:给热点 key 人为拼接随机前缀,把大 key 拆散成多个小 key,打散后在 reduce 阶段再聚合。

4、自定义分区器:根据 key 的实际分布规律,设计自定义 Partitioner,避免数据集中到某一个分区。

5、任务参数调优:增加并行度:提高 spark.sql.shuffle.partitions(默认 200),让 shuffle 后的 task 更多,数据更均匀。调大资源配置:提高 executor 内存、core 数,缓解单 task 负载。

6、拆分热点任务:对于某些极端热点 key,可以单独抽取出来单独处理,其余数据正常 shuffle

2. 讲讲spark的宽窄依赖

窄依赖(Narrow Dependency)

定义

  • 子 RDD 的每个分区只依赖于父 RDD 的一个或少量分区
  • 不涉及全量数据的重新分布,数据依赖关系是局部的。

特点

  • 数据本地性好:数据只需要在父分区和子分区之间传递,不会发生大量的网络 IO。
  • 可以流水式计算:父 RDD 分区算完直接传递给子 RDD,task 可以 pipeline 化执行。
  • 执行效率高

宽依赖

定义

  • 子 RDD 的一个分区依赖于父 RDD 的多个分区
  • 涉及数据的 shuffle,需要跨节点数据传输和重新分区。

特点

  • 会触发 shuffle:需要将父 RDD 的数据按照 key 或分区规则重新分布。
  • 存在网络 IO 和磁盘 IO,性能开销大。
  • 会产生 stage 划分:DAG 会在宽依赖处切分 stage。

Hive

4. 讲讲hive的内部表外部表

udf udaf udtf核心区别总结

特性 UDF  UDAF  UDTF 
全称 用户自定义函数 用户自定义聚合函数 用户自定义表生成函数
输入输出关系 一行进,一行出 多行进,一行出 一行进,多行出
功能类比 类似于 SQL 中的普通函数 类似于 SQL 中的聚合函数 类似于 SQL 中的 EXPLODE() 函数
常见场景 数据格式化、字段拼接、大小写转换、计算等 求和、求平均、求最大值、计数、Top N 等 解析JSON数组、Map键值对展开、一行拆多行
继承类 org.apache.hadoop.hive.ql.exec.UDF org.apache.hadoop.hive.ql.exec.UDAF org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
开发难度 简单 复杂 中等

数仓

模型

层级


网站公告

今日签到

点亮在社区的每一天
去签到