Flink知识点或面试题

Flink

1 简单介绍一下 Flink

Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。并且 Flink 提供了数据分布、容错机制以及资源管理等核心功能。Flink提供了诸多高抽象层的API以便用户编写分布式任务:

DataSet API 对静态数据进行批处理操作,将静态数据抽象成分布式的数据集,用户可以方便地使用Flink提供的各种操作符对分布式数据集进行处理,支持JavaScalaPython

DataStream API,对数据流进行流处理操作,将流式的数据抽象成分布式的数据流,用户可以方便地对分布式数据流进行各种操作,支持JavaScala

Table API,对结构化数据进行查询操作,将结构化数据抽象成关系表,并通过类SQLDSL对关系表进行各种查询操作,支持JavaScala

此外,Flink 还针对特定的应用领域提供了领域库,例如: Flink MLFlink 的机器学习库,提供了机器学习Pipelines API并实现了多种机器学习算法。 GellyFlink 的图计算库,提供了图计算的相关API及多种图计算算法实现。

注:

       flink是以事件驱动的,有状态的分布式流式计算引擎,具有容错机制,且能够处理乱序数据。在flink的世界观中一切数据都是流式数据,分为有界流和无界流,离线数据是有界流,实时数据是无界流。

       为什么需要流式处理引擎?

1. 传统的数据框架要么是处理的数据量有限,要么是实时性不好

       传统的数据架构是为了计算机计算方便,数据基于有限数据集,数据量是固定的,且处理过程中数据不会增长。缺点就是实时性和数据量不能兼得。

1.1传统数据处理架构:事务型处理,主要分为两层

    1)计算层:接收用户请求或接收外部的事件,比如CRM(客户资源管理系统),ERP(企业资源管理系统)、下单系统、页面APP,但是不管是什么系统,都会发生一条数据,作为一个事件进入处理系统,最后得到计算结果反馈给用户,在计算过程中,需要使用到外部数据,或者改动外部数据,这时就需要与关系型数据打交道。

    2)存储层:接收到请求,业务系统会查询数据库中的信息,拿到想要得到的信息结合用户的请求去做计算,得到的结果可能需要改动数据,并写入到数据库中。另外会包装成一个响应,反馈给用户。

    3)存在的问题:关系型数据库,存储的都是强业务的数据,对于用户普通的点击操作等数据一方面不方便存入数据库,另一方面数据量太大。

    4)优点:用户的响应可以实时得到。

1.2基于传统数据库的问题,做进一步分析处理--离线数仓:

    将业务数据或日志数据做ETL清洗,存储到数仓中,可以生产数据报表或者做即席查询,需要的是所有数据都确定。

    1)好处就是处理的数据量增大;

    2)缺点就是实时性差。

1.3 基于离线数仓的缺陷,诞生了SparkStreaming

SparkStreaming的架构思想还是基于离线数仓的思想,对于源源不断的流式数据,做微批次的处理,每一批次的数据是固定的。用批处理模拟流处理,有延迟,且无法处理乱序数据。

2. 流式处理框架的演变

2.1第一代,Storm

   不像微批次/离线数仓需要等到数据确定后才能计算,而是借鉴事务处理的架构,对于用户的请求及时反馈。而事务处理的问题就在于需要使用到外部数据,为了解决这个问题,不依赖外部数据,可以将使用到的数据直接存放在内存中。如果将数据存放在内存中,一方面响应用户的请求比事务处理更快,另一方面扩增数据规模只需要扩增机器的数量即可,完全不需要将数据存放在关系型数据库中,跟数据库没有任何关系。

对于源源不断的数据,经过计算逻辑后,每一个数据都有对应的输出,在做输出计算时可能需要使用外部数据,之前这些数据是存储在数据库中,但是现在不存放在数据库中,而是存放在本地内存中,叫做本地状态。这样就不需要与数据库打交道,而且计算速度更快。为了解决内存不稳定的缺陷,提高计算的容错性,出现错误能够恢复,需要定期对当前状态进行存盘。

总结:能够实现低延迟,但是缺点就是准确性得不到保障,且集群扩增困难,对于高吞吐的实现困难

2.2 流式处理的结果准确性如何保证?

    为了保证高吞吐,必须要使用分布式集群,当各个节点的数据需要进行Shuffle时,如何保证数据的时间顺序就是一个问题。经过了分布式处理的网络延迟,如何保证先进来的数据经过Shuffle后依然先进行处理,就是一个问题。因此,早期的流式处理架构无法保证结果的准确性。比如窗口大小为一天,而由于网络延迟可能进入窗口的数据是昨天的,或者是今天的数据没有进入窗口,而是进行下一天,都是无法保证数据的准确性。

2.3.Lambda架构(第二代):并行使用两套系统,同时实现时效性和准确性的需求。

    1)流处理架构(Speed Layer 快速层):保证数据的时效性,数据存储在流处理表;

    2)批处理架构(Batch Layer 批处理层):保证数据的准确性,进行校正数据,数据存储在批处理表。

    3)将流处理表与批处理进行合并得到最终的结果,呈现在应用程序中。

       整体流程:源源不断的数据到来后,每条数据封装成一个事件,先进入流处理层进行计算,结果存入流处理表中;同时数据也会进入批处理层中,等到一个批次的时间到后,就进行批次间的计算,并将结果存到批处理表中。如果想获取实时数据,就从流处理表中获取数据,但是数据可能不准。如果想看准确的数据,需要等到批处理层跑完结果,再与快速层的结果合并,得到最终准确的结果。

       缺点:使用两套系统,需要维护两套API,比如使用Spark实现批处理,另外使用流处理器,对于开发人员很痛苦,但是能够满足需求。

    1. 第三代Flink

1flink是以事件驱动的,有状态的分布式流式计算引擎,具有容错机制,且能够处理乱序数据。

2)在flink的世界观中一切数据都是流式数据,分为有界流和无界流,离线数据是有界流,实时数据是无界流。

       3)分层API:第一层:SQLTableAPI;第二层:DataStream/DataSet;第三层:Process API,能够实现状态管理、获取运行时环境、制作定时器等。

2    FlinkSpark Streaming的区别

这个问题是一个非常宏观的问题,因为两个框架的不同点非常之多。但是在面试时有非常重要的一点一定要回答出来:Flink 是标准的实时处理引擎,基于事件驱动。而 Spark Streaming 是微批(Micro-Batch)的模型,基于时间驱动,伪实时。

下面我们就分几个方面介绍两个框架的主要区别:

1)架构模型Spark Streaming 在运行时的主要角色包括:MasterWorkerDriverExecutorFlink 在运行时主要包含:JobmanagerTaskmanagerSlot

2)任务调度Spark Streaming 连续不断的生成微小的数据批次,构建有向无环图DAGSpark Streaming 会依次创建 DStreamGraphJobGeneratorJobSchedulerFlink 根据用户提交的代码生成 StreamGraph,经过优化生成 JobGraph,然后提交给 JobManager进行处理,JobManager 会根据 JobGraph 生成 ExecutionGraphExecutionGraph Flink 调度最核心的数据结构,JobManager 根据 ExecutionGraph Job 进行调度。

3)时间机制Spark Streaming 支持的时间机制有限,只支持处理时间。 Flink 支持了流处理程序在时间上的三个定义:处理时间、事件时间、注入时间。同时也支持 watermark 机制来处理滞后数据。

4)容错机制对于 Spark Streaming 任务,我们可以设置 checkpoint,然后假如发生故障并重启,我们可以从上次 checkpoint 之处恢复,但是这个行为只能使得数据不丢失,可能会重复处理,不能做到恰好一次处理语义。Flink 则使用两阶段提交协议来解决这个问题。

5)流与批的世界观: SparkStreaming是将流式数据转换为批处理数据,因此实时性是秒级别的,对于实时性要求高的场景,spark就不适用了Flink是一切数据都是流数据,批处理的数据是特殊的有界流数据。

6)数据模型:Flink没有数据集的概念,底层的数据,就是数据流以及事件序列,事件驱动。SparkStreaming有数据集的概念DStream,底层是RDD弹性分布式数据集。

7)运行时架构:Spark是微批次计算,需要DAG划分stage,一个阶段结束才能进行下一个阶段,有延迟;Flink是流运行模式,一个数据过来后执行完数据就执行发往下一个节点计算,没有延迟。

8)子任务的管理Flink可以更细粒度的管理子任务(通过设置共享组(侧重资源共享)、设置任务链(侧重task)),而spark只能将多个窄依赖放入一个stage中。

9)窗口的区别: SparkStreaming的窗口是先有数据集rdd,再将多个RDD union在一起,形成窗口。并且sparkStreaming没有计数窗口。Flink是先有桶,之后窗口内的数据进入桶中,窗口是通过开始时间与结束时间确定。

10checkpoint的区别:spark streaming checkpoint 仅仅是针对 driver 的故障恢复做了数据和元数据的 checkpoint。而 flink checkpoint 机制 要复杂了很多,它采用的是轻量级的分布式快照,实现了每个算子的快照,及流动中的数据的快照。

3 Flink集群有哪些角色?各自有什么作用?

 

Flink 程序在运行时主要有 TaskManagerJobManagerClient三种角色。

JobManager扮演着集群中的管理者Master的角色,它是整个集群的协调者,负责接收Flink Job,协调检查点,Failover 故障恢复等,同时管理Flink集群中从节点TaskManager

TaskManager是实际负责执行计算的Worker,在其上执行Flink Job的一组Task,每个TaskManager负责管理其所在节点上的资源信息,如内存、磁盘、网络,在启动的时候将资源的状态向JobManager汇报。

ClientFlink程序提交的客户端,当用户提交一个Flink程序时,会首先创建一个Client,该Client首先会对用户提交的Flink程序进行预处理,并提交到Flink集群中处理,所以Client需要从用户提交的Flink程序配置中获取JobManager的地址,并建立到JobManager的连接,将Flink Job提交给JobManager

注:

1.JobManager扮演着集群中的管理者Master的角色,它是整个集群的协调者,主要作用是以下几个方面:

  1. 分发任务:负责接收Flink Job,将程序转化为执行图,并分发给taskmanager
  2. 申请资源:flink自己的ResourceManager申请执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(slot),一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的TaskManager上;
  3. 协调检查点和故障恢复;

2.  资源管理器ResourceManager)主要负责管理任务管理器(TaskManager)的插槽(slot),TaskManger插槽是Flink中定义的处理资源单元。

       1)分配资源:JobManager申请插槽资源时,ResourceManager会将有空闲插槽的TaskManager分配给JobManager

       2)申请资源:如果ResourceManager没有足够的插槽来满足JobManager的请求,它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器;

       3)释放资源:负责终止空闲的TaskManager,释放计算资源。

3. TaskManager是实际负责执行计算的Worker,在其上执行Flink Job的一组Task,每个TaskManager负责管理其所在节点上的资源信息,如内存、磁盘、网络,在启动的时候将资源的状态向JobManager汇报。

4.其他的还有客户端和分发器,分发器不是所有模式都必备,比如per job模式就没有。

4 公司怎么提交的实时任务,有多少 Job Manager?

1)我们使用yarn session模式提交任务;另一种方式是每次提交都会创建一个新的 Flink 集群,为每一个 job 提供资源,任务之间互相独立,互不影响,方便管理。任务执行完成之后创建的集群也会消失。线上命令脚本如下:

bin/yarn-session.sh -n 7 -s 8 -jm 3072 -tm 32768 -qu root.*.* -nm *-* -d

其中申请 7 taskManager,每个 8 核,每个 taskmanager 32768M 内存。

2)集群默认只有一个 Job Manager。但为了防止单点故障,我们配置了高可用。对于standlone模式,我们公司一般配置一个主 Job Manager,两个备用 Job Manager,然后结合 ZooKeeper 的使用,来达到高可用;对于yarn模式,yarnJob Mananger故障会自动进行重启,所以只需要一个,我们配置的最大重启次数是10次。

5 Flink的并行度了解吗?Flink的并行度设置是怎样的?

Flink中的任务被分为多个并行任务来执行,其中每个并行的实例处理一部分数据。这些并行实例的数量被称为并行度。我们在实际生产环境中可以从四个不同层面设置并行度:

操作算子层面(Operator Level)

执行环境层面(Execution Environment Level)

客户端层面(Client Level)

系统层面(System Level)

需要注意的优先级:算子层面>环境层面>客户端层面>系统层面。

6 Flink的Checkpoint 存在哪里

可以是内存,文件系统,或者 RocksDB

7 Flink的三种时间语义

Event Time:是事件创建的时间。它通常由事件中的时间戳描述,例如采集的日志数据中,每一条日志都会记录自己的生成时间,Flink通过时间戳分配器访问事件时间戳。

Ingestion Time:是数据进入Flink的时间。

Processing Time:是每一个执行基于时间操作的算子的本地系统时间,与机器相关,默认的时间属性就是Processing Time

8 说说Flink中的窗口

来一张官网经典的图:

 

Flink 支持两种划分窗口的方式,按照timecount。如果根据时间划分窗口,那么它就是一个time-window 如果根据数据划分窗口,那么它就是一个count-windowflink支持窗口的两个重要属性(sizeinterval)如果size=interval,那么就会形成tumbling-window(无重叠数据) 如果size>interval,那么就会形成sliding-window(有重叠数据) 如果size< interval, 那么这种窗口将会丢失数据。比如每5秒钟,统计过去3秒的通过路口汽车的数据,将会漏掉2秒钟的数据。通过组合可以得出四种基本窗口:

time-tumbling-window 无重叠数据的时间窗口,设置方式举例:timeWindow(Time.seconds(5))

time-sliding-window 有重叠数据的时间窗口,设置方式举例:timeWindow(Time.seconds(5), Time.seconds(3))

count-tumbling-window无重叠数据的数量窗口,设置方式举例:countWindow(5)

count-sliding-window 有重叠数据的数量窗口,设置方式举例:countWindow(5,3)

9 Exactly-Once的保证

下级存储支持事务:Flink可以通过实现两阶段提交和状态保存来实现端到端的一致性语义。 分为以下几个步骤:

1)开始事务(beginTransaction)创建一个临时文件夹,来写把数据写入到这个文件夹里面

2)预提交(preCommit)将内存中缓存的数据写入文件并关闭

3)正式提交(commit)将之前写完的临时文件放入目标目录下。这代表着最终的数据会有一些延迟

4)丢弃(abort)丢弃临时文件

5)若失败发生在预提交成功后,正式提交前。可以根据状态来提交预提交的数据,也可删除预提交的数据。

下级存储不支持事务:

具体实现是幂等写入,需要下级存储具有幂等性写入特性。

10 说一下Flink状态机制

Flink在做计算的过程中经常需要存储中间状态,来避免数据丢失和状态恢复。选择的状态存储策略不同,会影响状态持久化如何和 checkpoint 交互。

Flink提供了三种状态存储方式:MemoryStateBackendFsStateBackendRocksDBStateBackend

11 Flink 中的Watermark机制

Watermark 是一种衡量 Event Time 进展的机制,可以设定延迟触发

Watermark 是用于处理乱序事件的,而正确的处理乱序事件,通常用Watermark 机制结合 window 来实现;

数据流中的 Watermark 用于表示 timestamp 小于 Watermark 的数据,都已经到达了,因此,window 的执行也是由 Watermark 触发的。

12 Flink分布式快照的原理是什么

Flink的容错机制的核心部分是制作分布式数据流和操作算子状态的一致性快照。 这些快照充当一致性checkpoint,系统可以在发生故障时回滚。 Flink用于制作这些快照的机制在“分布式数据流的轻量级异步快照”中进行了描述。 它受到分布式快照的标准Chandy-Lamport算法的启发,专门针对Flink的执行模型而定制。

 

barriers在数据流源处被注入并行数据流中。快照nbarriers被插入的位置(我们称之为Sn)是快照所包含的数据在数据源中最大位置。

例如,在Apache Kafka中,此位置将是分区中最后一条记录的偏移量。 将该位置Sn报告给checkpoint协调器(FlinkJobManager)。

然后barriers向下游流动。当一个中间操作算子从其所有输入流中收到快照nbarriers时,它会为快照n发出barriers进入其所有输出流中。

一旦sink操作算子(流式DAG的末端)从其所有输入流接收到barriers n,它就向checkpoint协调器确认快照n完成。

在所有sink确认快照后,意味快照着已完成。一旦完成快照njob将永远不再向数据源请求Sn之前的记录,因为此时这些记录(及其后续记录)将已经通过整个数据流拓扑,也即是已经被处理结束。

注:flink是有状态的分布式流式计算引擎,容错机制是flink的亮点之一,发生故障时会根据保存的状态进行回滚,因此状态的保存就非常重要。由于flink是分布式的,那么何时保存状态就很重要,必须要做到所有节点都处理完同一条数据时进行状态的保存。主要有两种思路:

第一种就是要做快照时source停止发送数据,等到数据流向sinksink处理完后,那么就说明所有的所有节点完成了同一条数据的处理,这时候就可以保存状态了。显然这种为了保存状态,节点停止计算的做法效率非常低。这个就类似于虚拟机快照,我平时喜欢研究新技术,自己就在虚拟机上搭建了一个集群,但是有时候肯定会出现各种各样的问题,所以在安装新的框架前,我都对虚拟机做了一个快照,这时候我都是停机做的快照,因为如果开机做快照占用的空间会更多。

第二种就是flinkChandy-Lamport算法的启发,整体思路是将检查点的保存与数据的处理过程分离开,保存的时候不需要暂停整个应用,该保存的时候保存即可,最后将保存的状态合并即可,并不会消耗系统的性能。比如之前拍集体合照需要等到所有人忙完手头的活才能进行,效率低。而这次疫情出现了云合照,每个人自己拍照片即可,最后将每个人的照片P在一起形成合照,这样就不用等每个人忙完,效率提高。所以具体实现就是在数据流中加入特殊的数据类型barrier,看到barrier就做状态的保存。barrier向下游传递时,如果不是one to one的关系就会向下游广播barrier。整体的检查点算法就是3句话:1barrier对齐,barrier向下游传递时,需要等到所有分区的barrier到时才做状态的保存;2)对于barrier已经到达的分区,继续到达的数据会被缓存起来;3)对于barrier尚未到达的分区,数据会被正常处理。当jobmanager收到所有任务的检查点的保存时即完成了状态点的保存。

13 介绍一下Flink的CEP机制

CEP全称为Complex Event Processing,复杂事件处理

Flink CEP是在 Flink 中实现的复杂事件处理(CEP)库

CEP 允许在无休止的事件流中检测事件模式,让我们有机会掌握数据中重要的部分

一个或多个由简单事件构成的事件流通过一定的规则匹配,然后输出用户想得到的数据 —— 满足规则的复杂事件

注:CEPflink提供的一个处理复杂事件的库,类似于一个功能复杂的filter,过滤出符合我们定义的模式序列的一组数据。CEP的实现底层与正则的实现差不多,CEP的底层实现了NAF(非确定性有限状态机),用于控制状态的跳转,当前是否匹配上是通过状态机进行跳转。当前匹配到的事件序列,就保存在Map里。key为事件的名称。value是一个list,指的是不止可以检测到一个事件,还可以检测到多个事件(循环模式)。CEP的使用主要分为3个部分:

第一个是定义模式:模式分为个体模式、模式序列以及模式组。其中个体模式分为单例模式、循环模式;模式序列分为严格近邻和非严格近邻。

第二个是将定义的模式应用到流上CEP可以作用的流可以是普通流,也可以是keyBy之后的流;

第三个是在应用的流上可以拣选出超时的事件以及匹配到的复杂事件,并对其进行处理。所谓超时事件是指在within规定的时间范围内,开始是匹配上的,但是由于窗口关闭,而被认为没有匹配上,如果继续等待下去可能会匹配上。

当然CEP的本质就是状态的管理,只会处理超时事件和匹配到的复杂事件。Process API能够实现的逻辑会比CEP更加全面,可以将有问题的数据输出到侧输出流,而CEP就不能实现,但是CEP能够自己管理状态,代码逻辑简单。

14 Flink CEP 编程中当状态没有到达的时候会将数据保存在哪里?

在流式处理中,CEP 当然是要支持 EventTime 的,那么相对应的也要支持数据的迟到现象,也就是watermark的处理逻辑。CEP对未匹配成功的事件序列的处理,和迟到数据是类似的。在 Flink CEP的处理逻辑中,状态没有满足的和迟到的数据,都会存储在一个Map数据结构中,也就是说,如果我们限定判断事件序列的时长为5分钟,那么内存中就会存储5分钟的数据,这在我看来,也是对内存的极大损伤之一。

15 统计最近一小时热门商品TopN,每5分钟输出一次(aggregate算子)

实现思路:

1.使用什么时间语义:使用事件时间语义

2.观察数据源思考生成watermark的方式:由于数据已经经过ETL,成为有序的了,不存在乱序数据,所以可以使用升序提取watermark的方式获取watermark

3.按照itemID分组,定义滑动窗口(keyedWindow),计数,使用aggregate(预聚合函数,窗口函数获取聚合后的值以及分配时间戳)

    1reducesum等函数具有预聚合功能,来一条数据计算一条,但是无法获取窗口信息

    2)全窗口函数,能够获取窗口信息(开始时间,结束时间),但会将一个窗口的数据全部都放到迭代器中,没有预聚合功能。

    3aggregate可以传入两个参数(AggregateFunctionWindowFunction,AggregateFunction每来一条数据计算一条,并将最后的结果传递到WindowFunction的迭代器中,这样迭代器就只有一条数据,还能获取窗口时间。

4.按照窗口时间分组,为了将所有数据排序可以将窗口内的所有数据使用状态保存,等到收集到所有数据后再统一进行排序,然后输出topN

5.由于使用定时器,当定时时间到后对数据进行排序。定时器是根据定时时间唯一确定,窗口内的所有数据的标记都是结束时间,所有注册多个定时器。其实是同一个定时器。

16 统计UV,指的是一段时间(比如一小时)内访问网站的总人数,去重(实现布隆过滤器)

整体思路:

1.数据来源:经过ETL清洗,有序的数据

2.一小时滚动窗口,应用全窗口函数,收集到所有用户,使用HashSet对用户去重,统计用户的个数

存在的问题

    1)全窗口函数会将一个窗口的所有数据收集到迭代器中,等到窗口关闭时才会触发计算,计算效率低

    2)使用HashSet对用户去重,需要将迭代器中的数据加载到内存,占用内存空间,当用户量大时容易OOM。比如1亿用户,每个用户信息20字节,需要的内存空间是 10^8 * 20 B = 10^6 * 2kB = 10^3 * 2MB = 2G

    3) 即便是将用户存在redis中也是对内存消耗非常大。

解决思路:

    1)使用布隆过滤器实现用户去重,在redis中存入String类型,key为窗口日期,value进行BitMap操作,由于redis是动态扩展存储空间,因此节省空间; 1亿用户 * 1个hash算法 * 10倍 = 10^9 bit = 10^6 * 1000 bit= 10^6 * 125B = 125 * 10^6 B = 125 * 10^3 KB = 125MB

    2)自定义Bloom过滤器,定义Bloom过滤器的长度,实现一个hash算法计算用户在数组中的offset,之后用offset在redis进行BitMap操作

    3)使用process API进行全窗口的操作,但是自定义触发器,每来一条数据就计算一次,并发送数据;

4)自定义全窗口processFunction,实现将用户写入到redis,并将UVcount保存在redis中。UvCount的保存按理说应该使用String类型,但是这里使用hash类型。

17 什么是触发器?

自定义触发器:定义数据什么时候发送和计算。1)计算;2)关窗。 可以分开定义。

1)TriggerResult.CONTINU:No action is taken on the window.(什么都不做)

2)FIRE_AND_PURGE:evaluates the window function and emits the window(计算数据,并发送数据,清空状态)

3)FIRE:the window is evaluated and results are emitted.The window is not purged, though, all elements are retained.(只计算数据)

4)PURGE:All elements in the window are cleared and the window is discarded,

without evaluating the window function or emitting any elements.(发送数据,并清空状态)

18 任务并行度与slot之间的关系?

Slots(槽位):就是分配好的一组资源,即分配资源的最小单位,然后在资源上执行任务,运行时一个任务就必须分配到一个slots上执行,占用一组特定的资源。默认一个taskmanager上开启一个slots。

任务并行度,是指一个flink任务提交后在整个集群的并行度。

numberOfTaskSlots与当前运行的job没有关系,他是taskmanager本身资源分配的静态属性,就是资源到底有几个。所以任务的运行与否与numberOfTaskSlots没有关系,而是与并行度有关系。

19 Flink默认的故障恢复策略?

  1. state:savepoints.dir:状态检查点的存储路径,存储在HDFS上。
  2. Jobmanager.execution.failover-strategy:region:故障恢复的策略默认是region。在flink1.9出的故障优化手段,如果是一个任务失败后,不需要将所有的任务停掉,然后从检查点重新执行。只是需要将与坏掉的节点有关联的任务重新计算,其他节点正常执行任务。

 

20 Flink集群有几种部署模式?

       1)Standalone模式

       2)yarn模式:

              2.1)session模式:在yarn中初始化一个flink集群,开辟指定的资源,以后提交任务都向这里提交,所有作业共享Dispatcher和ResourceManager,共享资源。这个flink集群会常驻在yarn集群中,除非手工停止

              2.2)per job模式:每次提交都会创建一个新的flink集群,任务之间互相独立,互不影响,方便管理。任务执行完成之后创建的集群也会消失。

       3)k8s

21 Flink并行度设置优先级?

    1)代码级别的设置,各个算子设置并行度;

    2)全局设置;

    3)提交job时配置文件的设置;

    4)默认集群配置文件的设置。

22 Flink提交作业的流程?

图 Yarn模式任务提交流程(per-job-cluster模式)

Flink任务提交后,Client向HDFS上传Flink的Jar包和配置,之后向Yarn ResourceManager提交任务,ResourceManager分配Container资源并通知对应的NodeManager启动ApplicationMaster,ApplicationMaster启动后加载Flink的Jar包和配置构建环境,然后启动JobManager,之后ApplicationMaster向ResourceManager申请资源启动TaskManager,ResourceManager分配Container资源后,由ApplicationMaster通知资源所在节点的NodeManager启动TaskManager,NodeManager加载Flink的Jar包和配置构建环境并启动TaskManager,TaskManager启动后向JobManager发送心跳包,并等待JobManager向其分配任务。

注:

1.其实是在AppManager内部启动Flink的JobManager和ResourceManager,JobManager先向Flink的ResourceManager申请资源,再向yarn的ResourceManager申请资源。TaskManager启动后向Flink的ResourceManager注册slots信息,由于资源是yarn分配好的,所以注册之后就立马分配任务进行执行。

2.上图其实是per-job-cluster模式,每来一个job创建一个Flink集群,任务结束后就注销集群释放资源。

23 Flink怎样实现并行计算?

可以在配置文件、代码全局设置指定并行度,以及每个算子也可以指定并行度。

24 并行的任务,需要占用多少slot?

并行任务的每一个子任务都需要占用一个slot。但是流处理需要的slot个数,一个流程序的并行度,可以认为就是其所有算子中最大的并行度。

25一个流处理程序,到底包含多少个任务?

经过任务链合并后的子任务数,子任务数由每个算子的并行度决定。

26 taskmanager与slot之间的关系?

可以认为每一个taskmanager就是一个JVM进程,而里面执行的每一个任务可以认为是一个独立的线程,为了保障线程之间不互相影响,就给每个线程一份独立的内存空间,线程所占用的资源就叫做slot。因此,slot数量就是内存划分的数量,决定了一个taskmanager可以并行执行几个task,通过slot的数量可以控制taskmanager并行处理的能力。总之,一个taskmanager上的多个slot共享一个JVM,共享CPU,但是有独立的内存。

27 什么是slot共享,slot共享的好处?

Slot共享:对于每一个数据而言,他的任务的先后顺序是无法改变的,不可能并行处理。不同数据之间具有时间顺序,并行度指的是不同数据,不同的数据可以并行分配到不同的slot中。同一个数据同一个时间只能执行一个任务。所以可以允许将前后发生的不同任务放到一个slot中,也就是需要不同的子任务共享slot。

好处:默认的共享组是default,共享组的优点资源利用率高,默认条件下是使用共享组的,除了有特殊需求。

1)保存整个作业管道:对于先后发生的任务,可以共享slot,一个数据执行完后可以执行下一步操作,这样一个slot就可以保存作业的整个管道,即保存了处理流程的每一步操作,所有的操作可以在同一个slot中完成。

2)可靠性:由于一个slot保存了整个处理流程,即便别的taskmanager的slot挂掉之后,也不会影响整个数据处理。

3)防止数据积压:不同的任务有不同的复杂程度,不同的算子可以对CPU资源的占用情况不同,比如window就是资源密集型的算子,而像source、map这样的操作对于CPU来说可能就是一瞬间。如果不同的算子分布到不同的slot,就有可能出现像source、map不停的读取数据,而window进行大量计算占用CPU资源,出现忙的忙死,闲的闲死,出现数据堆积产生背压。为了避免这种情况,让资源更加平均的分布开,就需要让忙闲做个搭配,CPU占用比较高的任务和CPU占用比较低的任务放在一起共享slot,当map处理完后可以先不着急读取新的数据,可以接下处理window,这样资源的利用率就会更高,也不会出现数据积压。

28 为什么整个流处理的并行度就可以以任务最多的并行度决定?

为有slot共享的存在,所以整个流处理的并行度就可以以任务最多的并行度决定,也就是至少要分配的slot数量。

29 如何切断任务链?

由于共享slot的存在,当一个任务链的计算量特别庞大时,且只在一个slot上执行,对于slot的压力过大,需要拆开。

1)disableChaining:如果对一个算子使用了disableChaining(取消任务链),那么该算子就会与前后算子隔离开,不参与任务链的组合,独用一个slot。

2)startNewChain:如果一个任务链只是过于庞大,但是算子之间的操作简单,仅想拆开为2个任务链,并且参与任务链组合,就需要对算子使用startNewChain(开启一个新的任务链),意思就是之前该怎么合并就怎么合并,map之后重新合成任务链。

3)env.disableOperatorchaining ,全局切断任务链。所有的算子都是独立的任务,再按照并行度拆分开。

4)slotSharingGroup:取消任务链后,还需要打破slot共享,使用单独的slot。这时需要使用slotSharingGroup,之前的算子不管,从当前算子开始共享slot,并可以为共享组命名。同一个共享组内的算子可以共享一个slot,不同共享组的slot必须分配到不同的slot。且可以设置多个共享组,跨算子设置。

 

30 Flink整个流处理需要的资源数如何计算?

整个流处理需要的资源数= 每个共享组最大的并行度之和。

31 不同job可以共享slot吗?

可以,默认情况下,Flink允许子任务共享slot,即使它们是不同任务的子任务(前提是它们来自同一个job)。 这样的结果是,一个slot可以保存作业的整个管道。

 

32 flink的数据流(dataflow)是什么?flink程序由几部分组成?flink程序会做stage划分吗?

 

程序组成:所有的Flink程序都是由三部分组成的:  Source TransformationSink。Source负责读取数据源,Transformation利用各种算子进行处理加工,Sink负责输出。

数据流:数据流不会进行stage划分,而是根据算子顺序执行,数据来到之后,先进行source操作,再进行flatmap、map等转换操作,每次转换完后直接传递给下一步操作,直到sink输出。整个处理流程只针对数据的当前操作步骤来讲,根本不用等其他的数据,也不用等其他的并行任务,只考虑自己的流动即可,这就是所谓的数据流dataflow。

33 Flink中数据流图(StreamGraph)、作业图(JobGraph)、执行图(ExecutionGraph)、物理执行图分别是什么意思?

Flink 中的执行图可以分成四层:StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图。

1. StreamGraph根据用户通过 Stream API 编写的代码生成的最初的图, 就是每个算子对应一个任务,由于客户端完成。

2.JobGraph :client提交JobGraph给Jobmanager时,会将一些简单的算子合并成一个任务,这样可以减少数据在节点之间流动所需要的序列化/反序列化/传输消耗。在客户端上完成。

3. ExecutionGraphJobManager 根据 JobGraph 生成ExecutionGraph。根据并行度,将每一个任务分别拆开,定义每个任务之间的传输方式(数据来源哪里,去向哪一个任务),形成可执行的图,之后Jobmanager就会将ExecutionGraph分发给TaskManager,TaskManager就会根据执行图来定义每一个slot上执行哪些任务。在jobmanager上完成。

4. 物理执行图:JobManager 根据 ExecutionGraph 对 Job 进行调度后,在各个TaskManager 上部署 Task 后形成的“图”。在taskmanager上完成。

 

34 谈一下Flink的并行度?

1)一个特定算子的子任务(subtask)的个数被称之为其并行度(parallelism)。

2)一个流程序的并行度,可以认为就是其所有算子中最大的并行度。

3)一个程序中,不同的算子可能具有不同的并行度。

 

35 Flink的数据传输形式分为几种?

1)one-to-one:维护着分区以及元素的顺序。比如map、fliter、flatMap等算子都是one-to-one的对应关系。

2)Redistributing(重分区):rebalance、keyBy() 基于hashCode重分区、broadcast。

注:redistributing的两种场景:

1)上下游分区发生改变。如果不进行重分区,那么并行度就无法利用;

2)前后发生的两步操作,对于数据传输有要求。比如map之后需要分组进行sum,中间有一步keyBy操作。keyBy不是具体的计算操作,不是一个任务,而是数据传输操作,定义了key按hashCode值进行重分区。至于是hashCode还是轮循,具体看哪种算子。

 

36 什么是任务链,有什么好处?什么情况下两个任务可以合并?

任务链:flink将满足某种条件下,将先后发生的算子任务连接在一起,形成一个大的任务,放在一起进行计算。

好处:就是本地调用,减少网络传输的成本,减少线程之间的切换和基于缓存区的数据交换,在减少时延的同时提升吞吐量。

合并条件:

       1)并行度相同;

       2)one to one;

       3)同一个共享组;

4)同一个任务链

37 slot并行的条件?

slot是否真正的并行得看taskManager分配的cpu核心,同一个taskmanager的slot可以独享内存,但是只能共享CPU,如果2个slot共用一个cpu,那么并不是真正的并行。只有一个slot独享一个cpu才是真正的并行。

38 Flink DataStreamAPI常见的source?

       1)从集合创建:env.fromCollectionList

    2) 从文件读取数据: env.readTextFile("YOUR_FILE_PATH ");

    3以kafka消息队列的数据作为来源: env.addSource( new FlinkKafkaConsumer011<String>("sensor", new SimpleStringSchema(), properties)); 当没有指定并行度时,flink-kafka连接器会自动检测消费的topic的分区数,根据分区数设置并行度。当topic只有一个分区时,并行度就是1

    4)自定义source

    4.1)定义类继承SourceFunction

    4.2) 重写runclose方法,run方法内定义whileflag)不断的发送数据,close修改标记位flag

    5)从端口读取数据

39 Flink 中Connect与 Union 区别?

1)Union之前两个流的类型必须是一样,Connect可以不一样,在之后的coMap中再去调整成为一样的。

2)Connect只能操作两个流,Union可以操作多个。

40 Flink中富函数的作用?

所有Flink函数类都有其Rich版本,它与常规函数的不同在于,可以获取运行环境的上下文,并拥有一些生命周期方法,所以可以实现更复杂的功能,比如说定义状态。

  1. open()方法是rich function的初始化方法;
  2. close()方法是生命周期中的最后一个调用的方法,做一些清理工作。
  3. getRuntimeContext()方法提供了函数的RuntimeContext的一些信息,例如函数执行的并行度,任务的名字,以及state状态。

41 Flink中常见的Sink?

       1)写入kafkadataStream.addSink(new FlinkKafkaProducer011[String]("localhost:9092", "test", new SimpleStringSchema()))

       2)写入redis定义类实现RedisMapper接口,实现3个方法(定义redis中数据类型,定义key,定义value),dataStream.addSink( new RedisSink<SensorReading>(config, new MyRedisMapper()) );

    3)写入ES定义类实现ElasticsearchSinkFunction接口,dataStream.addSink( new ElasticsearchSink.Builder<SensorReading>(httpHosts, new MyEsSinkFunction()).build());

    4)自定义sink定义类继承RichSinkFunction

42 Flink中分流操作的应用场景?

分流操作:(split,select)

 1)基本概念:

   1.1)split将一个DataStream拆分为两个或多个流,进行流类型转换,得到SplitStream,理论上并没有把DataStream拆开,而是把流做一个划分,还是在一个流内,只不过做了一个分类,类似于一个班划分为多个组。

   1.2)如何将一个流分成两个流,得到两个DataStream?split相当于给流做一个分类,而select是真正根据分类将一个DataStream拣选为两个或多个DataStream。因此,split和select经常一起使用。

  2)应用场景:有时候日志数据可能没有分类直接放到kafka的一个主题内,这时就需要进行预分流处理,自己部门拣选出自己需要的数据,其他数据可以给其他部门使用,这时候就可以使用split分成不同的流,自己部门消费自己部门的数据,其他数据再写入到kafka中供其他部门消费。

43 Flink中写入数据库为什么需要使用sink,而不是在其他算子内部?

尽管可以在一些算子内部进行数据库的连接,比如读写,但是由于Flink是分布式系统,为了保证结果的正确性以及容错性还是要使用Sink进行输出,如果在map中进行数据库写入操作,那么当出现错误时重新计算还需要再次写入数据库,因此不能在map中进行数据输出。

44 Flink中window与windowAll的区别?

window()方法必须在keyBy之后才能使用,即只有KeyedStream中才有window(),必须先分组。当然也可以不先分组而是基于DataStream使用windowAll()。

注:Flink官网不推荐使用windowAll,因为使用windowAll() Flink底层会将所有的数据都发往同一个分区去做窗口的分桶及计算,相当于并行度变为1,没有了并行度。因此,推荐使用keyBy分组之后使用窗口。

45 Flink中window function主要分为几类,各有什么作用?

window function 定义了要对窗口中收集的数据做的计算操作,主要可以分为两类:增量聚合函数和全窗口函数。

注:

  1. 窗口是截取无界流变为有界流然后将数据放入桶中,增量聚合函数是将桶中的有界流依然当做无界流处理,而全窗口函数就是批处理模式。
  2. 增量聚合函数是来一条数据就进行计算,只需要保存计算后的状态即可,而不需要保存已经计算的数据,等到到点后直接输出状态即可。因此效率更高。
  3. 全窗口函数需要等到所有的数据到齐后才开始计算,效率低,但是也有应用场景,比如求一批数据的中位数,只能等所有的数据到齐后才能计算。
  4. 此外,全窗口函数比如增量集合函数能够获取的信息更多,能够在上下文中拿到当前窗口的信息(窗口结束时间),运行时上下文的状态信息。

46 Flink中哪种时间语义更重要?

案例:90秒内消消乐通关5次获取奖励,在地铁在玩消消乐,一口气过了8关,但是中间由于没有网发送了过关的消息到达Flink系统的摄入时间就乱序了。如果按照处理时间就不能发放奖励,但是按照事件时间应该发放奖励。因此,从考虑用户体验的角度应该使用事件时间。

处理时间的应用场景:对于实时性要求高,但是对于正确性要求没有那么高。在窗口时间到的时刻就关闭窗口,不等待迟到的数据,丢一些数据算了,只为了保证能够立刻获取结果。

47 谈谈你对watermark的理解?

1)一类特殊的数据:Watermark是数据流中插入的一类特殊类型数据,底层就是一个与时间戳相关数据,可以通过Watermark指示当前系统的时间。

2)处理乱序数据:可以延迟窗口计算和关闭的触发,处理乱序数据,可以认为watermark之前的数据全部到齐,默认200ms生成一次watermark。

3)提高准确性:乱序数据会让计算不准确,而延迟机制就能提高数据计算的准确性,延迟机制叫做Watermark。

4)如果想让正确性提高,就调大Watermark,增大事件延迟;如果想提高实时性,就调小Watermark,这样正确性就下降。

总之:watermark就是延迟系统时间,可以将迟到的数据依然能够放进正确的桶中。

48 Watermark的传递规则?

1.因为Watermark就是一条特殊的数据,因此可以在流中传递。

2.Watermark在并行处理时传递的规则:上游有多个子任务,上游向下游传递是广播Watermark;下游接收上游Watermark时会保留上游分区Watermark,自己的时钟是以上游分区最小的Watermark为准。

       3.只有watermark向前更新才会向下游传播。

49 周期性生成Watermark与间断式生成Watermark的区别?

1)间断式生成是每来一条数据就生成一个Watermark,周期性生成是一定时间间隔生成一个Watermark。

2)在大数据场景数据密集,短时间大量数据涌入,可能大量数据的时间戳都相同,如果使用间断式生成就非常浪费性能,生成的Watermark大部分都相同,这时候就适合使用周期性生成。

3)对于数据稀疏,数据间断式过来,就适合使用间断式生成更新Watermark,如果使用周期性生成,可能一段时间没有数据到来,但是生成大量Watermark,做了无用功,但是也无所谓,因为这时候闲着也是闲着,生成一些Watermark也没有问题。

50 周期性生成Watermark的最大乱序程序如何设定?

1)周期性生成Watermark设置大了,影响实时性,但是结果准确性提高;设置小了,实时性提高,消耗性能也提高,结果准确性下降。

2)一般先设置比较小的最大乱序程序,比如30毫秒,他可以包含大部分数据延迟的情况,因为大部分的乱序数据属于正态分布,只有少部分的数据延迟很高,因此不能一直等待下去,可以设置一个比较小的延迟时间,她可以hold住大部分延迟的数据。如果想要结果非常正确,可以window后设置收集迟到数据放入侧输出流中。

51 Flink处理乱序数据三重保证?

1)Watermark延迟时间:先设置比较小的Watermark延迟时间,快速得到一个近似正确的结果,且能够包含大部分延迟的数据;

2)窗口允许迟到数据:如果要求更加精准,就可以设置处理迟到数据;

3)侧输出流:最后数据不能一直等待下去,可以设置输出到侧输出流中,保证数据不丢。

52 Flink窗口的起始时间如何确定?

       窗口起始时间为窗口大小的整数倍。

53 Flink中Process API的主要功能?

无所不能,能够获取运行时上下文,生命周期方法,定义状态,定义定时器,输出到侧输出流。

54 谈谈你对Flink中状态的理解?

1)每个任务都可以有状态。Flink中每一步操作都是数据流中的一个任务,任务可以有状态的,也可以没有状态。尽管说Flink是有状态的流式计算,但是对于一些简单的操作(map、filter)是可以没有状态的,但是复杂的计算(sum、reduce、窗口)是需要使用到状态的。

2)Flink中的状态由当前任务保存

3)状态就是一个本地变量。task就是运行在slot上的一个线程,因此task使用到的数据可以保存在线程独享的内存空间中,是一个变量可以被当前线程的任何业务逻辑访问。Flink会对状态进行管理。

4)flink会进行状态管理,包括状态一致性、故障处理以及高效存储和访问。

55 为什么不能自己定义一个变量来保存状态?

主要是因为Flink是分布式系统,获取数据涉及到序列化和反序列化;同时故障恢复时需要从检查点中恢复数据,如果是一个自定义的本地变量用什么类型去做存储管理,就显得很困难。而Flink有一套自己的类型系统,如果想自己定义变量进行容错管理,那就必须使用Flink提供的状态管理机制进行变量的定义,所以自己来实现这一套机制就非常麻烦,需要考虑序列化、在checkpoint中如果保存,且由于是分布式的还需要考虑数据如何拼在一起。比如目前并行度为3,考虑到并行度不足,停掉程序,设置下游并行度为4,这是就需要考虑上游数据的状态如何拼接以及如何给下游均匀分配数据的情况。Flink实现了一整套状态管理的机制,故障发生后如何进行故障恢复,恢复状态,以及状态的高效存储和访问,从而不需要做底层比较难受的事情。

56 Flink中算子状态与键控状态的区别?

算子状态的作用域就是每一个流经并行子任务的数据能够访问,而键控状态是只能是相同key才能访问,相当于key对内存又进一步划分。在生产中我们一般使用键控状态。

57 Flink中如何注册状态?

为了在运行时使用状态,Flink必须知道状态在内存管理机制中的保存位置、类型等,从而在底层才能使用状态管理机制的序列化、反序列化读取状态,因此算子必须先在环境注册状态。在运行时环境中获取状态的控制句柄,给状态一个具体的名,具体的类型,这样flink的状态管理机制就知道如何操作。

58 Flink中算子状态可以定义哪几种数据结构?

算子状态:状态对于同一子任务而言是共享的,但是对于并行的另一个子任务是分开,因为他们跨了slot,甚至跨了taskManager。因此他们是不能相互访问的,要是能访问就涉及网络传输,也必须得实现序列化。

       1)列表状态:将所有状态保存为一组数据的列表,方便后续的调整管理(比如可以将多个并行的任务的状态直接拼接在一块,如果下游增大并行度,直接将列表拆开即可)。

       2)联合列表状态:也将状态表示为数据的列表。

       3)广播状态:如果一个算子有多项任务,而它的每项任务状态又都相同。(使用的较少,比如从一个流中读取到的动态的配置项,各个并行的子任务都需要使用,对于一些常规的配置项直接写在配置文件中即可)。

59 算子状态中列表状态与联合列表状态的区别?

主要区别就是在发生故障时,或者从保存点(savepoint)启动应用程序时如何恢复。

1)列表状态如何进行故障恢复?保存的时候拼接在一块,恢复的时候直接打散。

2)联合列表状态如何进行故障恢复?保存的时候把并行状态对应的每一个列表都存一份,恢复的时候联合在一块再做动态调整。

60 Flink中键控状态由几种数据类型?

键控状态: Flink为每个key维护一个状态实例,主要分为:

  1. 值状态(ValueState[T]):来一个数据就存一个数据。
  2. 列表状态(ListState[T]):来一个数据就追加到列表的最后面。
  3. 映射状态(MapState[K, V]):来一个数据有则更新,无则插入。
  4. 聚合状态(ReducingState[T],AggregatingState[I, O]):将状态表示为一个用于聚合操作的列表。来一个数据直接在之前聚合的结果上再次进行聚合,最后保存聚合结果就ok了。比如min、max、sum等底层保存的状态就是聚合状态。

61 什么是状态一致性?

       有状态的流处理,内部每个算子都可以有自己的状态。所谓状态一致性,就是我们所说的计算结果要保证准确。主要包括以下两个方面:

  1. 一条数据都不应该丢失,也不应该重复计算。
  2. 在遇到故障是可以恢复状态,恢复以后的重新计算,结果应该也是完全正确的。

62 Flink中一致性的级别?

       1at-most-once(最多一次):当任务故障时,最简单的做法是什么都不干,既不恢复丢失的状态,也不重播丢失的数据。At-most-once 语义的含义是最多处理一次事件。(注:应用场景就是对实时性要求特别高的场景,丢一些数据无所谓。类似的是传输层协议中的TCP/UDP。TCP尽管需要三次握手确保一定建立连接,数据传输的可靠性增加,但是效率低。而UDP用户数据包协议,只管发送数据,比如在传输视频时,丢一两帧数据无所谓(丢包),大不了重发一次,省去了握手效率更高。在网络环境好的时候,使用UDP效率很高。)

       2at-least-once(最少一次):注:在大多数的真实应用场景,我们希望不丢失事件。这种类型的保障称为 at-least-once,意思是所有的事件都得到了处理,而一些事件还可能被处理多次。

       3exactly-once(精准一次): 只计算一次是最严格的保证,也是最难实现的。只计算一次不仅仅意味着没有事件丢失,还意味着针对每一个数据,内部状态仅仅更新一次。(注:只计算一次,指的是状态只更新一次,有可能计算进行了2次,第一次计算后任务挂掉,但状态没有保存。)

62 storm、SparkStreaming和Flink内部一致性的级别及优缺点?

       1)storm(第一代流处理器):实现了at-least-once。因为在架构层面实现exactly-once非常困难,只能在应用层面通过幂等性弥补。

       2)SparkStreaming:为了保证exactly-once,无法对单个数据进行处理,只能形成微批次,保证对每一批的处理要么全部成功,要么全部失败。因此,在实时性方面表现不足。

       3)flink:既保证了exactly-once,也具有低延迟和高吞吐的处理能力。

注:精准一次性就是为了保证结果的正确性。

63 什么是一致性检查点?

       就是分布式快照算法。

64 什么是端到端的状态一致性?

       Flink内部实现了精准一次性,但是流处理应用除了流处理器以外还包括了数据源(例如 Kafka)和输出到持久化系统。端到端的一致性保证,要求每一个组件(source、transform、sink)都保证了它自己的一致性,整个端到端的一致性级别取决于所有组件中一致性最弱的组件。具体可以划分如下:

  1. 内部保证 —— 依赖checkpoint
  2. source 端 —— 需要外部源可重设数据的读取位置,保证数据不丢。

3)sink 端 —— 需要保证从故障恢复时,数据不会重复写入外部系统

而对于sink端,又有两种具体的实现方式:幂等(Idempotent)写入和事务性(Transactional)写入。

65 什么是sink端的幂等(Idempotent)写入?

幂等操作:是说一个操作,可以重复执行很多次,但只导致一次结果更改,也就是说,后面再重复执行就不起作用了。比如Hbase和Es实现了幂等性。

存在的问题:可能会出现历史重演,但是最终的结果是正确的。(比如:故障恢复时可能会暂时不一致,比如大屏监视温度的变化(想看到温度连续上升的情况)。数据为10->15->barrier ->20 ->25->30(挂掉) ->35。在大屏显示时就会出现10->15-> 20 ->25 ->20 ->25->30 ->35,影响显示效果历史重演。)

改进:可以将检查点做成一个事务,等检查点真正完成后,才将一个检查点期内的数据写入。

66 什么是sink端的事务写入?

需要构建事务来写入外部系统,构建的事务对应着 checkpoint,等到 checkpoint 真正完成的时候,才把所有对应的结果写入 sink 系统中。对于事务性写入,具体又有两种实现方式:预写日志(WAL两阶段提交(2PC

1.预写日志:把结果数据先当成状态保存,然后收到checkpoint完成的通知时,一次性写入sink系统。

2.预写日志存在的问题:不完美

1)实时性降低:预写日志(WAL)由于是批量写入sink系统,因此即便前面再怎么流式处理,sink也是一批实现,相当于实时性降低。

2)存在重复写入:如果在批处理写入的时候,没有做事务,写到一半挂掉,从状态点恢复的时候还是会重复写入。

3)改进之处:两阶段提交。

3.两阶段提交(2PC):对于每个checkpoint,sink任务会启动一个事务,并将接下来所有接收的数据添加到事务里,然后将这些数据写入外部sink系统,但不提交他们,只是进行预提交,等到他收到jobmanager发送的checkpoint完成的通知时,它才正式提交事务,实现结果的真正写入。如果开启了同时支持多个checkpoint的保存,当第二个checkpoint到来时,但是没有收到第一个checkpoint完成的同时,会另外开启一个预提交队列,将数据写入到新的预提交队列里,实现了实时性。

4.两阶段提交的要求:两阶段提交整体对flink的性能影响不大,还是来一条数据处理一条,只是将事务与checkpoint捆绑在一块。要求下游sink必须实现2PC,否则需要自己写,很麻烦。Kafka已经实现了2PC提交,所以flink与kafka是天生的一对。

67 Flink+Kafka如何实现端到端的exactly-once语义?

端到端的状态一致性的实现,需要每一个组件都实现,对于Flink + Kafka的数据管道系统(Kafka进、Kafka出)而言,各组件怎样保证exactly-once语义呢?

  1. flink内部:利用checkpoint机制,把状态存盘,发生故障的时候可以恢复,保证内部的状态一致性。Flink由JobManager协调各个TaskManager进行checkpoint存储,checkpoint保存在 StateBackend中,默认StateBackend是内存级的,也可以改为文件级的进行持久化保存。
  2. source kafka consumer作为source,可以将偏移量保存下来,如果后续任务出现了故障,恢复的时候可以由连接器重置偏移量,重新消费数据,保证一致性
  3. sink kafka producer作为sink,采用两阶段提交 sink,sink 任务首先把数据写入外部 kafka,这些数据都属于预提交的事务(还不能被消费);当遇到 barrier 时,把状态保存到状态后端,并开启新的预提交事务。当sink 任务收到确认通知,就会正式提交之前的事务。

注:

1)sink任务的状态保存完,并不代表其他任务的状态保存完,必须等待所有的任务的状态保存完后,收到jobmanager的确认信息才算真的检查点保存完,这时sink的事务才真正的提交,之前每个数据都是预提交。

2)修改sink提交的超时时间小于kafka预提交超时的时间:Kafka中读取数据的隔离级别也必须设为readCommit的,只能读取已经提交的数据,否则就会出现不可重复读。在kafka中开启事务进行预提交。Kafka中默认的预提交超时间是15min,flink的sink默认等checkpoint的超时时间是1小时,当sink等待checkpoint的时间超过15分钟但没有超过1小时时,kafka认为事务失败进行回滚,而flink却认为事务成功,就有可能出现数据丢失。所以需要将sink提交任务的超时时间限制在15min内。

68 什么是状态后端?

       Flink中状态的存储、访问以及维护由一个可插入的组件决定,这个组件叫做状态后端。状态后端主要负责两件事:

  1. 本地状态的管理:便于快速访问状态
  2. 将检查点状态写入远程存储:便于故障恢复。

69 Flink中的状态后端分为几种,如何选择?

我们选择RocksDB状态后端,状态后端主要分为以下几个部分:

       1)内存级的状态后端(MemoryStateBackend,默认配置):

1.1)概念:会将键控状态作为内存中的对象进行管理,将它们存储在TaskManager的JVM堆上;而将checkpoint存储在JobManager(远程)的内存中。

1.2)特点:快速、低延迟、但不稳定(注:一方面是断电,另一方面是受GC管理)。1.3)应用场景:测试,生产环境中不使用。

       2)持久化文件系统(FsStateBackend):

       2.1)概念:将checkpoint存到远程的持久化文件系统(FileSystem)上。而对于本地状态,跟MemoryStateBackend一样,也会存在TaskManager的JVM堆上。

2.2)特点:同时拥有内存级的本地访问速度,和更好的容错保证。

2.3)存在的问题:是本地状态存到内存中,如果任务很庞大,管理的状态特别多,本地内存不够使用就会出现问题。

2.4)应用场景:生产环境中要求性能快,如果内存不足就加机器,加钱。

3)RocksDB数据库:RocksDBStateBackend

3.1)概念:将所有状态序列化后,存入本地的RocksDB中存储。

3.2)特点:权衡的方法,RocksDB就是一个基于磁盘读写性能好的数据库,由于序列化所以会消耗性能,但是能够解决本地内存不足以管理状态的场景。

3.3)注意事项:RocksDBStateBackend当状态特别多时,可以设置不用每次全量式保存状态,而是设置保存新增及变化的状态。但是要求之前的状态不能丢,只有这样才能练成完整的状态。

 

70 Flink怎么做压力测试和监控?

我们一般碰到的压力来自以下几个方面:

一,下游算子消费不及时:产生数据流的速度如果过快,而下游的算子消费不过来的话,会产生背压。背压的监控可以使用 Flink Web UI(localhost:8081) 来可视化监控Metrics,一旦报警就能知道。一般情况下背压问题的产生可能是由于 sink 这个 操作符没有优化好,做一下优化就可以了。比如如果是写入 ElasticSearch, 那么可以改成批量写入,可以调大 ElasticSearch 队列的大小等等策略。

二,watermark导致的内存压力:设置watermark的最大延迟时间这个参数,如果设置的过大,可能会造成内存的压力。可以设置最大延迟时间小一些,然后把迟到元素发送到侧输出流中去。晚一点更新结果。或者使用类似于 RocksDB 这样的状态后端, RocksDB 会开辟堆外存储空间,但 IO 速度会变慢,需要权衡。

三,还有就是滑动窗口的长度如果过长,而滑动距离很短的话:Flink 的性能会下降的很厉害。我们主要通过时间分片的方法,将每个元素只存入一个“重叠窗口”,这样就可以减少窗口处理中状态的写入。参见链接:https://www.infoq.cn/article/sIhs_qY6HCpMQNblTI9M

四,状态后端使用 RocksDB还没有碰到被撑爆的问题。

71 为什么使用 Flink 替代 Spark?

主要考虑的是flink的低延迟、高吞吐量和对流式数据应用场景更好的支持;另外,flink可以很好地处理乱序数据,而且可以保证exactly-once的状态一致性。

72  Flink 的 checkpoint 存在哪里?

可以是内存,文件系统,或者 RocksDB。我们选择RocksDB,效率高,且不会出现内存爆掉的情况。

73 如果下级存储不支持事务,Flink 怎么保证 exactly-once?

端到端的exactly-once对sink要求比较高,具体实现主要有幂等写入和事务性写入两种方式。幂等写入的场景依赖于业务逻辑,更常见的是用事务性写入。而事务性写入又有预写日志(WAL)和两阶段提交(2PC)两种方式。

如果外部系统不支持事务,那么可以用预写日志的方式,把结果数据先当成状态保存,然后在收到 checkpoint 完成的通知时,一次性写入 sink 系统。

注:更常见的是at-least-once + 幂等性。

74 说一下 Flink 状态机制?

Flink内置的很多算子,包括源source,数据存储sink都是有状态的。在Flink中,状态始终与特定算子相关联。Flink会以checkpoint的形式对各个任务的状态进行快照,用于保证故障恢复时的状态一致性。Flink通过状态后端来管理状态和checkpoint的存储,状态后端可以有不同的配置选择。

75 海量key去重?

问题:怎么去重?考虑一个实时场景:双十一场景,滑动窗口长度为 1 小时,滑动距离为 10 秒钟,亿级用户,怎样计算 UV?

解答:使用类似于 scala 的 set 数据结构或者 redis 的 set 显然是不行的,因为可能有上亿个 Key,内存放不下。所以可以考虑使用布隆过滤器(Bloom Filter)来去重。

76 Flink 的 checkpoint 机制对比 spark 有什么不同和优势?

spark streaming 的 checkpoint 仅仅是针对 driver 的故障恢复做了数据和元数据的 checkpoint。而 flink 的 checkpoint 机制 要复杂了很多,它采用的是轻量级的分布式快照,实现了每个算子的快照,及流动中的数据的快照。

77 Flink中exactly-once语义是如何实现的,状态是如何存储的?

Flink依靠checkpoint机制来实现exactly-once语义,如果要实现端到端的exactly-once,还需要外部source和sink满足一定的条件。状态的存储通过状态后端来管理,Flink中可以配置不同的状态后端。

78 Flink 三种时间语义是什么,分别说出应用场景?

1)Event Time:这是实际应用最常见的时间语义,具体见文档第七章。

2)Processing Time:没有事件时间的情况下,或者对实时性要求超高的情况下。

3)Ingestion Time:存在多个Source Operator的情况下,每个Source Operator可以使用自己本地系统时钟指派 Ingestion Time。后续基于时间相关的各种操作,都会使用数据记录中的 Ingestion Time。

79 Flink程序在面对数据高峰期时如何处理?

1)找兄弟:使用大容量的 Kafka 把数据先放到消息队列里面作为数据源,再使用 Flink 进行消费,不过这样会影响到一点实时性。

2)自身:加机器,提高并行度。

80 批处理与流处理的区别?

1)批处理:hadoop和spark是批处理的代表作,其中spark可以说是批处理的巅峰,一般说起离线数仓都是以spark为主。

2)流处理:storm和flink是流处理的代表作,其中storm作为第一代流处理作品,后来在大规模流式数据处理时,storm的实时性是够好的,但是吞吐量不够大,处理的数据量不够大,同时对于乱序数据的处理要求时间正确又得不到保障,因此storm没有得到广泛的应用。而后来更广泛应用的是Lambda架构,Storm作为Lambda架构的一部分参与计算,分为两个部分,一部分是快速的流处理保证实时性,另一部分是批处理保证结果正确性。目前,Flink就实现了两者的统一,实现了低延迟、高吞吐的实时流式处理系统,而且具有不同的时间语义能够处理乱序数据保证结果的正确性,此外还有一套完善的状态管理机制和容错机制,实现非常好的状态一致性保证。

3)hadoop/spark是数据已经确定,然后任务划分stage一步一步的去操作。而flink是任务都已经确定好了就等数据到来。铁打的营盘流水的兵,除非cancel,否则就是无休无止,源源不断。

81 Flink中控制数据流向的几种方法?

1)rebalance轮循向下游发送数据,需要是one-to-one

 

2)keyBy,根据数据的hash值%下游并行度,决定数据的流向

3)shuffle

4)forward

 

82 Flink怎样实现双流join?

由于flink是由状态的流式处理框架,所以不需要借助于第三方框架就能够完成状态的管理,很容易实现双流join:

1)方式一:使用connect的方式连接,自定义状态,用状态编程,解决一个数据等待另一个数据的情况。

2)方式二:使用Interval Join的方式针对单个事件开窗。

 

  • 由于是对单个事件开窗口,如果没有匹配上,那么该条数据就会丢失,而使用connect的方式可以输出到侧输出流中。
  • Join的底层是实现状态编程的,只不过不需要我们管理状态。
  • 用橙流join绿流,绿流等待橙流的时间叫做下界,必须是负数。橙流等待绿流的时间叫做上界,是正数。
  • 用于join的流必须是经过keyBy的流。
  • 调用intervalJoin的流作为主体,决定上下界。

 

3)Join与connect的区别:

如果是从文本文件中读取数据,而watermark默认是生成周期是200ms生成一个,文本文件读取过快,会出现,本不应该join上的数据join上了。但是在实际生产中不会出现这种情况。而join的方式是严格按照时间进行join,不会出现乱join的问题,只不过缺陷就是没有join上的数据会发生丢失,而connect可以输出到侧输出流中。

83 Table API/Flink SQL的执行环境?

1.old planner:1.10默认是old Planner,1.11默认是blink Planner

    1)流处理环境

    2)批处理环境

2.blink planner:

    1)流处理环境

    2)批处理环境

 

3.批流统一:Blink将批处理作业,视为流式处理的特殊情况。所以,blink不支持表和DataSet之间的转换,批处理作业将不转换为DataSet应用程序,而是跟流处理一样,转换为DataStream程序来处理。

4.因为批流统一,Blink planner也不支持BatchTableSource,而使用有界的StreamTableSource代替。

84 Table API/Flink SQL定义连接器的步骤?

定义连接器步骤:tableEnv.connect().withFormat().withSchema().createTemporaryTable("表名")

Table类型:1)从流转换;2)从表转换

可以从文件系统或者kafka中定义连接器读取数据

85 Table API/Flink SQL中的更新模式?

1)追加模式(Append Mode):在追加模式下,表(动态表)和外部连接器只交换插入(Insert)消息,比如文件系统、kafka。

2)撤回模式(Retract Mode):在撤回模式下,表和外部连接器交换的是:添加(Add)和撤回(Retract)消息。在此模式下,不能定义key。

3)Upsert(更新插入)模式:这个模式需要一个唯一的key,通过这个key可以传递更新消息。这种模式和Retract模式的主要区别在于,Update操作是用单个消息编码的,而Retract模式需要发送两条消息,所以Upsert模式效率会更高。

86 Table API/Flink SQL中如何设定process time或者event time?

1.处理时间:使用proctime替换或追加处理时间字段:

1)DataStream转化成Table时指定

2)定义Table Schema时指定

3)创建表的DDL中指定(必须使用blink planner运行)

2.事件时间:使用rowtime替换或追加处理时间字段:

1)DataStream转化成Table时指定

2)定义Table Schema时指定

3)创建表的DDL中指定(必须使用blink planner运行)

87 Table API/Flink SQL中如何实现分组窗口?

1.时间窗口:

    1)滚动窗口

    2)滑动窗口

    3)会话窗口

2.计数窗口:

    1)滚动窗口

    2)滑动窗口

3. 创建Table或表时需要指定时间字段,是事件时间(rowtime)还是处理时间(proctime)

    Table table = tableEnv.fromDataStream(sensorDS,"id,ts,temp,pt.proctime");

4. table API

1)tw.end,tw.start是窗口的开始时间和结束时间

2)groupBy后必须加上窗口别名,可以不加表的字段

3) table.window(Tumble.over("5.seconds").on("pt").as("tw")) seconds写单数或者复数都行

5.SQL

1)Tumble_end(pt,interval '5' second) 是窗口的结束时间

2)group by id,Tumble(pt,interval '5' second) 在group by 定义窗口大小,时间单位是单数,pt为定义的时间字段

88 Table API/Flink SQL中怎么实现开窗Over?

1.处理时间开窗:

处理时间开窗:order by(事件时间/处理时间) 和 as 是必须的,而partition by 和 preceding是可选的,preceding默认是上无边界,由于是按行开窗,所以是追加模式

 

2.事件时间开窗:

1)在hive中如果有 1,2,2,3,4,5几个数,对其进行开窗(按照数字排序),求和。

    row     window          sum

    1       1               1

    2       1,2,2           5

    2       1,2,2           5

    3       1,2,2,3         8

    4       1,2,2,3,4       12

    5       1,2,2,3,4,5     17

  注:开窗排序相同的数据会进入同一个窗口

2) 在时间语义为事件时间时进行开窗,只有watermark推进时才会进行计算,没有推进就不计算。当相同时间的多个数据到来时,由于watermark没有推进,所以不会触发计算,只有当新的watermark产生时才会计算。比如现在watermark为190,这时到来数据是(a,190)(b,190)(a,190) ,只有来了一条(a,191)数据时才会计算。

 

89 Table API/Flink SQL能够实现的自定义函数有标量函数(UDF)、聚合函数(UDAF)、表函数(UDTF)、表聚合函数的步骤?

1.标量聚合函数:UDF

1)自定义函数继承ScalarFunction

2)必须定义eval的方法,以便反射时调用

3)注册函数

4)使用函数跟系统内置函数一致

2.自定义表函数:UDTF,可以实现一行进,多行多列出,多列可以用元组类型表示;

 

3. 聚合函数UDAF:多进一出

注意导包:import org.apache.flink.table.functions.AggregateFunction;

1)继承AggregateFunction

2)自定义方法public void accumulate(Tuple2<Double, Integer> buffer, Double value) {

3)注册函数,使用函数

4)聚合结果必须使用toRetractStream输出

4. 表聚合函数:flatAggregate

实现求topN,sql方式无法使用表聚合函数,但是她不需要,他有rank。

1)自定义类继承TableAggregateFunction

2)定义两个方法

    public void accumulate(Tuple2<Double, Double> buffer, Double value) {}

     public void emitValue(Tuple2<Double, Double> buffer, Collector<Tuple2<Double, Integer>> collector) {}

3)注册函数

4)使用函数:group by 聚合-> flatAggregate 炸裂成表 -> select

5)由于是聚合结果所以需要使用toRetractStream输出

90 需求:统计最近10分钟内热门页面topN,每5秒钟统计一次?

数据来源:来自于Apache日志服务器。由于前端没有进行页面埋点,但是Apache服务器发送请求时有加载网络时发送的请求(加载图片,视频等),但是这些并不是用户点击产生的日志,可以使用正则表达式进行过滤(.png...等等)。如果有埋点日志肯定不使用Apache服务器产生的日志,请求主要是(GET/POST/PUT/DELETE),再这里简单的过滤GET请求的数据。

1.下面这种方式的问题:

由于数据观察到有1分钟左右的延迟,设置watermark延迟为1分钟,这非常不恰当。因为滑动步长为5秒,说明对实时性要求非常高,因此watermark的延迟可以设置为一个可以包含大部分数据延迟的情况,比如1秒。这样数据的准确性就会下降,但是没有办法,为了追求实时性准确性肯定会下降。当然也会有一部分数据丢失,为了保证数据不丢失可以使用允许迟到数据和侧输出流的方式保证结果的正确性。设置迟到数据1分钟。设置了1分钟的迟到数据,当watermark到达窗口时间就会触发计算,之后进行排序,然后清空状态。如果有迟到的数据,在迟到允许范围内就会再次注册定时器,添加到list状态中,这样数据就有问题,出现之前窗口的数据输出一次就丢失。

2.改进的思路是:

设置watermark最大乱序程度为1s,1分钟的允许迟到数据,清空状态的时间为在允许迟到的时间到时(比如1分钟)再清空状态。但是如果继续使用list保存状态就会出现问题,没有迟到的数据会统一保存一次状态,而迟到的数据每来一次保存一次,虽然之前的聚合状态还是正确的,但是list中存的数据就可能出现同一个url,保存多个count。需要使用map状态保存url和count值。

91 在事件时间语义下,什么数据进入侧输出流?什么情况下会丢失数据?

   网络延迟会导致数据在传输过程中发生乱序,因此使用事件时间语义真实反应数据产生时间。flink是一个流式处理框架,为了追求实时性,结果的正确性就会降低可以通过设置watermark最大乱序程度、允许迟到数据、以及输出到侧输出流的方式保证数据不丢失。

   1)watermark最大乱序程度的设置应该能够包含大部分迟到数据,设置的过大实时性降低,设置的过小正确性会降低。watermark到了窗口时间就会触发窗口计算。

   2)允许迟到数据,在迟到允许时间内到达的迟到数据还会和之前的窗口数据一起计算,只是每来一次就会计算一次,但是必须有watermark推进时才会触发计算;

   3)侧输出流:当迟到数据属于的所有时间窗口都关闭时就会进入侧输出流,只要有一个窗口没有关闭,就不会进入侧输出流。

   4)丢失数据的情况:

     4.1)滚动窗口:设置了侧输出流,对于输出到侧输出流迟到的数据直接分配到对应的窗口就行,不存在丢失数据的情况。

     4.2)滑动窗口:

        4.2.1)没有设置允许迟到数据,设置了侧输出流:不会丢失数据,对于输出到侧输出流迟到的数据直接分配到对应的窗口就行。

        4.2.2)设置了允许迟到数据,设置了侧输出流:会丢失数据,当迟到数据到来的时间大于A窗口允许迟到的时间,但是能够进入B窗口,那么数据就不会进入侧输出流,对于A窗口来说数据就丢失了,最终结果的正确性就会下降。

 

92 需求:统计每小时内的网站PV,pv是用户每点击一次页面都算一次点击量?(二次聚合,防止数据倾斜)

主要思路:

1.数据来源:日志服务器产生的用户行为数据,已经做了ETL,时间有序,过滤出pv数据;

2.过滤出pv,设置dummy key ,设置窗口大小为1小时,使用sum聚合(或reduce聚合,可以加上窗口信息),输出存在的问题:由于设置了同一个key,所以会发生数据倾斜,所有数据都发往同一个slot上。

解决思路:

    1)根据并行度,随机产生key,比如(0,最大并行度),添加上窗口信息,聚合;

    2)按照窗口结束时间分组,再次聚合,输出窗口内的数据。

93 需求:恶意登录检测,如果用户连续两秒内登录失败超过2次,就认为恶意登录?

错误1:

整体思路:按照用户分组,实现process API

    1.定义状态保存用户登录失败,定义状态保存定时器注册时间

    2.如果有登录成功的消息,就清空状态和删除定时器;

    3.对于第一条失败的登录,注册定时器,并保留状态

    4.等到定时器触发时,判断保存的状态是否大于2,如果大于,输出恶意登录警告

存在的问题:如果黑客在1秒内连续失败1万次,终于在1.99s时登录成功,这时就删除定时器和清空状态,不会输出报警信息。

进阶2:不定义定时器,当收到第二条失败信息时判断两条失败的信息的时间差是否小于2秒,如果小于就输出报警信息。当有登录成功的信息就清空状态。

存在的问题:如果需求更改为两秒内失败登录超过5次,实现的逻辑就非常复杂,当到来了失败消息,需要与第一条失败消息判断是否小于2秒钟,如果不小于就删除第一条失败消息,且依次判断第二条,第三条。实现的逻辑就非常复杂。

进阶3:使用CEP匹配复杂事件

    1)CEP会根据定义的模式序列,实现状态的管理,CEP底层的实现就是非限制性有限状态机(NFA)实现对状态的管理。

    2)CEP也会根据watermark,处理延迟数据/乱序数据,只有watermark推进时才会将watermark到达的时间点的数据匹配到流中。

    3)java中泛型方法的泛型写在方法名的前面

 

注意:.times(2)  //循环两次,且默认是宽松近邻

     .consecutive(); //指定循环模式是严格近邻

94 需求:统计最近一小时,各省份页面广告点击量统计,每5秒钟统计一次,对重复点击广告超过100次的用户拉入黑名单?

整体思路:

    1.观察数据源:发现数据的时间戳是升序的,都指定生成watermark为升序,不设置最大乱序程度。

    2.自定义process过滤,黑名单判断:按照用户和广告分组,计算用户是否点击同一条广告超过100次,如果超过拉入黑名单即输出到侧输出流

    3.按照省份分组,开滑动窗口,统计广告点击次数,补充窗口信息

注意:侧输出流必须加{},new OutputTag<BlackListWarning>("outPut"){}

95 需求:市场营销需求:统计最近一小时各渠道用户行为次数,每隔5秒展示一次?

数据来源:自定义source,产生数据

整体思路:按照渠道和行为进行分组,滑动窗口,使用aggregate,附带窗口信息

96 需求:使用flink进行双流连接,判断支付和到账能够连接上?

背景:对于订单支付事件,用户支付完成其实并不算完,我们还得确认平台账户上是否到账了。而往往这会来自不同的日志信息,所以我们要同时读入两条流的数据来做合并处理。这里我们利用connect将两条流进行连接,然后用自定义的CoProcessFunction进行处理。

整体思路:使用connect的方式

    1.读取两条流,使用connect进行连接,connect可以连接类型不同的两条流;而union只能连接相同类型的流。

    2.实现coMap中的两个方法,保存相应的状态;

        1)对于订单事件(pay),判断账单是否存在状态中,如果存在状态中,则证明关联上进行输出,否则,注册定时器,比如5秒

        2)对于账单事件,判断订单是否存在状态中,如果存在状态中,则证明关联上进行输出,否则,注册定时器,比如3秒

        3)按理说pay需要等待账单的时间长一些。

    3.当定时器响时,判断状态,

        1)如果订单状态不为空,则说明账单没有到,输出侧输出流中,标记为有订单没账单。

        2)如果订单状态为空,则说明账单不为空,输出到侧输出流中,标记为有账单没订单。

整体思路:使用join的方式,存在的问题就是如果没有join上的数据会丢失,而connect可以输出到侧输出流中。

    1.读取两条流,使用join进行连接

    2.between默认是左闭右闭,可以使用参数进行闭开的调整。

    3.join的两条流必须是keyBy之后的流。

存在的问题:由于是从文本文件中读取数据,而watermark默认是生成周期是200ms生成一个,文本文件读取过快,会出现,本不应该join上的数据join上了。但是在实际生产中不会出现这种情况。而join的方式是严格按照时间进行join,不会出现乱join的问题,只不过缺陷就是没有join上的数据会发生丢失。

97 需求:订单超时统计,15分钟算作超时,使用CEP筛选出超时的订单?

背景:为什么使用Flink做订单超时的检测?主要目的就是为了减轻业务系统的压力,对于订单超时的检测不是业务系统的核心任务,业务系统需要不停的轮循判断订单是否超时,消耗性能,因此,可以将这部分业务抽离出来,交给大数据实时处理,如果订单超时或完成订单,大数据可以直接修改数据库中的订单状态。业务系统直接获取数据即可。

整体思路:使用CEP

    1.数据来源:文本文件,没有乱序数据

    2.使用CEP定义模式序列,应用到流上(经过keyBy,按照orderId),使用select拣选超时事件与匹配事件,分别进行处理,超时事件输出到侧输出流中。

    3.使用宽松近邻定义模式序列,因为订单的创建和支付之间可能会穿插其他事件。

    4.java的泛型方法是写在方法名前

    5.CEP可以作用的流可以是普通流,也可以是keyBy之后的流。具体要根据逻辑选择,这里只有同一个订单的事件匹配才有意义。

整体思路:使用ProcessAPI

    1.读取数据,提取事件时间戳后,按照OrderId进行分组,自定义Process API

    2.主要分为3种情况

       1)定义值状态,保存create,并注册15分钟定时器。

       2)如果15分钟内pay过来,判断是否有create

            2.1)如果有,输出数据,并删除定时器,清空状态。

            2.2)如果没有,输出到侧输出流,正常逻辑不应该出现有pay而没有create的情况。由于是自己造的数据,所以可能会出现这种情况

总结:Process API能够实现的逻辑会比CEP更加全面,可以将有问题的数据输出到侧输出流,而CEP就不能实现,但是CEP能够自己管理状态,代码逻辑简单。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值