Spark原理与实践 | 青训营笔记

281 阅读4分钟

Spark原理与实践 | 青训营笔记

这是我参与「第四届青训营 」笔记创作活动的的第5天

今天笔记主要分为四个部分:

大数据处理引擎Spark介绍

Spark生态和特点

特点:

  1. 统一引擎,支持多种分布式场景
  1. 多语言支持
  1. 可读写丰富数据源
  1. 丰富灵活的API/算子
  1. 支持K8S、YERN、MESOS资源调度

运行架构

首先用户创建一个SparkContext,SparkContext链接到Cluster Manager,Cluster Manager会根据用户提交设置的参数(CPU,内存)去给用户分配资源,启动Executor。Driver会将用户程序划分为不同的stage,每个stage会有完全相同的一组task,这些task会作用于待处理的数据的不同分区,在阶段划分完成后和task创建完成后,Driver会向Executor发送task,Executor在接受task之后,会下载依赖,准备好执行环境。并将每次运行状态发送给Driver,Driver根据运行状态做状态更新,直到所有task执行正确或超出执行限制。

部署方式

  • Spark Local Mode 本地测试/单进程多线程模式
  • Spark Standalone Mode 需要启动Spark的Standalone集群的Master/Worker
  • On YARN/K8S 依赖外部资源调度器

SparkCore 原理解析

RDD

定义

表示可并行操作的不可变的分区元素集合。

RDD五要素

RDD算子

  1. Transform算子:生成一个新的RDD
  1. Action算子:触发Job提交

RDD依赖

  1. 窄依赖:父RDD的每个partition至多对应一个子RDD分区
  • NarrowDependency
  • PruneDependency
  • RangeDependency
  • OneToOneDependency
  1. 宽依赖:父RDD的每个partition都可能对应多个子RDD分区

RDD执行流程

调度器

内存管理

执行器内存有两种:Storage、Execution

  • UnifiedMemoryManager统一管理Storage/Execution内存
  • Storage、Execution内存使用的是动态调整,可以互相借用。
  • 当Storage空闲 ,Execution可以借用Storage的内存使用
  • 可以减少spill等操作,Execution使用的内存不能被Storage驱逐
  • 当Execution空闲,Storage可以借用Execution的内存使用
  • 当Execution需要内存时,可以驱逐被Storage借用的内存,直到spark.memory.storageFraction边界

多任务间内存分配

UnifiedMemoryManager统一管理Storage/Execution内存

每个Task获取的内存区间为1/(2*N)~1/N (N为当前执行器中正在并发运行的task数量)

Shuffle

SortShuffleManager

External Shuffle Service

shuffle write 的文件被Node Manager中的Shuffle Service托管,供后续Reduce Task进行shuffle fetch,如果Executor空闲,DRA可以进行回收。

SparkSQL原理解析

SparkSQL

Catalyst优化器

RBO

Batch执行策略:

  • Once ->只执行一次
  • FixedPoint -> 重复执行,直到plan不再改变,或者执行达到固定次数(默认100次)

RBO规则:

transformDown 先序遍历树进行规则匹配

transformUp 后序遍历树进行规则匹配

CBO

需要预先统计数据

AQE(自适应查询)

每个Task结束会发送MapStatus信息给Driver

特点:边优化边执行,根据已经完成计划的真实节点去做统计,进行反馈,优化剩余计划。

三种优化场景

Partition合并

作业运行过程中,根据前面运行完的Stage的MapStatus中实际的partition大小信息,可以将多个相邻的较小的partition进行动态合并,右一个Task读取进行处理。

动态切换JOIN策略

1存在的问题时Catalyst Optimizer优化阶段,算子的statistics估算不准确,生成的执行计划并不是最优。

2的解决方案时AQE运行过程中动态获取准确JOIN的leftChild/rightChild的实际大小,将SMJ转换为BHJ。

Skew Join

AQE根据MapStates信息自动检测是否右倾斜,将大的partition拆分成多个Task进行Join

Runtime Filter

Runtime Filter减少了大表的扫描,shuffle的数据量以及参加啊Join的数据量,所以对整个集群IO/网络/CPU有比较大的节省

Bloom Runtime Filter

Codegen

Expression(表达式)

将表达式中的大量虚函数调用压平到一个函数内部,类似手写代码。

WholeStageCodegen

原先编译的火山模型算子之间大量的虚函数调用,开销大

现在将同一个Stage中的多个算子压平到一个函数内部去执行。

业界挑战与实践

Shuffle 稳定性问题

在大规模作业下,开源ESS的实现机制容易带来大量随机读导致的磁盘IOPS瓶颈、Fetch请求积压等问题,进而导致运算过程中经常会出现Stage重算甚至作业失败,继而引起资源使用的恶性循环,严重影响SLA。

解决方案(下次笔记重点写shuffle)

  • 数据远端存储
  • Map,Reduce端partition的数据进行聚合

SQL执行性能问题

目前的解决方案:

参数推荐/作业诊断

存在的问题:

  • 调参难度大
  • 参数不合理的作业,对资源利用率/Shuffle稳定性/性能有非常大影响
  • 线上作业失败/运行慢的时候用户排查难度大

解决方案:

  • 自动参数推荐
  • 作业诊断