Flink基础理论:四大核心原理

Flink的基础理论四大核心原理

|0x00 窗口(Window)

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

|0x01 时间(Time)

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

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

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

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

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

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

|0x02 状态(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)。如下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

|0xFF 检查点(Checkpoint)

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

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

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

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

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

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

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

相关文章

Flink-core小总结1.实时计算和离线计算1.1离线计算离线计算的...
2022年7月26日,Taier1.2版本正式发布!本次版本发布更新功能...
关于Flink相关的概念性东西就不说了,网上都有,官网也很详尽...
最近准备用flink对之前项目进行重构,这是一个有挑战(但我很...
Thispostoriginallyappearedonthe ApacheFlinkblog.Itwasre...
Flink配置文件对于管理员来说,差不多经常调整的就只有conf下...