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

108 阅读3分钟

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

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

01-大数据处理引擎Spark介绍

1.1 大数据处理技术栈

数据 -> 存储 -> 计算 -> 应用

海量的数据,数据源种类丰富多样,快速处理来提升数据的价值。

存储:Parquet/ORC高性能列式存储,数据湖技术优化存储的读写

HDFS: 分布式文件存储系统

Kafka: 分布式消息系统

HBase: k-v分布式存储的No-SQL引擎数据库

Kudu: 基于列式存储的分布式数据库

TOS/S3: 对象存储

Presto/Implala/ClickHouse: 处理在线分布式查询场景的,可交互式的OLAP引擎

常见的大数据处理链路:

  1. 数据源(数据库,日志,…)

  2. 数据采集(采集到的原始数据可以存储到:Kafka,HDFS,…)

  3. 数据处理(Kafka,Iceberg/Hudi;多次数据的读取和写入)

  4. 数据应用(BI报表,OLAP,机器学习)

Spark特点:

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

02-SparkCore原理介绍

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

两类RDD算子:

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

RDD依赖:

窄依赖:父RDD的每个partition至多对应一个子RDD分区。

宽依赖(会产生Shuffle):父RDD的每个partition都可能对应多个子RDD分区。

RDD执行流程:

  • Job:RDD action算子触发
  • Stage:依据宽依赖划分
  • Task:Stage内执行单个partition任务

根据ShuffleDependency切分Stage,并按照依赖顺序调度Stage,为每个Stage生成并提交TaskSet到TaskScheduler

根据调度算法(FIFO/FAIR)对多个TaskSet进行调度,对于调度到的TaskSet,会将Task调度(locality)到相关Executor_上面执行,Executor SchedulerBackend提供。

Executor内存主要有两类:Storage、Execution

UnifiedMemoryManager统一管理Storage/Execution内存

Storage和Execution内存使用是动态调整,可以相互借用

当Storage空闲,Execution可以借用Storage的内存使用,可以减少spill等操作,Execution使用的内存不能被Storage驱逐

当Execution空闲,Storage可以借用Execution的内存使用,当Execution需要内存时,可以驱逐被Storage借用的内存,直到spark.memory.storageFraction边界

03-SparkSQL原理解析

RBO使用Catalyst优化器

Adaptive Query Execution(AQE):每个Task结束会发送MapStatus信息给Driver。Task的MapStatus中包含当前Task Shuffle产生的每个Partition的size统计信息。Driver获取到执行完的Stages的MapStatus信息之后,按照MapStatus中partition;大小信息识别匹配一些优化场景,然后对后续未执行的Plan进行优化。

04-业界挑战与实践

  1. shuffle稳定性问题

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

远程shuffle方案来解决。

  1. SQL执行性能问题
  2. SQL执行性能解决方向
  3. 参数推荐/作业诊断