赞
踩
Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。并且 Flink 提供了数据分布、容错机制以及资源管理等核心功能。Flink提供了诸多高抽象层的API以便用户编写分布式任务:
DataSet API, 对静态数据进行批处理操作,将静态数据抽象成分布式的数据集,用户可以方便地使用Flink提供的各种操作符对分布式数据集进行处理,支持Java、Scala和Python。
DataStream API,对数据流进行流处理操作,将流式的数据抽象成分布式的数据流,用户可以方便地对分布式数据流进行各种操作,支持Java和Scala。
Table API,对结构化数据进行查询操作,将结构化数据抽象成关系表,并通过类SQL的DSL对关系表进行各种查询操作,支持Java和Scala。
此外,Flink 还针对特定的应用领域提供了领域库,例如: Flink ML,Flink 的机器学习库,提供了机器学习Pipelines API并实现了多种机器学习算法。 Gelly,Flink 的图计算库,提供了图计算的相关API及多种图计算算法实现。
这个问题是一个非常宏观的问题,因为两个框架的不同点非常之多。但是在面试时有非常重要的一点一定要回答出来:Flink 是标准的实时处理引擎,基于事件驱动。而 Spark Streaming 是微批(Micro-Batch)的模型。
下面我们就分几个方面介绍两个框架的主要区别:
Flink 基于 Chandy-Lamport 算法,会把分布式的每⼀个节点的状态保存到分布式⽂件系统⾥⾯作为 Checkpoint(检查点),过程⼤致如下。⾸先,从数据源端开始注⼊ Checkpoint Barrier,它是⼀种⽐较特殊的消息。
然后,它会跟普通的事件⼀样随着数据流去流动,当 Barrier 到达算⼦之后,这个算⼦会把它当前的本地状态进⾏快照保存,当 Barrier 流动到 Sink,所有的状态都保存完整了之后,它就形成⼀个全局的快照。
这样当作业失败之后,就可以通过远程⽂件系统⾥⾯保存的 Checkpoint 来进⾏回滚:先把 Source 回滚到 Checkpoint 记录的offset,然后把有状态节点当时的状态回滚到对应的时间点,进⾏重新计算。这样既可以不⽤从头开始计算,⼜能保证数据语义的⼀致性。
Flink程序在运行时主要有TaskManager,JobManager,Client三种角色。
Flink 的核⼼概念主要有四个:Event Streams、State、Time 和 Snapshots。
Flink的三种时间语义具体包括Event Time、Ingestion Time和Processing Time。
Flink在做计算的过程中经常需要存储中间状态,来避免数据丢失和状态恢复。选择的状态存储策略不同,会影响状态持久化如何和 checkpoint 交互。
Flink提供了三种状态存储方式:MemoryStateBackend、FsStateBackend、RocksDBStateBackend。
watermark是⼀种衡量Event Time进展的机制,它是数据本⾝的⼀个隐藏属性。通常基于Event Time的数据,⾃⾝都包含⼀个timestamp.watermark是⽤于处理乱序事件的,⽽正确的处理乱序事件,通常⽤watermark机制结合window来实现。
流处理从事件产⽣,到流经source,再到operator,中间是有⼀个过程和时间的。虽然⼤部分情况下,流到operator的数据都是按照事件产⽣的时间顺序来的,但是也不排除由于⽹络、背压等原因,导致乱序的产⽣(out-of-order或者说late element)。
但是对于late element,我们⼜不能⽆限期的等下去,必须要有个机制来保证⼀个特定的时间后,必须触发window去进⾏计算了。这个特别的机制,就是watermark。
全局快照⾸先是⼀个分布式应⽤,它有多个进程分布在多个服务器上;其次,它在应⽤内部有⾃⼰的处理逻辑和状态;第三,应⽤间是可以互相通信的;第四,在这种分布式的应⽤,有内部状态,硬件可以通信的情况下,某⼀时刻的全局状态,就叫做全局的快照。
那为什么需要全局快照呢,主要有以下两点:
Flink的容错机制的核心部分是制作分布式数据流和操作算子状态的一致性快照。 这些快照充当一致性checkpoint,系统可以在发生故障时回滚。 Flink用于制作这些快照的机制在“分布式数据流的轻量级异步快照”中进行了描述。 它受到分布式快照的标准Chandy-Lamport算法的启发,专门针对Flink的执行模型而定制。
barriers在数据流源处被注入并行数据流中。快照n的barriers被插入的位置(我们称之为Sn)是快照所包含的数据在数据源中最大位置。
例如,在Apache Kafka中,此位置将是分区中最后一条记录的偏移量。 将该位置Sn报告给checkpoint协调器(Flink的JobManager)。
然后barriers向下游流动。当一个中间操作算子从其所有输入流中收到快照n的barriers时,它会为快照n发出barriers进入其所有输出流中。
一旦sink操作算子(流式DAG的末端)从其所有输入流接收到barriers n,它就向checkpoint协调器确认快照n完成。
在所有sink确认快照后,意味快照着已完成。一旦完成快照n,job将永远不再向数据源请求Sn之前的记录,因为此时这些记录(及其后续记录)将已经通过整个数据流拓扑,也即是已经被处理结束。
CEP全称为Complex Event Processing,复杂事件处理。Flink CEP是在 Flink 中实现的复杂事件处理(CEP)库。CEP 允许在无休止的事件流中检测事件模式,让我们有机会掌握数据中重要的部分。一个或多个由简单事件构成的事件流通过一定的规则匹配,然后输出用户想得到的数据 —— 满足规则的复杂事件。
在流式处理中,CEP 当然是要支持 EventTime 的,那么相对应的也要支持数据的迟到现象,也就是watermark的处理逻辑。CEP对未匹配成功的事件序列的处理,和迟到数据是类似的。在 Flink CEP的处理逻辑中,状态没有满足的和迟到的数据,都会存储在一个Map数据结构中,也就是说,如果我们限定判断事件序列的时长为5分钟,那么内存中就会存储5分钟的数据,这在我看来,也是对内存的极大损伤之一。
Flink 是一种流式计算引擎,主要是来处理无界数据流的,数据源源不断、无穷无尽。想 要更加方便高效地处理无界流,一种方式就是将无限数据切割成有限的“数据块”进行处理,这 就是所谓的“窗口”(Window)。 在 Flink 中, 窗口就是用来处理无界流的核心。我们很容易把窗口想象成一个固定位置的 “框”,数据源源不断地流过来,到某个时间点窗口该关闭了,就停止收集数据、触发计算并输 出结果。例如,我们定义一个时间窗口,每 10 秒统计一次数据,那么就相当于把窗口放在那 里,从 0 秒开始收集数据;到 10 秒时,处理当前窗口内所有数据,输出一个结果,然后清空 窗口继续收集数据;到 20 秒时,再对窗口内所有数据进行计算处理,输出结果;依次类推。
Flink 支持两种划分窗口的方式,即时间方式和计数方式。如果根据时间划分窗口,那么它就是一个time-window 如果根据数据划分窗口,那么它就是一个count-window。flink支持窗口的两个重要属性(size和interval)如果size=interval,那么就会形成tumbling-window(无重叠数据) 如果size>interval,那么就会形成sliding-window(有重叠数据) 如果size< interval, 那么这种窗口将会丢失数据。比如每5秒钟,统计过去3秒的通过路口汽车的数据,将会漏掉2秒钟的数据。通过组合可以得出四种基本窗口:滚动窗口(Tumbling Window)、 滑动窗口(Sliding Window)、会话窗口(Session Window),以及全局窗口(Global Window)。
参考链接:Flink中的窗口
Flink的API可分为三层:
其中,SQL & Table API 同时适⽤于批处理和流处理,这意味着你可以对有界数据流和⽆界数据流以相同的语义进⾏查询,并产⽣相同的结果。除了基本查询外, 它还⽀持⾃定义的标量函数,聚合函数以及表值函数,可以满⾜多样化的查询需求。
DataStream & DataSet API 是 Flink 数据处理的核⼼ API,⽀持使⽤ Java 语⾔或 Scala 语⾔进⾏调⽤,提供了数据读取,数据转换和数据输出等⼀系列常⽤操作的封装。
Stateful Stream Processing 是最低级别的抽象,它通过 Process Function 函数内嵌到 DataStream API 中。下图是常见的一些Process。
在我们的Flink程序运行时,或许会发生各种各样的错误,导致程序中断,那我们在程序重启时需要找到一个状态并且从这个状态(可以称之为快照)进行恢复,使得程序可以从这个状态重新运行,该机制称之为Checkpoint。
我们的Flink程序很多时候都是7*24小时不间断的运行,需要不间断的过程中源源不断的产生快照(Global consistent snapshot,全局一致性快照)。
Checkpoint是由JobManager触发,假设我们现在需要产生Checkpoint Barrier N,此次Checkpoint一旦被触发,首先会在我们的数据源安插Checkpoint Barrier N,如上图所示,CheckPoint Barrier N前面的数据和事件(红色的圆圈部分)都由Checkpoint Barrier N负责,而N后面的数据和事件(色圆圈部分)则不属于Checkpoint Barrier N的管辖范围。
数据源收到Checkpoint Barrier N时,会先保存自己的状态(假如如果是kafka,那么就是kafka partition的offset),并填入全局一致性快照表格中,当Checkpoint Barrier N流经下游的算子时,算子会暂停数据处理,立即执行Checkpoint形成快照(执行完成以后恢复数据处理),当所有的算子及数据源快照形成完毕以后,我们则认为此次全局一致性快照制作成功,否则制作失败。
Flink状态维护指的就是我们维护一组状态值,比如我们需要统计1天的我们页面部分模块的点击PV和UV,当这些状态值非常大时并且开启checkpoint机制时,这些状态则会被持久化到存储中以便恢复,目前状态的存储后端主要有以下三种:MemoryStateBackend、FsStateBackend和RocksDBStateBackend。
Flink可以完全独⽴于Hadoop,在不依赖Hadoop组件下运⾏。但是做为⼤数据的基础设施,Hadoop体系是任何⼤数据框架都绕不过去的。Flink可以集成众多Hadooop 组件,例如Yarn、Hbase、HDFS等等。例如,Flink可以和Yarn集成做资源调度,也可以读写HDFS,或者利⽤HDFS做检查点。
TaskManager是一个jvm进程,,并会以独立的线程来执行一个task或多个subtask。为了控制一个 TaskManager 能接受多少个 task,Flink 提出了 Task Slot 的概念。
Flink 中的计算资源通过 Task Slot 来定义。每个 task slot 代表了 TaskManager 的一个固定大小的资源子集。例如,一个拥有3个slot的 TaskManager,会将其管理的内存平均分成三分分给各个 slot。将资源 slot 化意味着来自不同job的task不会为了内存而竞争,而是每个task都拥有一定数量的内存储备。需要注意的是,这里不会涉及到CPU的隔离,slot目前仅仅用来隔离task的内存。
通过调整 task slot 的数量,用户可以定义task之间是如何相互隔离的。每个 TaskManager 有一个slot,也就意味着每个task运行在独立的 JVM 中。每个 TaskManager 有多个slot的话,也就是说多个task运行在同一个JVM中。而在同一个JVM进程中的task,可以共享TCP连接(基于多路复用)和心跳消息,可以减少数据的网络传输。也能共享一些数据结构,一定程度上减少了每个task的消耗。
简单的说,TaskManager会将⾃⼰节点上管理的资源分为不同的Slot:固定⼤⼩的资源⼦集。这样就避免了不同Job的Task互相竞争内存资源,但是需要主要的是,Slot只会做内存的隔离。没有做CPU的隔离。
Flink的重启策略主要有几下四种:
默认重启策略是通过Flink的配置文件设置的flink-conf.yaml。定义策略的配置key为: restart-strategy。如果未启用检查点,则使用“无重启”策略。如果激活了检查点但未配置重启策略,则使用“固定延迟策略”:restart-strategy.fixed-delay.attempts: Integer.MAX_VALUE尝试重启。
使用群集定义的重新启动策略。这对于启用检查点的流式传输程序很有帮助。默认情况下,如果没有定义其他重启策略,则选择固定延迟重启策略。
参考链接:Flink内存模型
简单来说数据倾斜就是数据的key 的分化严重不均,造成一部分数据很多,一部分数据很少的局面。数据倾斜表现为以下几种场景:
如果keyBy之前就存在数据倾斜,上游算⼦的某些实例可能处理的数据较多,某些实例可能处理的数据较少,产⽣该情况可能是因为数据源的数据本⾝就不均匀,例如由于某些原因Kafka的topic中某些partition的数据量较⼤,某些partition的数据量较少。对于不存在keyBy的Flink任务也会出现该情况。
这种情况,需要让Flink任务强制进⾏shuffle。使⽤shuffle、rebalance、rescale算⼦即可将数据均匀分配,从⽽解决数据倾斜的问题。
map端使⽤状态先预聚合,达到⼀定时间或者⼀定size后再同⼀输出(localkeyby)。
因为使⽤了窗⼝,变成了有界数据的处理,窗⼝默认是触发时才会输出⼀条结果发往下游,所以可以使⽤两阶段聚合的⽅式:
Flink-On-Yarn常见的提交模式有两种,分别是yarn-session和per-job模式。
在Flink的后台任务管理中,我们可以看到Flink的那个算⼦和task出现了反压。最主要的⼿段是资源调优和算⼦调优,即对作业中的Operator的并发数(parallelism)、CPU(core)、堆内存(heap_memory)等参数进行调优。作业参数调优包括:并行度的设置,State的设置,checkpoint的设置。
为了更⾼效地分布式执⾏,Flink会尽可能地将operator的subtask链接(chain)在⼀起形成task。每个task在⼀个线程中执⾏。将operators链接成task是⾮常有效的优化:它能减少线程之间的切换,减少消息的序列化/反序列化,减少数据在缓冲区的交换,减少了延迟的同时提⾼整体的吞吐量。这就是我们所说的算⼦链。其实就是尽量把操作逻辑放⼊到同⼀个subtask⾥⾯也就是⼀个槽TaskSolt。
使⽤⼤容量的 Kafka 把数据先放到消息队列⾥⾯作为数据源,再使⽤Flink 进⾏消费,不过这样会影响到⼀点实时性。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。