这是我参与「第四届青训营 」笔记创作活动的第3天
大数据处理引擎 Spark 介绍
Spark 的特点
- 统一引擎,支持多种分布式场景
- 多语言支持(SQL、Java、Scala、R、Python, etc.)
- 可读写丰富的数据源:内置data source、自定义data source
- 丰富灵活的 API/算子
- SparkCore -> RDD (map, reduce, repartition, groupBy, foreach, count, etc.)
- SparkSQL -> DataFrame (select, filter, agg, join, orderBy, UDF, etc.)
- 支持 K8S/YARN/Mesos 资源调度
Spark 架构
- Driver Program(驱动器):整个应用的管理者,是一个JVM的进程,运行程序的main()函数创建一个SparkContext上下文。一个Spark Application只有一个Driver
- Cluster Manager(集群管理器):控制整个集群,监控worker节点,负责资源管理和调度。用于在集群上申请资源的外部服务(如:独立部署的集群管理器、Mesos或者Yarn)
- Worker Node(工作节点):集群上运行应用程序代码的节点,启动工作进程executor
- Executor(执行器):在集群工作节点上为某个应用启动的工作进程,该进程负责运行计算任务,并为应用程序存储数据。
SpareCore 原理解析
RDD
RDD(Resilient Distributed Dataset),弹性分布式数据集,是一个容错的、并行的数据结构
五个特性
- 分区:每个RDD都会有多个分区,运行在集群的不同节点上,决定了并行计算的数量
- 计算函数:每个RDD都会实现一个compute函数,对具体的partition进行计算
- 依赖:每个RDD都会依赖于其他RDD,每次转换生成新的RDD,形成前后依赖关系,便于丢失时重新计算
- 实现了两种类型的分区函数:hash/range partition (for key-value RDDs)
- 每个分区都会有优先的位置列表,存储每个partition的优先位置。(移动数据不如移动计算,将计算移动到需要处理的数据块的存储位置)
RDD算子
- Transform(转换)算子: 生成新的RDD(map, filter, groupBy, etc.)
- Action(动作)算子: 将在数据集上运行计算后的数值返回到驱动程序,触发真正的计算 (count, collect, take, etc.)
RDD依赖:描述父子RDD之间的依赖关系
- 窄依赖:父RDD的每个partition至多对应一个子RDD分区
- 宽依赖:父RDD的每个partition都可能对应多个子RDD分区,会产生shuffle
RDD执行流程
Job: RDD action 算子触发
Stage: 根据宽依赖划分
Task: Stage内执行的单个 partition 任务
Scheduler 调度器
触发job后,将DAG提交给DAG Scheduler。DAG Scheduler根据shuffle dependency将DAG分为不同的stage,为每个stage生成一个TaskSet任务集合并以TaskSet为单位提交给TaskScheduler。TaskScheduler根据调度算法(FIFO/FAIR)对多个TaskSet进行调度。对于调度到的TaskSet,会将task调度到相关的executor上执行
- DAG: 有向无环图,Spark中的RDD通过一系列的转换算子操作和行动算子操作形成了一个DAG
- DAGScheduler:将作业的DAG划分成不同的Stage,每个Stage都是TaskSet任务集合,并以TaskSet为单位提交给TaskScheduler。
- TaskScheduler:通过TaskSetManager管理Task,并通过集群中的资源管理器(Standalone模式下是Master,Yarn模式下是ResourceManager)把Task发给集群中Worker的Executor
内存管理
executor 内存主要有两类:storage、execution
- storage:缓存RDD数据或广播数据
- execution:shuffle(/join/sort/agg)时占用的内存
UnifiedMemoryManager统一管理storage/execution内存,动态调整,可以互相借用。execution使用的内存不能被storage驱逐;而当execution需要内存时,可以驱逐被storage借用的内存
以上都是堆内内存,Spark还引入了堆外内存,可以减少不必要的内存开销和频繁的gc
多任务之间的内存分配:
- 在一个executor中,所有task共享JVM内存
- UnifiedMemoryManager统一管理多个task的内存分配
- 每个task获取1/(2N) ~ 1/N,N为当前executor中正在并发运行的task数量
SparkSQL 原理解析
Catalyst:在执行过程中对执行计划进行处理和优化,生成可以执行的代码
Adaptive Query Execution:自适应查询执行,spark 3.0新增的特性。可以根据运行时的统计数据对正在运行的查询进行优化,边执行边优化。每个task结束会发送MapStatus信息给Driver,用于对后续的执行计划进行优化
Runtime Filter:运行时过滤。对join算法的优化。减少了大表扫描,shuffle的数据量和参与join的数据量
Codegen:生成程序代码的技术或系统,可以在运行时环境中独立于生成器系统使用
DataFrame: 是一种以RDD为基础的分布式数据集, 被称为SchemaRDD