Flink引擎介绍|青训营笔记

101 阅读12分钟

一、Flink介绍

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

1.Apache Flink诞生背景

  1. 大数据:指无法再一定时间内用常规软件工具对其进行获取、存储、管理和处理的数据集合。价值化,海量化,快速化,多样化。
  2. 发展历史 image.png

3.大数据的实时性带来价值很大

  • 监控场景:实时发现业务系统的健康状态,提前避免业务故障
  • 金融风控:实时监测异常交易行为,及时阻断风险发生
  • 实时推荐:痘印根据用户行为发掘用户兴趣,偏好,向用户推荐更感兴趣的内容
  1. 架构模式的变化

批式计算:

  • 离线计算,非实时
  • 静态数据集
  • 小时/天等周期性计算

流式计算:

  • 实时计算,快速、低延迟
  • 无限流、动态、无边界
  • 7*24h持续运行
  • 流批一体

二、Flink整体架构

1.Flink分层架构

image.png

1.  SDK层:Flink的SDK目前主要有三类,SQL/Table,DataStream、pyFlink
2.  执行引擎层(Runtime层):执行引擎曾提供了统一的DAG,用来描述数据处理的Pipeline,不管是流还是批,都会转化为DAG图,调度层再把DAG转化成分布式环境下的Task,Task之间通过Shuffle传输数据
3.  状态存储层:负责存储算子的状态信息
4.  资源调度层:目前Flink可以支持部署在多种环境(yarn,K8S)

2.整体架构

  1. JobManager(JM):负责整个任务的协调工作,包括:调度task、出发协商Tasl做checkpoint、协调容错恢复等。 image.png
  • Dispatcher:接受作业,拉起JobManager来执行作业,并在JobMaster挂掉之后恢复作业。
  • JobMaster:管理一个job的整个生命周期,会向ResourceMangager申请资源slot,(向K8S/Yearn的API拉取一些资源,并将task调度到对应TM上
  • ResourceManager:负责slot资源的管理和调度,Task manager拉起之后会向RM注册
  1. TaskManager(TM):负责执行DAG的和恶化task以及data streams的buffer和数据交换。 cilent端将program code 代码区经过optimizer处理转化为DAG图,提交给JM,再转化为物理的执行图,JM根据物理执行图将任务调度到不同的woker节点执行。 image.png

3.作业实例

流式的WordCount示例,从kafka中读取一个实时数据流,每10s读取一个实时数据流,每10s统计一次单词出现次数。

DataStream实现代码如下:

image.png datafloat的API的使用

  • 第一步是Flink的环境变量,申请好,从kafka里读取一个数据,去addsource,从flinkkafkaconsumer读数据,拿取到了string格式数据。
  • 第二步,map是对每行line数据的解析处理,parse将空格拆开,拆为了event格式。
  • 第三步,keyby分发,timewindow设置了10s的窗口,聚合函数aggregationfunction,来一条数据后加1,统计频次。 最后,通过addsink,把数据写到了某个地方,也可以通过sdout将数据打印输出。

作业处理流程:

业务逻辑转换为Streaming DataFlow Graph image.png 在客户端收到code后,做一些简单的处理。

逻辑执行图到可以支持并发执行图 image.png 在分布式处理中会遇到并发度的,在前面抽象出来的作业,设置并发度。紧接着在JM中作处理,Execution Graph逻辑执行图。source等拆成两个算子,subtask,子task,source到map直接处理,没有keyby,和用户数据没有关系,幂等性,may到下一层需要keyby,需要做哈希,有可能发到1,也有可能发到2。sink只有一个并发,keyby1和2的数据处理完都会发到sink1 subtask上。

operator功能 image.png source 可以叫source也可以是operator,operater chain,上游source读完数据后,紧接着做map,parse操作,不需要有哈希shuffle的过程,可以把这两个task浸在一起,在物理执行上,source1和map1可以在一个线程上执行。如果没有chain,需要两个线程,要有线程之间的切换,减少数据的序列化和反序列化,chain会把他们当成一个算子task串行处理,如果结合Flink的本身实验机制,可以减少TM缓冲区的交换,减少延迟的同时,提高了整体的吞吐率。

什么样的算子可以浸在一起: flink任务划分阶段 - CSDN

一个数据流在算子之间传输数据的形式可以是一对一(one-to-one)的直通 (forwarding)模式,也可以是打乱的重分区(redistributing)模式,具体是哪一种形式,取决于算子的种类。

(1)一对一(One-to-one,forwarding)

       这种模式下,数据流维护着分区以及元素的顺序。source算子读取数据之后,可以直接发送给 map 算子做处理,它们之间不需要重新分区,也不需要调整数据的顺序。这就意味着 map 算子的子任务,看到的元素个数和顺序跟 source 算子的子任务产生的完全一样,保证着“一对一”的关系。

(2)重分区(Redistributing)

        在这种模式下,数据流的分区会发生改变。每一个算子的子任务,会根据数据传输的策略,把数据发送到不同的下游目标任务。例如,keyBy()是分组操作,本质上基于键(key)的哈希值(hashCode)进行了重分区;而当并行度改变时,比如从并行度为 2 的 window 算子,要传递到并行度为 1 的 Sink 算子,这时的数据传输方式是再平衡(rebalance),会把数据均匀地向下游子任务分发出去。

合并算子链:在 Flink 中,并行度相同的一对一(one to one)算子操作,可以直接链接在一起形成一个“大”的任务(task),这样原来的算子就成为了真正任务里的一部分。这样的技术被称为合并算子链。

有了前面operator chain功能后,整体的物理执行图。 image.png

将物理执行图调度到TM上,去真正的执行起来。 image.png 最后JM去resource manager 申请一些资源,TM里面有三个slot(用户自己定义),每个slot在TM里是一个单独的线程在执行,将task放到slot上执行,cpu没有严格的隔离,内存有一些隔离。TM可以理解为一个进程在执行。

4.Flink如何做到流批一体

为什么需要流批一体?

抖音播放量,点赞量,实时观看人数,评论量,广告收入,典型的批处理场景。

image.png

行为日志,买点数据都在数据源,原始数据导入kafka,flink再去做基于kafka的数据清洗,再导入服务层,再通过服务层向抖音业务上真正数据的展示。 离线数仓,导入kafka后再落入hive,经过一些hive处理后再导入服务层。

痛点:

  1. 人力成本比较高:批、流两套系统,相同逻辑需要开发两遍;
  2. 数据链路冗余︰本身计算内容是一致的,由于是两套链路,相同逻辑需要运行两遍,产生一定的资源浪费;
  3. 数据口径不一致: 两套系统、两套算子、两套UDF,通常会产生不同程度的误差,这些误差会给业务方带来非常大的困扰。

流和批业务场景的特点:

流式计算批示计算
实时计算离线计算
延迟在秒级以内处理时间为分钟到小时级别,甚至天级别
0~1s10S~1h+
广告推荐、金融风控搜索引擎构建索引、批示数据分析

批式计算相比于流式计算核心的区别:

维度流式计算批式计算
数据流无限数据集有限数据集
时延低延迟、业务会感知运行中的情况实时性要求不高,只关注最终结果产出时间

为什么能做到流批一体?

批式计算是流式计算的特例,Flink认为有界数据集(批式数据)也是一种数据流。理论上可以用一套引擎架构来解决上述两种场景,只不过需要对不同场景支持相应的扩展性,并允许做不同的优化策略。

Flink流式引擎 image.png 批式计算是一种特殊的流式计算,可以做一些更加灵活的调度策略,流和批可以走不同的shuffle service。

Apache Flink主要从以下几个模块来做流批一体:

  1. SQL层;Flink支持有边界无边界的数据集处理。
  2. DataStream API层统一,批和流都可以使用DataStream API来开发。特殊的state用sql难表达,可以用java或scala。
  3. Scheduler层架构同一,支持流批场景。
  4. failover Recovery层架构统一,容错部分支持流批场景。
  5. Shuffle Service层架构统一,流批场景选择不同的Shuffle Service.

Scheduler层: Scheduler主要负责将作业DAG逻辑执行图转化为物理执行图做相应的调度,分布式环境中可以执行的TASK.

image.png

在1.12之前的Flink版本中,Flink支持以下两种调度模式: image.png

EAGER模式:

image.png

AB两个并发,CD四个并发,不做all to all,b1直接平均分到c1,c2,会有聚合keyby的操作或者groupby的操作,哈希shuffle分发到d1,d2,d3,d4。12个task一起调度,集群需要有足够的资源。

LAZY模式:

只要有一个task能调度资源可以运行起来了。

最新的调度机制: image.png LAZY,资源最少,性能最差。Eager性能最好,需要的资源也最多。 Pipeline region兼容。由Pipeline的数据交换方式连接的Task狗成为一个Pipeline Region。所有的TASK之间的交换都是pipeline,没有blocking模式,都是有限数据集,没有无线数据集,就可以Pipeline Region。 本质上,不管是留作业还是批作业,都是按照Pipeline Region粒度来申请资源和调度任务。

image.png 第一种是传统的批处理,blocking是a产生的数据需要写到磁盘,b1可以从磁盘去读数据,不是实时传输的,需要落盘,a1使用完释放资源。blocking需要切换不同的pipleline region。 第二种是流的调度模式,a1产生的数据直接发给内存,内存发给b1,资源就释放了,中间不做落盘,是一个pipeline region。

Shuffle Service层: 把执行图调度起来后,TM之间的交互通过shuffle service交互。 image.png Shuffle:在分布式计算中,用来连接上下游数据交互的过程叫做shuffle。 对数据做keyby做相应的操作在放到window里面做聚合,就是shuffle。 分布式计算中所有涉及到上下游衔接的过程,都可以理解为shuffle。

针对不同的分布式计算框架,shuffle通常有几种不同的实现:

  1. 基于文件的Pull Based Shuffle,比如 Spark或MR,它的特点是具有较高的容错性,适合较大规模的批处理作业,由于是基于文件的,它的容错性和稳定性会更好一些;
  2. 基于Pipeline的Push Based Shuffle,比如 Flink、Storm、Presto等,它的特点是低延迟和高性能,但是因为shuffe 数据没有存储下来,如果是batch任务的话,就需要进行重跑恢复;

流和批shuffle之间的差异:

  1. Shuffle数据的生命周期:流作业的Shuffle数据与Task是绑定的,而批作业的Shuffle数据与Task是解耦的;
  2. Shuffle数据存储介质︰流作业的生命周期比较短、而且流作业为了实时性,Shuffile通常存储在内存中,批作业因为数据量比较大以及容错的需求,一般会存储在磁盘里;
  3. Shuffle的部署方式︰流作业 Shuffle服务和计算节点部署在一起,可以减少网络开销,从而减少latency,而批作业则不同。 流的task没了,他的shuffle也会没有。

Flink对于流和批提供两种类型的shuffle,虽然streaming和batch shuffle在具体的策略上存在一定的差异,但本质上都是为了对数据进行Re-Partition,因此不同的Shuffle之间是存在一定的共性的。 所以Flink的目标是提供一套统一的Shuffle架构,可以满足不同Shuffle在策略上的定制,同时还能避免在共性需求上进行重复开发。

流、批、olap三种业务场景的对比:

image.png

为什么三种业务场景为什么可以用一套引擎来解决:

  1. 批示计算是流式计算的特列,有界数据集(批示数据)也是一种数据流、一种特殊的数据流
  2. OLAP计算是一种特殊的批示计算,他对并发性和实时性要求更高,其他情况与普通批式作业没有特别大的区别。

因此,理论上可以用一套引擎架构来解决上述三种场景,只不过需要对不同场景支持相应的扩展性、并允许做不同的优化策略。

image.png OLAP 特性:短查询,极致的查询性能,秒,毫秒级 针对不同的场景开不同的优化策略。

OLAP场景需求:短查询作业场景

  • 高并发支持
  • 极致处理性能

三、Flink的OLAP的优化之路

Flink做OLAP的优势

  • 引擎统一:降低学习成本,提高开发效率,提高维护效率
  • 既有优势:内存计算,Code-gen,Pipeline Shuffle,Session模式的MPP架构
  • 生态支持:跨数据源查询支持,TCP-DS基准测试性能强

OLAP场景的挑战

  • 秒级和毫秒级的小作业
  • Latency+QPS的要求
  • 作业频繁启停,资源碎片

OLAP架构现状

  • Client:提交SQL Query;
  • Gateway:接收Client提交的SQL Query,对SQL进行语法解析和查询优化,生成Flink作业执行计划,提交给Session集群;
  • Session Cluster:执行作业调度及计算,并返回结果。