这是我参加「第四届青训营 」笔记创作活动的第2天
流/批/OLAP一体的Flink计算引擎介绍
一. Flink概述
1.1 Apache Flink的诞生背景
大数据(Big Data):指无法在一定时间内用常规软件工具对其进行获取、存储、管理和处理的数据集合。
- 海量化
- 多样化
- 快速化
- 价值化
大数据计算架构的发展历史:
- 史前阶段~2006
- 传统数仓
- Oracle
- 单机
- 黑箱使用
- Hadoop
- 分布式
- Map-Reduce
- 离线计算
- Spark
- 批处理
- 流处理
- SQL高阶API
- 内存迭代计算
- Flink
- 流计算
- 实时、更快
- 流批一体
- Streaming/Batch SQL
1.2 Flink为什么脱颖而出
流式计算框架对比:
二. Flink整体框架
2.1 Flink分层框架
- SDK层:Flink的三类SDK,SQL/Table、DataStream(Java)、pyFlink(Python);
- 执行引擎层(Runtime层):提供了统一的DAG,用来描述数据处理的pipeline ,不管是流还是批,都会转化为DAG图 ,调度层(Scheduler) 再把DAG转化成分布式环境下的Task,Task之间通过 Shuffle 传输数据;
- 状态存储层:负责存储算子的状态信息;
- 资源调度层:目前Flink支持部署多种环境(Yarn,K8s)
2.2 Flink总体架构
一个Flink集群,主要包含以下两个核心部件:
- JobManager(JM):负责整个任务的协调工作
- 调度task
- 出发协调task做Checkpoint
- 协调容错恢复等
- TaskManager(TM):负责执行一个DataFlow Graph的各个task以及data streams的buffer和数据交换
2.2.1 JobManager职责
- Dispatcher:接受作业,拉起JobManager来执行作业,并在JobMaster挂掉后恢复作业
- JobMaster:管理一个job的整个生命周期,会向ResourceManager申请slot,并将task调度到对应的TM上
- ResourceManager:负责slot资源的管理和调度,TaskManager拉起会后向RM注册
2.3 Flink作业示例(WordCount)
从Kafka中读取一个实时数据流,每10s统计一次单词出现次数,DataStream实现代码如下:
- 业务逻辑转换为一个Streaming DataFlow Graph(即DAG,有向无环图)
- 假设sink算子的并发为1,其余算子并发为2,上面的Streaming DataFlow Graph转为Parallel DataFlow(内部叫Execution Graph)
- Flink会进行operation chain,将一些算子链接形成一个一个Task,这样每个Task可以在一个线程里执行,减少切换线程的工序。
- 如上图中Source1对map1直接进行数据传输,one2one,这样可以将他们放在一起,变成顺序执行;
- 而map到下一步的window是不确定的,因为要通过keyBy()的哈希进行确定属于哪一个window
- 最后将上面的task调度到具体的TM中的slot中执行,一个slot只能运行同一个Task的subTask。
- slot是单独的threads执行,内存未严格隔离
- slot是单独的threads执行,内存未严格隔离
2.4 Flink如何做到流批一体化
2.4.1 为什么要流批一体化
流和批业务的特点:
批式计算相对于流式计算核心的区别:
若是不流批一体化,对于同一应用(如抖音)的不同业务场景(流业务,批业务)需要构建两套系统:
上述架构通点:
- 人力成本高:批、流两套系统,相同逻辑需要开发两遍;
- 数据链路冗余:本身计算内容一致,但两条链路,同样的逻辑要运算两遍,产生一定的资源浪费;
- 数据口径不一致:两套系统产生不同程度的误差;
2.4.2 Flink如何做到流批一体化
批计算是流计算的特例,Everything is Streams,有界数据(批式数据)也是一种(特殊的)数据流,一个无边界数据流可以按照时间(如1s)切段成一个个有边界的数据集。
这是Flink支持流批一体的基础,可以用一套引擎解决两种场景,对不同场景支持不同扩展性、实现不同优化策略。并且Flink在流批一体的基础上,从上面的API到底层的处理机制都是统一的,是真正意义上的流批一体。
Flink通过以下模块来做流批一体:
- SQL层
- DataStream API层统一,流和批都可以开发
- Scheduler层架构统一,支持流批场景
- Failover Recovery层架构统一,支持流批场景
- Shuffle Service层架构统一,流批场景选择不同shuffle service
2.4.3 流批一体的Scheduler层
主要负责将作业的DAG转化为在分布式环境中可执行的task
Flink1.12以前的版本中,支持以下两种调度方式:
-
EAGER模式:申请一个作业所需要的全部资源,然后同时调度这个作业的全部Task,所有Task之间采取pipeline进行通信 (Stream作业场景)
- 需要所有task所需的资源全部调度才能进行
-
LAZY模式:先调度上游,等待上游产生数据或结束后再调度下游,类似Spark的Stage (Batch作业场景)
- 最小调度一个task即可,集群拥有1个slot就能运行
由Pipeline的数据交换方式连接的Task构成为一个 Pipeline Region ,本质上流批作业都按照 pipeline region粒度 来申请资源和调度任务
-
ALL_ENDGES_BLOCKING:(批处理)所有Task之间的数据交换都是BLOCKING模式,数据非实时传输,需要落盘(写到disk或数据库里) (12个Pipeline Region)
-
ALL_EDGES_PIPELINED:(流处理)所有Task都是pipeline模式,数据产出全部直接发给下游,不做落盘(直接传输) (1个Pipeline Region)
2.4.4 流批一体的Shuffle Service层
-
shuffle:在分布式计算中,用来连接上下游数据交互的过程。 实际上,分布式计算中所有涉及到上下游衔接的过程,都可以理解为shuffle。
-
shuffle的不同实现:
- 基于文件的Pull Based Shuffle
- 有较高的容错性和稳定性,适合大规模的批处理作业
- 基于Pipeline的Push Based Shuffle
- 低延迟和高性能,但是shuffle数据没有保存下来,如果是batch任务的话,就需要进行重跑恢复
- 基于文件的Pull Based Shuffle
-
流和批shuffle之间的差异:
- 数据的生命周期:流shuffle数据与task绑定,批shuffle数据与task解耦
- 据存储介质:流生命周期短,为实时性经常存储在内存;批数据量大容错高,存储磁盘
- 部署方式:流服务计算节点部署在一起,节省网络开销,减少latency;批作业不同
-
Flink对流和批提供 streaming 和 batch 两种类型的shuffle
-
在streaming/OLAP场景:为了性能,通常使用基于Pipeline的Shuffle模式
-
在batch场景:Blocking的shuffle模式
为了统一在这两种模式下的shuffle架构,Flink实现了一个Pluggable的Shuffle Service框架,抽象出一些公共模块
-
-
Shuffle Service
- Netty shuffle service:既支持pipeline也支持blocking,Flink默认的Shuffle Service策略
- Remote shuffle service:既支持pipeline也支持blocking,不过pipeline会性能下降,主要用在batch的blocking场景
三. Flink架构优化
3.1 流/批/OLAP业务场景对比
3.2 为什么三种业务场景可以用一套引擎解决
批是流的特例,OLAP是批的特例,对并发和实时性要求更高,其他情况与批没有区别
3.3 Flink如何支持OLAP
-
Flink做OLAP的优势
- 引擎统一:降低学习成本提高开发与维护效率
- 既有优势:内存计算、code-gen、pipeline shuffle、session
- 生态支持:跨数据源查询支持、TCP-DS基准测试性能强
-
OLAP场景的挑战
- 秒级、毫秒级小作业:并行性高
- 作业频繁启停,资源碎片:磁盘开销
- Latency+QPS要求
-
OLAP架构现状
- Client:提交SQL Query;
- Gateway:接受Client提交的SQL Query,对SQL进行语法解析和查询优化,生成Flink作业执行计划,提交给Session集群;
- Session Cluster:执行作业调度及计算并返回结果
-
Flink在OLAP架构的问题和设想
- 功能与架构模块:
- JobManager与ResourceManager在一个进程内启动,无法对JobManager进行扩展
- Gateway与Flink Session Cluster相互独立,无法统一进行管理 (SQL解析优化管理)
- 作业管理与部署模块:
- JobManager处理调度作业时负责功能多,但作业处理时间长,占用过多内存;(高并发占用过多)
- TaskManager部署计算任务时,初始化部分耗时严重,消耗大量CPU;
- 资源管理及计算任务调度:
- 资源申请/释放流程链路长
- slot作为资源管理单位,JM管理slot导致JM无法感知TM的资源分布,使得资源管理完全依赖于ResourceManager
- 其他:
- 作业心跳/failover机制不适合AP的秒级毫秒级计算
- AP使用Batch算子计算,初始化比较耗时
- 功能与架构模块: