这是我参与「第四届青训营」笔记创作活动的第 3 天。
一、笔记内容
- Apache Flink 概述;
- 流批一体的 Apache Flink 架构;
- Apache Flink 的 OLAP 场景面临的问题及优化思路;
- Flink 使用案例;
二、Apache Flink 概述
1. Apache Flink 诞生背景
- 大数据
大数据计算架构发展史
graph TD
史前阶段 --> Hadoop --> Spark --> Flink
-
流式计算
-
大数据的实时性带来的价值更大。其应用场景包括:监控场景、金融风控、实时推荐等。
-
大数据计算架构模式的转变:批式计算 --> 流式计算。
- 批式计算:离线计算(非实时), 静态数据集, 按小时/天等周期性计算;
- 流式计算: 实时计算(快速、低延迟),无限流、动态、无边界,持续运行,流批一体。
-
2.Apache Flink的优点
- 主要的流式计算引擎能力对比
- Flink官方介绍
Apache Flink 是一个基于无界和有界数据集之上的有状态计算的框架和分布式处理引擎。
- Apache Flink 开源生态
Apache Flink 在开源生态上的能力比较强大,可以支持:流批一体、OLAP、Gelly、Stateful Function、 Flink ML等。
三、Flink整体架构
1.Flink分层架构
- SDK层:主要有三类:SQL/Table、DataStream、Python;
- 执行引擎层(Runtime层) :提供统一的DAG,描述数据处理的Pipeline,不管是流还是批,都会转化为DAG图,调度层再把DAG转换成分布式环境下的Task,Task之间通过Shuffe传输数据。
- 状态存储层:负责存储算子的状态信息。
- 资源调度层:目前Flink可以支持部署在多种环境。
2.Flink总体架构
一个Flink集群,主要包含一下两个核心组件:
-
JobManager(JM):负责整个任务的协调工作,包括 调度task、触发协调 Task 做 Checkpoint、协调容错恢复等;
JobManager的职责:
- Dispatcher:接收作业,拉起 JobManager 执行作业,并在 JobMaster 挂掉之后恢复作业;
- JobMaster:管理一个 job 的整个生命周期,会向 ResourceManager 申请 slot ,并将 task 调度到对应TM上;
- ResourceManager:负责 slot 资源的管理和调度,Task manager 拉起之后会向 RM 注册。
-
TaskManager(TM):负责执行一个 DataFlowGraph 的 各个task 以及 data streams 的 buffer 和数据交换。
3.Flink作业示例
1. 流处理
-
Source:从Kafka中读取一个实时数据流。
-
transformation:
-
map():转换数据格式;
-
keyBy():按event的id统计;
-
timeWindow():每10s统计一次单词出现次数;
-
-
Sink:输出路径
2. 并行数据流处理
Flink 中的程序本质上是并行和分布式的。在执行过程中,一个流有一个或多个流分区,每个算子都有一个或多个算子子任务。算子子任务相互独立,在不同的线程中执行,可能在不同的机器或容器上执行。
-
一对一的流:
- 例如上图中的 Source 和 map()之间。保留了元素的分区和排序。
- 此时map() 的 subtask[1] 将与 Source 的 subtask[1] 生成相同的顺序来查看相同的元素。
-
重新分配流:
- 如上图的 map() 和 keyBy/window 之间,以及 keyBy/window 和 Sink 之间
- 此时会改变流的分区。每个算子子任务将数据发送到不同的目标子任务,这将取决于所选的转换。
- 在重新分配交换中,元素之间的顺序仅保留在每对发送和接收子任务中,例如,上面显示的 keyBy/window 和 Sink 运算符之间的重新分配,可能导致不同键的聚合结果到达 Sink 时顺序的不确定性。
3. Tasks and Operator Chains
为了更高效地分布式执行,Flink会尽可能地将不同的operator链接(chain)在一起形成Task。这样每个Task可以在一个线程中执行,内部叫做OperatorChain,如下图地source和map算子可以Chain在一起:
4. Task Slots and Resources
将上面的Task调度到具体地TaskManager中的slot中执行,一个slot只能运行同一个task的subTask。
4.Flink如何做到流批一体
1.为什么需要流批一体
实时数仓(Flink)和离线数仓(Spark/Hive)的分离架构,有一些痛点:
- 人力成本比较高:批、流两套系统,相同逻辑需要开发两遍;
- 数据链路冗余:本身计算内容是一致的,由于是两套链路,相同逻辑需要运行两边,产生一定的资源浪费。
- 数据口径不一致:两套系统、两套算子、两套UDF,通常会产生不同程度的误差,这些误差会给业务方带来非常大的困扰。
2.流批一体的挑战
流和批业务场景的特点如下表:
| 流式计算 | 批示计算 |
|---|---|
| 实时计算 | 离线计算 |
| 延迟在秒级以内 | 处理时间为分钟、小时,设置天级别 |
| 0 ~ 1s | 10s ~ 1h+ |
| 广告推荐、金融风控 | 搜索引擎构建索引、批式数据分析 |
批式计算相比于流式计算核心的区别如下表:
| 维度 | 流式计算 | 批示计算 |
|---|---|---|
| 数据流 | 无线数据集 | 有线数据集 |
| 时延 | 低延迟,业务可以感知运行中的情况 | 实时要求性不高,只关注最终结果的产出 |
3.Flink如何做到流批一体
1.为什么可以做到流批一体?
批式计算是流式计算的特例,Everythine is Streams,有界数据集(批式数据)也是一种数据流、一种特殊的数据流;因此,理论上我们可用一套引擎架构来解决上述两种场景,只不过需要对不同场景支持相应的扩展性、并允许做不同的优化策略。
2.流批一体的应用模块
Apache Flink主要从以下几个模块来做流批一体:
-
SQL层;
-
DataStream API层统一,批和流都可以使用DataStream API来开发;
-
Scheduler层架构同意,支持流批场景;
-
Failover Recovery层架构统一,支持流批场景;
-
Shuffe Service层架构统一,流批场景选择不同的Shuffe Service。
4.流批一体的Scheduler层
Scheduler主要负责将作业的DAG转化为在分布式环境中可执行的Task。
在1.12前的Flink版本中,Flink支持以下两种调度模式:
| 模式 | 特点 | 场景 |
|---|---|---|
| EAGER | 申请一个作用的全部资源,然后同时调度这个作业的全部Task,Task之间采取Pipeline的方式通信 | Stream作业场景 |
| LAZY | 先调度上游,等待上游产生数据或结束后再调度下游,类似Spark的Stage执行模式 | Batch作业场景 |
基于 Pipeline Region 的统一调度
-
为了既能发挥流引擎的优势,同时避免全图同时调度存在的一些短板,引入 Pipeline Region 的概念。
-
Unified DAG Scheduler 允许在一个 DAG 图中,Task 之间既可以通过 Pipeline 通讯,也可以通过 Blocking 方式进行通讯。这些由 Pipeline 的数据交换方式连接的 Task 被称为一个 Pipeline Region。
-
Flink 引入 Pipeline Region 的概念,不管是流作业还是批作业,都是按照 Pipeline Region 粒度来申请资源和调度任务。
5. 流批一体的Shuffle Service层
Shuffle:在分布式计算中,用来连接上下游数据交互的过程叫做Shuffle。实际上,分布式计算中所有涉及到上下游衔接的过程,都可以理解为Shuffle。
1.针对不同的分布式计算框架,Shuffle通常有几种不同的实现:
-
基于文件的 Pull Based Shuffle,比如 Spark 或 MR,它的特点是具有较高的容错性,适合较大规模的批处理作业,由于是基于文件的,它的容错性和稳定性会更好一些;
-
基于 Pipeline 的 Push Based Shuffle,比如 Flink、Storm、Presto 等,它的特点是低延迟和高性能,但是因为 shuffle 数据没有存储下来,如果是 batch 任务的话,就需要进行重跑恢复;
2.流和批 Shuffle 之间的差异:
- Shuffle 数据的生命周期:流作业的 Shuffle 数据与 Task 是绑定的,而批作业的 Shuffle 数据与 Task 是解耦的;
- Shuffle 数据存储介质:流作业的生命周期比较短、而且流作业为了实时性,Shuffle 通常存储在内存中,批作业因为数据量比较大以及容错的需求,一般会存储在磁盘里;
- Shuffle 的部署方式:流作业 Shuffle 服务和计算节点部署在一起,可以减少网络开销,从而减少 latency,而批作业则不同。
Flink对于流和批提供两种类型的Shuffle,虽然Streaming和Batch Shuffle在具体的策略上存在一定的差异,但本质上都是为了对数据进行Re-Partition,因此不同的Shuffle之间是存在一定的共性的。
所以Flink的目标是提供一套统一的Shuffle架构,既可以满足不同Shuffle在策略上的定制,同时还能避免在共性需求上进行重复开发。
3.不同场景下 Shuffle 的选择:
- 在Streaming和OLAP场景:为了性能的需要,通常会使用基于Pipeline的Shuffle模式。
- 在Batch场景:一般会选取Blocking的Shuffle模式。
为了统一Flink在Streaming和Batch模式下的Shuffle架构,Flink实现了一个Pluggable的Shuffle Service框架,抽象出一些公共模块。
4.对于Shuffle Service,Flink开源社区已经支持:
- Netty Shuffle Service:既支持pipeline又支持blocking,Flink默认的Shuffle Service策略;
- Remote Shuffle Service:既支持pipeline又支持blocking,不过对于pipeline模式,走remote反而会性能下降,主要是有用在batch的blocking场景,字节内部是基于CSS来实现RSS
5.Flink流批一体总结:
经过相应的改造和优化之后,Flink在架构设计上,针对DataStream层、调度层、Shuffle Service层,均完成了对流和批的支持,至此,业务已经可以非常方便地使用Flink解决流和批场景的问题了。
四、Flink 架构优化
1.流/批/OLAP 业务场景概述
1.三种业务场景的特点
2.三种业务场景面临的挑战
2.为什么三种场景可以用一套引擎来解决
经过流/批/OLAP 业务场景上的对比发现:
- 批式计算是流式计算的特例,Everything is Streams,有界数据集(批式数据)也是一种数据流、一种特殊的数据流;
- OLAP 计算是一种特殊的批式计算,它对并发和实时性要求更高,其他情况与普通批式作业没有特别大区别。
由上可知:只需要对不同场景支持相应的扩展性、并允许做不同的优化策略,就可以用一套引擎架构来解决流/批/OLAP三种场景。
Flink 需要解决一下问题,才可以更好的支持Batch和OLAP场景
| Batch场景需求(流批一体支持) | OLAP场景需求(短查询作业场景) |
|---|---|
| Unify DataStream APl | 高并发支持 |
| Scheduler | 极致处理性能 |
| Shuffle Service | - |
| Failover Recovery | - |
3.Flink 如何支持 OLAP 场景
1.Flink 做 OLAP 的优势
-
统一引擎:流处理、批处理、OLAP 统一使用 Flink 引擎;
- 降低学习成本,仅需要学习一个引擎;
- 提高开发效率,很多 SQL 是流批通用;
- 提高维护效率,可以更集中维护好一个引擎;
-
既有优势:利用 Flink 已有的很多特性,使 OLAP 使用场景更为广泛;
- 使用流处理的内存计算、Pipeline;
- 支持代码动态生成;
- 也可以支持批处理数据落盘能力;
-
相互增强:OLAP 能享有现有引擎的优势,同时也能增强引擎能力。
- 无统计信息场景的优化;
- 开发更高效的算子;
- 使 Flink 同时兼备流、批、OLAP 处理的能力,成为更通用的框架。
2.link OLAP 场景的挑战
- 秒级和毫秒级的小作业;
- 作业频繁启停、资源碎片;
- Latency + 高 APS 要求;
3.Flink OLAP 架构现状
- Client:提交 SQL Query;
- Gateway:接收 Client 提交的 SQL Query,对 SQL 进行语法解析和查询优化,生成 Flink 作业执行计划,提交给 Session 集群;
- Session Cluster:执行作业调度及计算,并返回结果。
4.Flink 在 OLAP 架构上的问题与设想
1.架构与功能模块问题:
- JobManager 与 ResourceManager 在一个进程内启动,无法对JobManager 进行水平扩展;
- Gateway 与 Flink Session Cluster 互相独立,无法进行统一管理;
2.作业管理及部署模块问题:
- JobManager 处理和调度作业时,负责的功能比较多,导致单作业处理时间长、并占用了过多的内存;
- TaskManager 部署计算任务时,任务初始化部分耗时验证,消耗大量 CPU;
3.源管理及计算任务调度问题:
- 资源申请及资源释放流程链路过长;
- Slot 作为资源管理单元,JM 管理 slot 资源,导致 JM 无法感知到 TM 维度的资源分布,使得资源管理完全依赖于 ResourceManager;
4.其他问题:
- 作业心跳与 Failover 机制,并不合适 AP 这种秒级或毫秒级计算场景;
- AP 目前使用 Batch 算子进行计算,这些算子初始化比较耗时;
5.设想: