流/批/OLAP一体的Flink引擎 | 青训营笔记
这是我参与「第四届青训营 」笔记创作活动的第2天
一、Flink概述
1.1 Apache Flink 诞生的背景
随着大数据时代的到来,众多处理大数据的技术不断推出。而直到Hadoop框架的诞生,分布式计算成为大数据处理的主要手段。Hadoop的计算框架MapReduce作为初代计算引擎,它的最大价值在于提供一种分布式计算的核心思想,map和reduce,但随着业务中海量的无限流数据集越来越普遍,使用作为无限流数据流处理而设计的系统处理数据的场景就越多,MapReduce的局限性就体现出来了。所以Apache Flink诞生了。
Apache Flink是为分布式、高性能、随时可用以及准确的的处理流处理应用程序打造的开源流处理框架。
1.2 为什么 Apache Flink会脱颖而出
对比四种主流的计算引擎
-
MapReduce:批处理引擎,为其他计算引擎提供了大数据处理的核心思想,即map和reduce
-
storm:流式计算引擎,但是Storm API的low-level以及开发效率低下。一致性问题:storm更多考虑到实时流计算的处理延时而非数据的一致性保证。
-
Spark:集流式处理和批处理于一身的统一的计算引擎,基于内存计算,提高了性能。SparkStreaming作为Spark流式处理的一个组件,SparkStreaming相比于Storm的低阶API以及无法正确性语义保证,Spark是流处理的分水岭:第一个广泛使用的大规模流处理引擎,既提供较为高阶的API抽象,同时提供流式处理正确性保证。
-
Flink:集流式处理和批处理于一身的统一的计算引擎,吸收了以上3个框架的优点并改进后的计算框架,它还具备很多其他框架没有的技术特征:
- 完全一次保证:故障后应正确恢复有状态运算符中的状态;
- 低延迟:越低越好。许多应用程序需要亚秒级延迟;
- 高吞吐量:随着数据速率的增长,通过管道推动大量数据直关重要;
- 强大的计算模型:框架应该提供一种编程模型,该模型不限制用户并允许各种各样的应用程序在没有故障的情况下,容错机制的开销很低;
- 流量控制:来自慢速算子的反压应该由系统和数据源自然吸收,以避免因消费者缓慢而导致崩溃或降低性能;
- 乱序数据的支持:支持由于其他原因导致的数据乱序达到、延迟到达后,计算出正确的结果;
- 完备的流式语义:支持窗口等现代流式处理语义抽象。
二、Apache Flink的整体架构
2.1 Flink的分层架构
-
SDK层:Flink 的 SDK 目前主要由有三类
- SQL/Table:提供SQL语法对数据进行处理
- DataStream:实际中我们有很多业务无法直接使用SQL来完成,这就需要我们使用DataStream API 用Java编程实现需求
- Python:主要为pyFlink,和 Flink ML提供基础
-
执行引擎层(Runtime 层) :执行引擎层提供了统一的DAG,用来描述数据处理的 Pipeline,不管是流还是批,都会转化为DAG图,调度层再把DAG转换成分布式环境下的Task,Task之间通过Shuffle传输数据;
-
状态存储层:负责存储算子的状态信息;
-
资源调度层:目前Flink可以支持在多种环境(Standalone,yarn,K8S等)
2.2 Flink的总体架构
一个Flink集群,主要包含以下两个核心组件:
-
JobManager(JM) :负责整个任务的协调工作,包括:调度Task、触发协调Task做Checkpoint、协调容错恢复等。
JobManager的职责:
Dispatcher:接收作业,拉起JobManager来执行作业,并在JobMaster挂掉后恢复作业
JobMaster:管理一个job的整个生命周期,会向ResourceManager申请slot,并将task调度到对应Task Manager上
ResourceManager:负责slot资源的管理和调度,TaskManager拉起之后会向ResourceManager注册
-
TaskManager(TM) :负责执行一个DataFlow Graph 的各个task以及data streams 的 buffer 和 数据交换。
图片源于:Flink Architecture
2.3 Flink作业示例
流式的WordCount示例,从kafka中读取一个实时数据流,每10秒统计一次单词出现的次数,DataStream实现代码如下:
// Source
DataStream<String> lines = env.addSource(new FlinkKafkaConsumer<>(...));
DataStream<Event> events = lines.map((line)->parse(line));
// transformation
DataStream<Statistics> stats = events.keyBy(event -> event.id)
.timeWindow(Time.second(10))
.apply(new MyWindowAggregationFunction());
// sink
stats.addSink(new BucketingSink(path));
2.4 Flink如何做到流批一体
为什么需要流批一体?
一些业务场景,除了实时的数据统计需求,为了确认运营或产品的效果,用户同时还需要和历史数据做比较,比如,抖音一些直播数据的统计;
这种架构有一些痛点:
- 人力成本比较高:批、流两套系统,相同逻辑需要开发两遍;
- 数据链路冗余:本身计算内容是一致的,由于是两套链路,相同逻辑需要运行两遍,产生一定的资源浪费;
- 数据口径不一致:两套系统、两套算子、两套 UDF,通常会产生不同程度的误差,这些误差会给业务方带来非常大的困扰。
Flink如何做到流批一体
-
批式计算是流式计算的特例,有界数据集(批式数据)也是一种数据流、一种特殊的数据流。
-
站在 Flink 的角度,无边界数据集是一种数据流,一个无边界的数据流可以按时间切段成一个个有边界的数据集,所以有界数据集(批式数据)也是一种数据流。因此,不管是有边界的数据集(批式数据)还是无边界数据集,Flink 都可以天然地支持,这是 Flink 支持流批一体的基础。并且 Flink 在流批一体上,从上面的 API 到底层的处理机制都是统一的,是真正意义上的流批一体。
-
Flink主要从以下几个模块来做到流批一体:
- SQL层
- DataStream API层统一,批和流都可以使用DataStream API 开发
- Scheduler层架构统一,支持流批场景
- Failover Recovery 层 架构统一,支持流批场景
- Shuffle Service 层架构统一,流批场景选择不同的 Shuffle Service
流批一体的 Scheduler 层
-
Scheduler 主要负责将作业的 DAG 转化为在分布式环境中可以执行的 Task;
-
1.12 之前的 Flink 版本,Flink 支持两种调度模式:
- EAGER(Streaming 场景) :申请一个作业所需要的全部资源,然后同时调度这个作业的全部 Task,所有的 Task 之间采取 Pipeline 的方式进行通信;
- LAZY(Batch 场景) :先调度上游,等待上游产生数据或结束后再调度下游,类似 Spark 的 Stage 执行模式。
-
Pipeline Region Scheduler 机制:由Pipeline的数据交换方式连接的Task构成为一个Pipeline Region,本质上,不管是流作业还是批作业,都是按照Pipeline Region粒度来申请资源和调度任务。
流批一体的 Shuffle Service 层
- Shuffle:在分布式计算中,用来连接上下游数据交互的过程叫做 Shuffle。实际上,分布式计算中所有涉及到上下游衔接的过程,都可以理解为 Shuffle;
-
Shuffle分类:
- 基于文件的Pull Based Shuffle:数据落入磁盘
- 基于Pipeline的Push Based Shuffle:数据存在内存
-
流和批 Shuffle 之间的差异:
- Shuffle 数据的生命周期:流作业的 Shuffle 数据与 Task 是绑定的,而批作业的 Shuffle 数据与 Task 是解耦的
- Shuffle 数据存储介质:流作业的生命周期比较短、而且流作业为了实时性,Shuffle 通常存储在内存中,批作业因为数据量比较大以及容错的需求,一般会存储在磁盘里
- Shuffle 的部署方式:流作业 Shuffle 服务和计算节点部署在一起,可以减少网络开销,从而减少 latency,而批作业则不同
三、Flink 架构优化
-
Flink 做 OLAP 的优势
- 统一引擎:流处理、批处理、OLAP 统一使用 Flink 引擎
- 既有优势:利用 Flink 已有的很多特性,使 OLAP 使用场景更为广泛
- 相互增强:OLAP 能享有现有引擎的优势,同时也能增强引擎能力
-
Flink OLAP 场景的挑战
- 秒级和毫秒级的小作业
- 作业频繁启停、资源碎片
-
Flink OLAP 架构现状
- Client:提交 SQL Query;
- Gateway:接收 Client 提交的 SQL Query,对 SQL 进行语法解析和查询优化,生成 Flink 作业执行计划,提交给 Session 集群;
-
Session Cluster:执行作业调度及计算,并返回结果。
- JobManager 管理作业的执行,在接收到 Gateway 提交过来的作业逻辑执行计划后,将逻辑执行计划转换为物理执行计划,为每个物理计算任务分配资源,将每个计算任务分发给不同的 TaskManager 执行,同时管理作业以及每个计算任务执行状态;
- TaskManager执行具体的计算任务,采用线程模型,为每个计算任务创建计算线程,根据计算任务的上下游数据依赖关系跟上游计算任务建立/复用网络连接,向上游计算任务发送数据请求,并处理上游分发给它的数据。
四、个人总结与思考
Flink是集流处理、批处理、OLAP于一体的计算引擎,在至今的大数据处理领域占据重要的地。Flink
在流处理和批处理领域做的更好,那么作为Flink是否会彻底的取代Spark框架呢?Flink在未来会不会实现流处理和批处理无缝切换、界限越来越模糊呢?而现在Flink已经开始支持Python语言进行开发,那么未来会不会支持更多的语言进行开发呢?比如:C++、GO语言等。Flink也在逐步完善机器学习算法库,期待Flink向更成熟的机器学习、深度学习方向发展。
\