SQL Optimizer 解析
https://bytedance.feishu.cn/file/boxcn9uWBTLWg2a8GIUSRJ0Txqb
https://live.juejin.cn/4354/yc_SQL
hash join和sort merge join:https://blog.csdn.net/lp284558195/article/details/80717219
大数据体系和SQL
SQL 的一生
-
- Parser
- 把文本变成抽象语法树结构(AST)
- 涉及词法分析阶段(拆分字符串,提取关键字,字符串,数值等)和语法分析阶段(把词条按照定义的语法规则组装成抽象语法树结构)
- 和编译原理课程里的“前端”知识相关
- Analyzer
- 访问库/表元信息并绑定
- 判断 SQL 是否合理,比如数据库,表和列名是否存在,列的数据类型是否正确
- 将 AST 转换成逻辑计划树(在某些系统中这个工作由一个 Converter 完成)
-
逻辑计划树
- 所谓逻辑计划树,可以理解为逻辑地描述一个 SQL 如何一步步地执行查询和计算,最终得到执行结果的一个分步骤地计划。树中每个节点是是一个算子,定义了对数据集合的计算操作(过滤,排序,聚合,连接),边代表了数据的流向,从孩子节点流向父节点。之所以称它为逻辑的,是因为算子定义的是逻辑的计算操作,没有指定实际的算法,比如对于逻辑的排序算子,逻辑计划树里没有指定使用快排还是堆排。
-
查询优化
- SQL 是一种声明式语言,用户只描述做什么,没有告诉数据库怎么做
- 查询优化的目标是为 SQL 找到一个正确的且执行代价最小的执行计划
- 查询优化器是数据库的大脑,最复杂的模块,很多相关问题都是 NP 的
- 一般 SQL 越复杂,Join 的表越多,数据量越大,查询优化的意义就越大,因为不同执行方式的性能差别可能有成百上千倍
- 类比 gcc/g++ 编译程序时的编译级别(-O1, -O2, -O3),经过编译优化的程序运行效率更高
-
物理执行计划
- 优化器的输出是一个分布式的物理执行计划。
- 分布式物理执行计划的目标是在单机 Plan 的基础上最小化数据移动和最大化本地 Scan,生成 PlanFragment 树。
- 一个 PlanFragment 封装了在一台机器上对数据集的操作逻辑。每个 PlanFragment 可以在每个 executor 节点生成 1 个或多个执行实例,不同执行实例处理不同的数据集,通过并发来提升查询性能。
- Plan 分布式化的方法是增加 shuffle 算子,执行计划树会以 shuffle 算子为边界拆分为PlanFragment。
-
Executor
- Executor 按照物理执行计划扫描和处理数据,充分利用机器资源(CPU 流水线,乱序执行,cache,SIMD)
常见的查询优化器
RBO
Rule-based Optimizer
- 基于关系代数等价规则对逻辑计划进行变换
- 实现上:
- Pattern:定义了特定结构的 Operator 子树(结构)
- Rule:定义了如何将其匹配的节点替换(Substitute)为新形态,从而生成新的、等价的Operator 树(原地替换)
- 优化器搜索过程被抽象为不断匹配 Pattern 然后应用 Rule 转换,直到没有可以匹配的 rule
- 局限性:
- 无法解决多表连接问题
- 无法确定和选择最优的分布式 Join/Aggregate 执行方式
列裁剪
scan时只扫描select选中的列
谓词下推
如有where条件,在scan时就过滤掉
传递闭包
如有jion on条件,可将一个表的where scan 传递给另一个表的 where scan
Runtime Filter(min-max filter,in-list filter,bloom filter)
jion前2个表都有filter,可将一个表filter后的一些索引特性在运行时传递给另一个表,这是另一个表进行filter时就可以减少很大一部分数据
Join 消除
谓词合并
小结
主流RBO实现一般都有几百条基于经验归纳得到的优化规则
实现简单,优化速度块,但不能保证最优的执行计划
CBO
Cost-based Optimizer
过程
使用一个模型估算执行计划的代价,选择代价最小的执行计划
分而治之,执行计划的代价等于所有算子的执行代价之和
通过 RBO 得到(所有)可能的等价执行计划(非原地替换)
算子代价包含 CPU,cache misses,memory,disk I/O,network I/O 等代价
- 和算子的统计信息有关,比如输入、输出结果的行数,每行大小等
- 叶子算子 scan:通过统计原始表数据得到
- 中间算子:根据一定的推导规则,从下层算子的统计信息推导得到
- 和具体的算子类型,以及算子的物理实现有关(e.g. hash join vs. sort join)
使用动态规划枚举所有执行计划,选出执行代价最小的执行计划
统计信息
- 基表统计信息
- 表或者分区级别:行数、行平均大小、表在磁盘中占用了多少字节等
- 列级别:min、max、num nulls、num、not nulls、num、distinct value(NDV)、histogram 等
- 推导统计信息
- 选择率(selectivity) :对于某一个过滤条件,查询会从表中返回多大比例的数据
- 基数(cardinality) :基本含义是表的 unique 行数,在查询计划中常指算子需要处理的行数
统计信息的收集方式
三种
统计信息推导规则
统计信息的问题
小结
CBO使用代价模型和统计信息估算执行计划的代价
CBO使用贪心或者动态规划算法寻求最优执行计划
社区开源实践
Apache Calcite
主流的查询优化器都包含RBO/CBO
Apache Calcite是大数据领域很流行的查询优化器
Apache Calcite RBO定义了很多优化规则,使用pattern匹配子树,执行等价变换
Apache Calcite CBO基于Volcano/Cascade 框架
Volcano/Cascade的精髓Memo、动态规划、剪枝
前沿趋势
存储计算分离
HSAP, HTAP, HTSAP
Cloud Native, Serverless
数据仓库,数据湖,湖仓一体,联邦查询
智能化
- AI4DB
- 自配置:智能调参(OtterTune,QTune)、负载预测、负载调度
- 自诊断和自愈合:软硬件错误、错误恢复和迁移
- 自优化:统计信息估计( Learned cardinalities )、代价估计、学习型优化器(IBM DB2 LEO),索引推荐,视图推荐
- DB4AI
- 内嵌人工智能算法(MLSQL,SQLFlow)
- 内嵌机器学习框架(SparkML, Alink, dl-on-flink )
流/批/OLAP 一体的 Flink 引擎介绍
https://bytedance.feishu.cn/file/boxcni8teJOjd4vUsgxn8rL0ylc
https://live.juejin.cn/4354/yc_OLAP
Apache Flink 概述
批处理
所谓 批处理 是指把一项数据处理任务先分解成更小粒度的任务,把这些任务分布在集群中的各台实例上进行计算,之后把各实例上的计算结果重新计算和组合成最终结果。批处理系统通常会操作大量的静态的数据,并等到这些数据全部处理完成后才能得到返回的结果。
批处理方式使用的数据集通常有以下特征:
- 有界:批处理数据集代表数据的有限集合
- 持久:数据通常始终存储在某种类型的持久存储位置中
- 大量:批处理操作通常是处理极为海量数据集的唯一方法
流处理
流处理 方式会随时对进入系统的数据进行实时的计算,这种模式不需要针对整个数据集执行操作,而是对通过系统传输的每个数据项执行操作。流处理中的数据集是 无边界 的,这就产生了几个重要的影响:
- 完整数据集只能代表截至目前已经进入到系统中的数据总量。
- 工作数据集也许更相关,在特定时间只能代表某个单一数据项。
- 处理工作是基于事件的,除非明确停止否则没有“尽头”。处理结果立刻可用,并会随着新数据的抵达继续更新。
混合处理
在大数据处理技术中流派中,除了单纯的批处理和流处理模式之外,还有一些处理框架既可以进行批处理也可以进行流处理,我们称之为混合处理框架。虽然专注于一种处理方式可能非常适合特定场景,但是混合框架为数据处理提供了通用的解决方案。这些框架可以用相同或相关的组件和 API 处理两种类型的数据,借此让不同的处理需求得以简化。混合处理框架中目前比较著名的就是 Spark 和 Flink 。
为什么 Flink 会脱颖而出
完全一次保证:故障后应正确恢复有状态运算符中的状态;
低延迟:越低越好。许多应用程序需要亚秒级延迟;
高吞吐量:随着数据速率的增长,通过管道推送大量数据至关重要;
强大的计算模型:框架应该提供一种编程模型,该模型不限制用户并允许各种各样的应用程序在没有故障的情况下,容错机制的开销很低;
流量控制:来自慢速算子的反压应该由系统和数据源自然吸收,以避免因消费者缓慢而导致崩溃或降低性能;
乱序数据的支持:支持由于其他原因导致的数据乱序达到、延迟到达后,计算出正确的结果;
完备的流式语义:支持窗口等现代流式处理语义抽象;
Google Dataflow Model 的开源引擎实现。
Apache Flink 开源生态
Apache Flink 在开源生态上的能力比较强大,可以支持:
流批一体:支持流式计算和批式计算;
OLAP:Flink 可以支持 OLAP 这种短查询场景;
Flink ML:pyFlink、ALink、AIFlow 等生态支持 Flink 在 ML 场景的应用;
Gelly:图计算;
Stateful Function:支持有状态的 FAAS 场景;
Flink 整体架构
Flink 分层架构
-
SDK 层:Flink’s APIs Overview;
-
执行引擎层(Runtime 层):执行引擎层提供了统一的 DAG,用来描述数据处理的 Pipeline,不管是流还是批,都会转化为 DAG 图,调度层再把 DAG 转化成分布式环境下的 Task,Task 之间通过 Shuffle 传输数据;
- 调度:Jobs and Scheduling;
- Task 生命周期:Task Lifecycle;
- Flink Failover 机制:Task Failure Recovery;
- Flink 反压概念及监控:Monitoring Back Pressure;
- Flink HA 机制:Flink HA Overview;
-
状态存储层:负责存储算子的状态信息
Flink 整体架构
-
JobManager(JM)负责整个任务的协调工作,包括:调度 task、触发协调 Task 做 Checkpoint、协调容错恢复等,核心有下面三个组件:
- Dispatcher: 接收作业,拉起 JobManager 来执行作业,并在 JobMaster 挂掉之后恢复作业;
- JobMaster: 管理一个 job 的整个生命周期,会向 ResourceManager 申请 slot,并将 task 调度到对应 TM 上;
- ResourceManager:负责 slot 资源的管理和调度,Task manager 拉起之后会向 RM 注册;
-
TaskManager(TM):负责执行一个 DataFlow Graph 的各个 task 以及 data streams 的 buffer 和数据交换。
Flink 如何做到流批一体
批式计算是流式计算的特例,Everything is Streams,有界数据集(批式数据)也是一种数据流、一种特殊的数据流;
站在 Flink 的角度,Everything is Streams,无边界数据集是一种数据流,一个无边界的数据流可以按时间切段成一个个有边界的数据集,所以有界数据集(批式数据)也是一种数据流。因此,不管是有边界的数据集(批式数据)还是无边界数据集,Flink 都可以天然地支持,这是 Flink 支持流批一体的基础。并且 Flink 在流批一体上,从上面的 API 到底层的处理机制都是统一的,是真正意义上的流批一体。
Apache Flink 主要从以下几个模块来做流批一体:
- SQL 层;
- DataStream API 层统一,批和流都可以使用 DataStream API 来开发;
- Scheduler 层架构统一,支持流批场景;
- Failover Recovery 层 架构统一,支持流批场景;
- Shuffle Service 层架构统一,流批场景选择不同的 Shuffle Service;
Flink 架构优化
Flink 如何支持 OLAP 场景
Flink 做 OLAP 的优势
- 统一引擎:流处理、批处理、OLAP 统一使用 Flink 引擎;
- 降低学习成本,仅需要学习一个引擎;
- 提高开发效率,很多 SQL 是流批通用;
- 提高维护效率,可以更集中维护好一个引擎;
- 既有优势:利用 Flink 已有的很多特性,使 OLAP 使用场景更为广泛;
- 使用流处理的内存计算、Pipeline;
- 支持代码动态生成;
- 也可以支持批处理数据落盘能力;
- 相互增强:OLAP 能享有现有引擎的优势,同时也能增强引擎能力
- 无统计信息场景的优化;
- 开发更高效的算子;
- 使 Flink 同时兼备流、批、OLAP 处理的能力,成为更通用的框架。
Flink OLAP 场景的挑战
-
秒级和毫秒级的小作业;
-
作业频繁启停、资源碎片;
- Flink OLAP 计算相比流式和批式计算,最大的特点是 Flink OLAP 计算是一个面向秒级和毫秒级的小作业,作业在启动过程中会频繁申请内存、网络以及磁盘资源,导致 Flink 集群内产生大量的资源碎片;
-
Latency + 高 APS 要求;
- OLAP 最大的特点是查询作业对 Latency 和 QPS 有要求的,需要保证作业在 Latency 的前提下提供比较高的并发调度和执行能力,这就对 Flink 引擎提出了一个新的要求。
-
Flink OLAP 架构现状
- Client:提交 SQL Query;
- Gateway:接收 Client 提交的 SQL Query,对 SQL 进行语法解析和查询优化,生成 Flink 作业执行计划,提交给 Session 集群;
- Session Cluster:执行作业调度及计算,并返回结果。
- JobManager 管理作业的执行,在接收到 Gateway 提交过来的作业逻辑执行计划后,将逻辑执行计划转换为物理执行计划,为每个物理计算任务分配资源,将每个计算任务分发给不同的 TaskManager 执行,同时管理作业以及每个计算任务执行状态;
- TaskManager执行具体的计算任务,采用线程模型,为每个计算任务创建计算线程,根据计算任务的上下游数据依赖关系跟上游计算任务建立/复用网络连接,向上游计算任务发送数据请求,并处理上游分发给它的数据。
Flink 在 OLAP 架构上的问题与设想
- 架构与功能模块:
- JobManager 与 ResourceManager 在一个进程内启动,无法对JobManager 进行水平扩展;
- Gateway 与 Flink Session Cluster 互相独立,无法进行统一管理;
- 作业管理及部署模块:
- JobManager 处理和调度作业时,负责的功能比较多,导致单作业处理时间长、并占用了过多的内存;
- TaskManager 部署计算任务时,任务初始化部分耗时验证,消耗大量 CPU;
- 资源管理及计算任务调度:
- 资源申请及资源释放流程链路过长;
- Slot 作为资源管理单元,JM 管理 slot 资源,导致 JM 无法感知到 TM 维度的资源分布,使得资源管理完全依赖于 ResourceManager;
- 其他:
- 作业心跳与 Failover 机制,并不合适 AP 这种秒级或毫秒级计算场景;
- AP 目前使用 Batch 算子进行计算,这些算子初始化比较耗时;
精选案例讲解
Exactly Once 语义在 Flink 中的实现
https://bytedance.feishu.cn/file/boxcnFPburXr95rMNel1SHOvISg
https://live.juejin.cn/4354/yc_Once
数据流和动态表
-
如何在实时数据流中定义 SQL 语义中的表?
- 动态表 : 随时间不断变化的表,在任意时刻,可以像查询静态批处理表一样查询它们
-
实时流的查询特点?
- 查询从不终止
- 查询结果会不断更新,并且会产生一个新的动态表
- 结果的动态表也可转换成输出的实时流
-
动态表到实时流的转换
- Append-only Stream: Append-only 流(只有 INSERT 消息)
- Retract Stream: Retract 流(同时包含 INSERT 消息和 DELETE 消息)
- Upsert Stream:: Upsert 流(同时包含 UPSERT 消息和 DELETE 消息)
算子状态
在流式计算中,会存在有状态的计算逻辑(算子)
比如,需要计算某个用户在网上的点击量,该用户在网站当前的总点击次数就是算子状态,对于新的输入数据,先判断是否是该用户的点击行为,如果是,则将保留的点击次数(状态)增加一,并将当前累加结果输出。
Exactly-Once 和 Checkpoint
一致性保证语义
-
At-most-once:每条数据消费至多一次,处理延迟低
-
At-least-once:每条数据消费至少一次,一条数据可能存在重复消费
-
Exactly-once:每条数据都被消费且仅被消费一次,仿佛故障从未发生
端到端 Exactly-Once 实现
Chandy-Lamport算法
解耦了快照制作和数据处理过程,各个算子制作完成状态快照后就可以正常处理数据,不用等下游算子制作制作完成快照; 在快照制作和 Barrier Alignment 过程中需要暂停处理数据,仍然会增加数据处理延迟; 快照保存到远端也有可能极为耗时。
Checkpoint 能保证每条数据都对各个有状态的算子更新一次,sink 输出算子仍然可能下发重复的数据; 严格意义的端到端的 Exactly-once 语义需要特殊的 sink 算子实现。
两阶段提交协议(2PC)
-
Coordinator:协作者,同步和协调所有节点处理逻辑的中心节点
-
Participant:参与者,被中心节点调度的其他执行处理逻辑的业务节点
事务开启:在 sink task 向下游写数据之前,均会开启一个事务,后续所有写数据的操作均在这个事务中执行,事务未提交前,事务写入的数据下游不可读; 预提交阶段:JobManager 开始下发 Checkpoint Barrier,当各个处理逻辑接收到 barrier 后停止处理后续数据,对当前状态制作快照,此时 sink 也不在当前事务下继续处理数据(处理后续的数据需要新打开下一个事务)。状态制作成功则向 JM 成功的消息,失败则发送失败的消息; 提交阶段:若 JM 收到所有预提交成功的消息,则向所有处理逻辑(包括 sink)发送可以提交此次事务的消息,sink 接收到此消息后,则完成此次事务的提交,此时下游可以读到这次事务写入的数据;若 JM 有收到预提交失败的消息,则通知所有处理逻辑回滚这次事务的操作,此时 sink 则丢弃这次事务提交的数据下。
Flink 案例讲解
流式计算中的 Window 计算
https://zhuanlan.zhihu.com/p/102484347
https://bytedance.feishu.cn/file/boxcn5expS9gYOnxpZUBayXPwVg
https://live.juejin.cn/4354/yc_Window
Watermark
Watermark定义:当前系统认为的事件时间所在的真实时间。
简单来说 Watermark 是一个时间戳,表示已经收集完毕的数据的最大 event time,换句话说 event time 小于 Watermark 的数据不应该再出现,基于这个前提我们才有可能将 event time 窗口视为完整并输出结果。
-
怎么观察一个任务中的watermark是多少,是否是正常的
- 一般通过Flink Web UI上的信息来观察当前任务的watermark情况
- 这个问题是生产实践中最容易遇到的问题,大家在开发事件时间的窗口任务的时候,经常会忘记了设置watermark,或者数据太少,watermark没有及时的更新,导致窗口一直不能触发。
-
如果有部分partition/subtask会断流,应该如何处理
- 数据断流是很常见的问题,有时候是业务数据本身就有这种特点,比如白天有数据,晚上没有数据。在这种情况下,watermark默认是不会更新的,因为它要取上游subtask发来的watermark中的最小值。此时我们可以用一种IDLE状态来标记这种subtask,被标记为这种状态的subtask,我们在计算watermark的时候,可以把它先排除在外。这样就可以保证有部分partition断流的时候,watermark仍然可以继续更新。
-
算子对于时间晚于watermark的数据的处理
- 对于迟到数据,不同的算子对于这种情况的处理可以有不同的实现(主要是根据算子本身的语义来决定的)
- 比如window对于迟到的数据,默认就是丢弃;比如双流join,对于迟到数据,可以认为是无法与之前正常数据join上。
Window
TUMBLE Window (滚动窗口)
HOP Window (滑动窗口)
SESSION Window (会话窗口)
迟到数据处理
根据上面说到的watermark原理,watermark驱动某个窗口触发输出之后,这个窗口如果后面又来了数据,那这种情况就属于是迟到的数据了。(注意,不是数据的时间晚于watermark就算是迟到,而是它所属的窗口已经被触发了,才算迟到)。
对于迟到的数据,我们现在有两种处理方式:
-
使用side output方式,把迟到的数据转变成一个单独的流,再由用户自己来决定如何处理这部分数据
-
直接drop掉
注意:side output只有在DataStream的窗口中才可以用,在SQL中目前还没有这种语义,所以暂时只有drop这一个策略。
增量计算 VS 全量计算
-
增量计算:每条数据到来后,直接参与计算(但是还不需要输出结果)
-
全量计算:每条数据到来后,先放到一个buffer中,这个buffer会存储到状态里,直到窗口触发输出的时候,才把所有数据拿出来统一进行计算
EMIT触发
正常的窗口都是窗口结束的时候才会进行输出,EMIT触发就是在这种情况下,可以提前把窗口内容输出出来的一种机制。比如我们可以配置一个1天的窗口,每隔5s输出一次它的最新结果,那这样下游就可以更快的获取到窗口计算的结果了。
这种emit的场景就是一个典型的retract的场景,发送的结果类似于+[1], -[1], +[2], -[2], +[4]这样子。这样才能保证window的输出的最终结果是符合语义的。
Window Offset
滑动窗口的时间戳是按照unix timestamp来算的。比如我们要用一个一周的窗口,想要的是从周一开始,到周日结束,但是按照上面这种方式计算出来的窗口的话,就是从周四开始的
Window 高级优化
Mini-batch
赞一小批数据再进行计算,这批数据每个key的state访问只有一次,这样在单个key的数据比较集中的情况下,对于状态访问可以有效的降低频率,最终提升性能。
Local-global
所谓的local-global,就是将原本的聚合划分成两阶段,第一阶段先做一个local的聚合,这个阶段不需要数据shuffle,是直接跟在上游算子之后进行处理的;第二个阶段是要对第一个阶段的结果做一个merge
Distinct状态复用
对于distinct的优化,一般批里面的引擎都是通过把它优化成aggregate的方式来处理,但是在流式window中,我们不能直接这样进行优化,要不然算子就变成会下发retract的数据了。
滑动窗口pane复用
将窗口的状态划分成更小粒度的pane,比如上面3小时窗口、1小时滑动的情况,可以把pane设置为1h,这样每来一条数据,我们就只更新这条数据对应的pane的结果就可以了。当窗口需要输出结果的时候,只需要将这个窗口对应的pane的结果merge起来就可以了。
Spark 原理与实践
https://www.bilibili.com/video/BV11A411L7CK
https://zhuanlan.zhihu.com/p/34436165
https://bytedance.feishu.cn/file/boxcnvEmKZp3gR3Q1swBBrrxDJb
https://live.juejin.cn/4354/yc_Spark
大数据处理引擎Spark介绍
Spark下载编译
1、官网download
2、查看运行是需要的依赖、参数配置等等
|
|
3、查看客户端的命令
|
|
Spark运行架构和工作原理
Spark生态组件:
-
Spark Core:Spark核心组件,它实现了Spark的基本功能,包含任务调度、内存管理、错误恢复、与存储系统交互等模块。
-
Spark SQL:用来操作结构化数据的核心组件,通过Spark SQL可以直接查询Hive、HBase等多种外部数据源中的数据。
-
Spark Structured Streaming:Spark提供的流式计算框架,支持高吞吐量、可容错处理的实时流式数据处理。
-
MLlib:Spark提供的关于机器学习功能的算法程序库,包括分类、回归、聚类、协同过滤算法等,还提供了模型评估、数据导入等额外的功能。
-
GraphX:Spark提供的分布式图处理框架,拥有对图计算和图挖掘算法的API接口以及丰富的功能和运算符。
-
独立调度器、Yarn、Mesos、Kubernetes:Spark框架可以高效地在一个到数千个节点之间伸缩计算,集群管理器则主要负责各个节点的资源管理工作,为了实现这样的要求,同时获得最大灵活性,Spark支持在各种集群管理器(Cluster Manager)上运行。
Spark 运行架构和工作原理:
-
Application(应用):Spark上运行的应用。Application中包含了一个驱动器(Driver)进程和集群上的多个执行器(Executor)进程。
-
Driver Program(驱动器):运行main()方法并创建SparkContext的进程。
-
Cluster Manager(集群管理器):用于在集群上申请资源的外部服务(如:独立部署的集群管理器、Mesos或者Yarn)。
-
Worker Node(工作节点):集群上运行应用程序代码的任意一个节点。
-
Executor(执行器):在集群工作节点上为某个应用启动的工作进程,该进程负责运行计算任务,并为应用程序存储数据。
-
Task(任务):执行器的工作单元。
-
Job(作业):一个并行计算作业,由一组任务(Task)组成,并由Spark的行动(Action)算子(如:save、collect)触发启动。
-
Stage(阶段):每个Job可以划分为更小的Task集合,每组任务被称为Stage。
Spark目前支持几个集群管理器:
-
Standalone :Spark 附带的简单集群管理器,可以轻松设置集群。
-
Apache Mesos:通用集群管理器,也可以运行 Hadoop MapReduce 和服务应用程序。(已弃用)
-
Hadoop YARN: Hadoop 2 和 3 中的资源管理器。
-
Kubernetes:用于自动部署、扩展和管理容器化应用程序的开源系统。
SparkCore
RDD(Resilient Distributed Dataset):弹性分布式数据集,是一个容错的、并行的数据结构
RDD算子:对任何函数进行某一项操作都可以认为是一个算子,RDD算子是RDD的成员函数
Transform(转换)算子: 根据已有RDD创建新的RDD
Action(动作)算子: 将在数据集上运行计算后的数值返回到驱动程序,从而触发真正的计算
DAG(Directed Acyclic Graph): 有向无环图,Spark中的RDD通过一系列的转换算子操作和行动算子操作形成了一个DAG
DAGScheduler:将作业的DAG划分成不同的Stage,每个Stage都是TaskSet任务集合,并以TaskSet为单位提交给TaskScheduler。
TaskScheduler:通过TaskSetManager管理Task,并通过集群中的资源管理器(Standalone模式下是Master,Yarn模式下是ResourceManager)把Task发给集群中Worker的Executor
Shuffle:Spark中数据重分发的一种机制。
SparkSQL
DataFrame: 是一种以RDD为基础的分布式数据集, 被称为SchemaRDD
Catalyst:SparkSQL核心模块,主要是对执行过程中的执行计划进行处理和优化
DataSource:SparkSQL支持通过 DataFrame 接口对各种数据源进行操作。
Adaptive Query Execution:自适应查询执行
Runtime Filter:运行时过滤
Codegen:生成程序代码的技术或系统,可以在运行时环境中独立于生成器系统使用
SparkSql执行过程:
-
Unresolved Logical Plan:未解析的逻辑计划,仅仅是数据结构,不包含任何数据信息。
-
Logical Plan:解析后的逻辑计划,节点中绑定了各种优化信息。
-
Optimized Logical Plan:优化后的逻辑计划
-
Physical Plans:物理计划列表
-
Selected Physical Plan 从列表中按照一定的策略选取最优的物理计划
业界挑战与实践
向量化(vectorization):将循环转换为向量操作的编译器优化
代码生成(Codegen:Code generation):生成程序代码的技术或系统,可以在运行时环境中独立于生成器系统使用
大数据 Shuffle 原理与实践
https://bytedance.feishu.cn/file/boxcnQaV9uaxTp4xF0d1vEK5W3c
https://live.juejin.cn/4354/yc_Shuffle
shuffle概述
https://www.cnblogs.com/lintong-zf/p/14231356.html
所谓shuffle就是指把数据打乱重新组合。指数据从map task输出到reduce task输入的这段过程。
Mapreduce
- map阶段:在单机上进行的针对一小块数据的计算
- shuffle阶段:在map阶段的基础上,进行数据移动
- reduce阶段:对移动后的数据进行处理,依然是在单机上处理一小份数据
为什么shuffle如此重要
- 数据shuffle表示了不同分区数据交换的过程,不同的shuffle策略性能差异较大。目前在各个引擎中shuffle都是优化的重点,在spark框架中,shuffle是支撑spark进行大规模复杂数据处理的基石。
shuffle算子
常见的触发shuffle的算子
-
repartition
- coalesce、repartition
重分区一般会shuffle,因为需要在整个集群中,对之前所有的分区的数据进行随机,均匀的打乱,然后把数据放入下游新的指定数量的分区内。
-
ByKey
- groupByKey、reduceByKey、aggregateByKey、combineByKey、sortByKeysortBy
byKey类的操作要对一个key,进行聚合操作,那么肯定要保证集群中,所有节点上的相同的key,移动到同一个节点上进行处理。
-
Join
- cogroup、join
两个rdd进行join,就必须将相同join key的数据,shuffle到同一个节点上,然后进行相同key的两个rdd数据的笛卡尔乘积。
shuffle过程
HashShuffle
- 优点:不需要排序
- 缺点:打开,创建的文件过多
SortShuffle
- 优点:打开的文件少、支持map-side combine
- 缺点:需要排序
TungstenSortShuffle
- 优点:更快的排序效率,更高的内存利用效率
- 缺点:不支持map-side combine