Flink系列(1):Flink的基础理论

目录

Flink的介绍

Flink的优点

Flink与Spark有何区别

Flink的前置学习之一:抽象层级

Flink的前置学习之二:数据流的运行过程

Flink的前置学习之三:如何并行处理数据

Flink的四大核心原理之一:窗口(Window)

Flink的四大核心原理之二:时间(Time)

Flink的四大核心原理之三:状态(State)

Flink的四大核心原理之四:检查点(Checkpoint)

Flink如何进行批量数据的流处理

Flink系统架构介绍之一:任务及操作链(Tasks and Operator Chains)

Flink系统架构介绍之二:分布式进程(Job Managers, Task Managers, Clients)

Flink系统架构介绍之三:线程槽位与资源(Task Slots and Resources)

Flink系统架构介绍之四:后端状态(State Backends)


Flink的介绍:

官方介绍:持续数据流下的有状态计算框架。

官网链接:https://flink.apache.org/

中文文档:http://flink.iteblog.com/

说明:Flink很多术语,单纯的用汉语解释,会产生一定的误解。例如Stream的翻译为流,作为英文,其表示名词,作为汉语翻译,却只能表示为动词。为了避免歧义,笔者在文章中尽量通过括号的形式,来表明术语的名词含义,例如:流(Steam),即表明这是一个Flink术语,是名词。

 

Flink的优点:

1.丰富的流式处理用例:事件驱动型应用程序;支持流式/批量处理;支持数据通道及ETL。

2.正确性有保障:严格执行一次机制;基于事件时间的处理;复杂情况下的延迟数据处理。

3.分层API机制:流式计算SQL与批量处理数据共存;数据流API与数据集API共存;基于时间和状态的过程控制;

4.聚焦可操作性:灵活部署能力;高可用性设置;保存点功能。

5.用例可扩展性:横向扩展架构;支持海量数据处理;增量式检查点。

6.出众的性能:低延迟;高吞吐量;内存计算。

 

Flink与Spark有何区别:

Spark和Flink都希望能够将流处理和批处理统一起来处理,但两者的实现方式却各不相同。Spark是以批处理的技术为根本,并尝试在批处理之上支持流计算;Flink则认为流计算技术是最基本的,在流计算的基础之上支持批处理。因为这种设计理念的差异,二者存在一些比较显著的差异。例如在低延迟场景中,由于Spark是基于批处理的方式进行流式计算,因而在运行的过程中存在一些额外的开销,如果遇到对延迟的要求非常苛刻的场景,例如百毫秒甚至十毫秒级别,Flink就存在显著的优势。对于用户来说,多一个选择永远是好的,不同的技术可能带来不同的优势,用户可以根据自己业务场景的需求进行选择。两者在部署上都支持Local模式、集群模式(Standalone集群或者Yarn集群)及云端部署模式。

 

Flink的前置学习之一:抽象层级

1.Flink框架的最底层是有状态的流式处理过程,类似于汇编在高级程序语言中的位置。将最基础的方法:包括流(Stream)、状态(State)及时间(Time)嵌入到API方法中,在保障一致性容错状态的前提下,通过事件时间及时间回调,方便的扩展和实现复杂的业务计算逻辑。

2.Flink框架的第二层是核心API层,是用户与Flink打交道的层级。核心API包括了DataStream和DataSet两部分API,分别对应了流式计算及批量计算方法集。这些API方法提供了用户数据处理的基础通用构件,包括了转换、联结、聚合等功能。

3.Flink框架的第三层是表API层,在流式处理过程中动态的更改表。表API遵循可扩展的关系模型,类似于关系型数据库,能够附加一些表结构,并且提供可操作的API,像Select、Join、Group by等。尽管表API可以由用户自行扩展函数,使用起来更加简洁,但它的表达性不如核心API。值得注意的是,用户可以自行在表API和核心API(DataStream/DataSet)之间做无缝转换,甚至是两者混用。

4. Flink框架的最高层级是SQL,在表达方式上与表API类似,但是提供对应的SQL查询表达式。

 

Flink的前置学习之二:数据流的运行过程

Flink程序的基本结构是由流(Stream)和转换(Transformation)组成的,从概念上讲,流(Stream)用于数据记录,而转换(Transformation)用于将一个或多个流作为输入或者作为结果输出。当程序被执行时,流和转换便映射到一个持续的计算数据流中,以Source作为流的起始,以Sink作为流的输出,整个过程类似于一个有向无环图:

 

Flink的前置学习之三:如何并行处理数据

Flink的设计思路天生就是并行和分布式的,在程序执行期间,一个流(Stream)有多个流分区(Steam Partitions),每个操作(Operator)都有多个子操作任务(Operator Subtask),每个子操作任务都是相互独立的、运行在独立的线程中、甚至是在不同的机器上。子操作任务的个数称之为并行度(Parallelism),同一个程序不同的操作(Operator)之间可以有不同的并行度(Parallelism):

两个不同的操作(Operator)之间,数据的传递有两种方式,分别是1对1模式(One-to-one)、重新分配模式(Redistributing)。数据的传递有两个基础的条件:分区数和排序,分区数可以打乱,但分区内的排序是不变的。

(一)1对1模式(One-to-one):流(Stream)之间按照相同的分区数和排序进行数据的传递,例如上图所示的例子中,Source中的分区数和排序,与map()中的完全相同。

(二)重新分配模式(Redistributing):流(Steam)根据转换(Transformation)的方式不同(例如根据Hash重新将Key分区、随机分区等),将数据发送到不同的子操作任务(Operator Subtask),也就是每个分区将重新进行分配和处理。但值得注意的是,虽然分区是重新分配的,但每个分区中的数据排序是保留的,虽然汇总后的整体顺序是不确定的。以上图为例,map()[1]中的数据发向keyBy()[2]后,数据排序保留,但汇总到Sink[1]后,整体的数据排序是不确定的。

 

Flink的四大核心原理之一:窗口(Window)

为什么窗口(Window)是Flink的核心原理呢?这就要提到一些在流式计算中常见的难题:聚合计算(例如Count、Sum),由于流式计算是一种近乎无限的运行状态,因而很难像批处理一样有明确的开始和结束节点。因此,Flink引入了窗口(Window)的概念,用于计算过去一定的时间节点内的聚合计算,例如“统计过去5分钟内的Count总和”、“计算过去100条数据的Sum综合”。窗口(Window)有两种计算方式:时间驱动(例如每30秒)和数据驱动(例如每100条数据)。如下图所示:

窗口(Window)有三种类型,分别为滚动窗口(Tumbling Windows)、滑动窗口(Sliding Windows)、会话窗口(Session Windows)。

(一)滚动窗口(Tumbling Windows):以时间为划分依据,每隔一定的时间便创建一个新的窗口,并统计该时间窗口内的数据,如下图所示:

(二)滑动窗口(Sliding Windows):

相对于滚动窗口,滑动窗口同样有控制窗口大小的参数,但新增了一个窗口新建频率的参数,假如窗口新建频率的时间比窗口大小的时间小的时候,会出现多个窗口重叠的情况,此时同一条数据会被分配到多个窗口中,如下图所示:

(三)会话窗口(Session Windows):

会话窗口没有固定的起止时间,通过Session的活跃度来进行窗口分组。会话窗口通过Session Gap来指定非活跃的周期时长,当时间超过这个时长时,Session被关闭,后续的数据会被分配到新的会话窗口,如下图所示:

 

Flink的四大核心原理之二:时间(Time)

时间(Time)是Flink中的核心原理,当程序中需要涉及到时间参数时(例如创建窗口),就可以指定对应的时间类型。Flink中时间有三种概念:事件时间(Event Time)、摄入时间(Ingestion Time)及处理时间(Processing Time)。

(一)事件时间(Event Time):事件时间指每个独立事件的发生时间,这些时间通常在数据进入Flink前就被记录。

(二)摄入时间(Ingestion Time):指事件进入Flink的时间,在Source中每个记录将当前时间作为时间戳,并且接下来基于时间的操作 (比如时间窗口),参考的就是这个时间戳。

(三)处理时间(Processing Time):指正在执行相关进程的机器的系统时间。当一个流式程序在处理时间运行时,所有基于时间的操作将会使用运行相关算子的机器的系统时间。

三种时间的差异如下图所示:

以下重点讲述Flink的水印(Watermark)机制:

由于事件的处理过程中存在延迟和无序,因而针对事件时间的处理通常会有一定的延迟,通常需要配合处理时间(Processing Time)一起进行操作。在Flink中,通常采用水印(Watermark)机制来测量事件时间的进度,即解决延迟数据的问题。通过时间戳t声明了流(Stream)中到达时间t时的事件时间,即带有时间戳的事件大于或等于Watermark。如下图所示:

Watermark对于乱序的数据来说比较重要,因为不清楚是否数据都到了。以App日志记录为例,假设A记录的时间是10:00,B记录的时间是10:05,但由于网络问题,B记录提前于A记录到达了日志系统,那么统计10:00 – 10:06之间的数据时,如何确定A、B记录都到了呢?这就需要Watermark了。Watermark(t)表示所有时间戳不大于t的数据都已经到来了,未来不会再来,因此可以放心的触发和销毁窗口了。如下图所示:

在并行处理任务时,每一个子任务(Subtask)都会生成自己的Watermark,在流式程序中流动时,它们会在到达算子时把事件时间提前,每当一个算子提前了它的事件时间,子任务(Subtask)就为它的继承算子生成了一个新的Watermark。如下图所示:

Watermark的产生方式有两种,周期性(Periodic)和递增式(Punctuated)。周期性(Periodic)是指每隔一段时间或每隔一定条数就生成一个Watermark,递增式(Punctuated)是指每次EventTime递增都会产生一个Watermark,但在数据量很大的情况下容易对下游计算单元产生较大的压力。

周期性(Periodic)代码如下图所示:

递增式(Punctuated)代码如下图所示:

Flink在与Kafka进行结合时,由于消费队列数据是并行的,会使得分区之间的事件时间(Event Time)产生交织甚至是重复,为了解决这个问题,建议使用Kafka-partition-aware方式生成Watermark,使得Watermark在Kakfa的Consumer中便进行生成,在Shuffle阶段中进行合并。代码及流程如下图所示:

 

Flink的四大核心原理之三:状态(State)

状态(State)是Flink能够进行复杂逻辑计算的基本组件,可以看做是算子的记忆能力。在流式计算中,很多操作(Operator)能够看作是一次独立的事件,但有些操作(Operator)能够记录多个事件间的信息,这些操作(Operator)被称作是有状态的(Stateful Operations)。简单讲,能够将过去处理完的输入的相关信息进行记录,并对后续输入的处理产生持续的影响。

有状态操作(Stateful Operations)的信息保存在嵌入式的键值对中,与对应的流(Stream)一起被严格的分区,因此只能访问keyBy()函数之后的Keyed Streams的键/值状态,并且仅限于与当前事件键相关联的值。在Flink中,状态分为两种,即Keyed State和Operator State。Operator State绑定到算子的每一个并行实例(Subtask) 中,而Keyed State总是和Key相关联,只能在Keyed Stream的函数或算子中使用。因为Flink中的keyBy()操作保证了每一个键相关联的所有消息都会送给下游算子的同一个并行实例处理,也可以看作是Operator State的一种分区形式,每一个键都关联一个状态分片(state-partition)。如下图所示:

 

Flink的四大核心原理之四:检查点(Checkpoint)

检查点(Checkpoint)是Flink实现容错性的核心保障,包括了流重放(Stream replay)和状态检查(Checkpointing)两种方式。Flink提供了一种失败容忍机制以持续的恢复数据流的状态,实现了一个轻量级的分布式快照机制,实现方式非常的轻量级并且不会对正在运行的任务性能产生太大影响。程序运行中即便遇到了崩溃的问题,Flink会重启当前数据流,并恢复到最新的已成功的检查点,因而程序的状态会恢复到数据流中的每条数据严格一致。这些快照信息被存储在指定的存储位置,例如HDFS上。

检查点(Checkpoint)的核心在于Stream Barriers,Flink会向数据流中写入对应的Barrier,成为数据流的一部分,与正常的数据流一同持续运行。Barrier永远不会追上记录,整个流程是严格线性的。在前进的过程中,Barrier会将当前运行的数据进行分离,写入当前的检查点,随后数据进入到下一个检查点,整个过程不打断当前的任务流,因此不同的Barrier能够同时存在,也就是同一时间会有不同的快照被记录。整个过程如下图所示:

那么如何判断一个检查点已经完成了?流(Stream)会从Source开始向下游的数据流注入对应的Barrier,位置就在检查点被注入的地方,这里称之为n,像Kafka等消息队列,Barrier被注入的位置就是最后一条数据所在的断点(Offset)。当下游的算子(Operator)收到所有输入流的n时,算子自身会提交一个Barrier,也命名为n,并随着输出流一些传递到下游。当最终的Sink收到这个n时,会认为检查点n已经完成了。

这里有一个并行的情况,当算子(Operator)有多个输入流时,Flink会阻断先到达的Barrier,并将消息放入到缓冲区中,等到所有的数据流都到达后,再进行快照操作,并向下游发送Barrier。但是,对齐操作会对流处理造成延时,尽管通常只有几毫秒的时间。但当业务情况比较特殊时,也可以选择跳过对齐操作,此时快照n中会包含一些属于n+1的数据,Exactly Once特性就不能被保证,只能降级为At Least Once。

最终的快照包括两个部分:

(一)对于每个并行的数据源,保存快照在整个流中的起始位置;

(二)对于每个算子(Operator),保存一个指向状态存储地址的指针。

检查点机制的完整流程如下图所示:

 

Flink如何进行批量数据的流处理

Flink将批处理当做是流处理的一种特殊形式,即数据流是有限度的,处理的方法与流处理也基本相似,但存在一些区别:

(一)不再使用检查点机制:由于数据集是有限的,因此容错机制可以通过重跑全部数据的形式来实现。尽管这样做会显著增加容错的代价,但由于实现方式非常简单,避免了可能存在的潜在问题。

(二)有状态操作(Stateful Operations)被极大的简化,使用了简单的内存操作及非核心数据结构来实现,而不是key/value键值对的形式。

(三)引入了只有在批处理时才使用的同步迭代机制。

 

Flink系统架构介绍之一:任务及操作链(Tasks and Operator Chains)

Flink在分布式状态下,会将算子(Operator)的子任务(Subtask)链接作为任务(Task)。每个任务(Task)在单独的线程中运行,能够减少线程之间的切换、减少消息的序列化/反序列化、减少数据在缓冲区的交换、减少了延迟的同时提高整体的吞吐量。相关图示如下:

 

Flink系统架构介绍之二:分布式进程(Job Managers, Task Managers, Clients)

Flink分布式环境包括两大进程:

(一)JobManagers,又称为Masters,用于协调分布式执行机制,包括分布式环境下的任务、检查点、容错机制等。JobManager最少要有1个,高可用性场景下要求有多个。多个JobManager中只有一个是Leader,其余的是备用进程。

(二)TaskManagers,用于执行数据流中的具体任务(Task)和子任务(Subtask),TaskManager至少应该有1个。

当Flink集群启动后,首先会启动一个JobManger和多个的TaskManager。由Client提交任务给JobManager,JobManager再调度任务到各个TaskManager去执行,然后TaskManager将心跳和统计信息汇报给JobManager。

分布式进程图式如下:

 

Flink系统架构介绍之三:线程槽位与资源(Task Slots and Resources)

每一个TaskManager是一个JVM进程,能够执行一个或多个子任务(Subtask)的线程,这些线程由线程槽位(Task Slots)控制。在TaskManager下,每个Task Slot分配了固定的资源,主要是内存资源,不涉及CPU资源。假如TaskManager包括了三个Task Slot,每个Task Slot都将分配到1/3的内存资源。图示如下:

在默认情况下,Flink允许子任务(Subtask)共享单元内的资源给不同类型的任务,只要这些不同类型的任务都是在同一个Job下,这样做有两个好处:

(一)每个Flink的节点都可以尽可能多的运行job任务,不需要计算它们总共需要多少资源。

(二)能够最大化的利用系统资源,提升数据流计算的并行度,并且确保繁荣的子任务(Subtask)能够公平的分布在TaskManager中。

以上图为例,通过槽位共享机制,并行度能够从2提升到了6,如下图所示:

 

Flink系统架构介绍之四:后端状态(State Backends)

当我们启动了检查点机制时,流处理中的相关状态(State)信息将被后端持久化,具体后端以何种方式存储,将决定持久化的方式和位置。例如可以选择在内存中存储HashMap,也可以选择通过RocksDB的方式存储键值对。图示如下:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值