Flink诞生于欧洲的一个大数据研究项目 StratoSphere。该项目是柏林工业大学的一个研究性项目。早期,Flink是做 Batch 计算的,但是在 2014 年,StratoSphere 里面的核心成员孵化出Flink,同年将 Flink 捐赠 Apache ,并在后来成为 Apache 的顶级大数据项目,同时 Flink 计算的主流方向被定位为 Streaming,即用六十计算来做所有大数据的计算,这就是 Flink 技术 诞生的背景。
官网: https://flink.apache.org/
核心理念:Apache Flink 是为分布式、高性能、岁时可用以及准确的刘处理应用程序打造的开源流处理框架。
**Apache Flink是一个面向分布式数据流处理和批量数据处理的开源计算平台,它能够基于同一个 Flink 运行时(Flink Runtime),提供支持流处理和批处理两种类型应用的功能。**现有的开源计算方案,会把流处理和批处理作为两种不同的应用类型,因为他们所提供的SLA是完全不相同的: 流处理一般需要支持低延迟、Exactly-once 保证,而批处理需要支持高吞吐、高效处理,所以在实现的时候通常是分别给出两套实现方法,或者通过一个独立的开源框架来实现其中每一种处理方案。例如,实现批处理的开源方案有 MapReduce、Tez、Crunch、Spark,实现流处理的开源方案有Samza、Storm。
Flink 在实现流处理和批处理时,与传统的一些方案完全不同,它从另一个视角看待流处理和批处理,将二者统一起来:**Flink是完全支持流处理,也就是说作为流处理看待时输入数据是无界的;批处理被作为一种特殊的流处理,只是它的输入数据流被定义为有界的。** 基于同一个Flink 运行时(Flink Runtime),分别提供了流处理和批处理 API,而这两种API 也是实现上层面向流处理、批处理类型应用框架的基础。
总的来说,现有的开源计算方案,会把流处理和批处理作为两种不同的应用类型,因为它们所提供的SLA(Service-Level-Aggreement,服务等级协议)是完全不相同的:
Flink 从另一个视角看待流处理和批处理,将二者统一起来:
Flink 能够支持 YARN,能够从HDFS 和 HBase 中获取数据
能够使用所有的 Hadoop 的格式化输入和输出
能够使用 Hadoop 原有的 Mappers 和 Reducers,并且能与 Flink 的操作混合使用
能够更快的运行 Hadoop 作业
流场景使用案例 | 正确性保证 | API 分层体系 |
---|---|---|
1、数据驱动的应用 2、批/流数据分析 3、数据通道和ELA | 1、Exactly-once 状态一致性保证 2、事件时间处理 3、复杂的late date处理 | 1、统一SQL支持 Stream 和 Batch 数据处理 2、DataStream API & DataSet API 3、ProcessFunction(Time & State) |
操作重点 | 适用于各种应用场景 | 高性能 |
1、部署灵活 2、高可用配置 3、Savepoints | 1、架构可扩展 2、超大 state 支持 3、增量 checkpointing | 1、低延迟 2、高吞吐 3、内存计算 |
Flink 最适合的应用场景是低延迟的数据处理场景:高并发处理数据,时延毫秒级,且兼具可靠性。
典型应用场景有互联网金融有任务、点击流日志处理、舆情监控。
Flink 的典型功能:
Flink 非常适合于:
从上图中可以了解到 Flink 几个最基础的概念,Client、JobManager 和 TaskManager 。Client用来提交任务给 JobManager,JobManager 分发任务给TaskManager 去执行,然后 Taskmanager会心跳的汇报任务状态。对Flink而言,可能是很多级,并且在 Taskmanager 内部和 TaskManager 之间都会有数据传递。
Flink 是一个分布式的主从架构,即 集群运行时是由主节点和从节点组成。Flink 的分布式执行包括两个重要的进程:Master 和 Worker。执行 Flink 程序时,多个进程参与执行,即作业管理器(JobManager),任务管理器(TaskManager)和作业客户端(JobClient)。
Flink 程序需要提交给 Job Client。然后,JobClient 将作业提交给 Job Manager。JobManager 负责协调资源分配和作业执行。它首先要做的是分配所需的资源。资源分配完成后,任务将提交给相应的TaskManager。在接受任务时,TaskManager 启动一个线程以开始执行。执行到位时,TaskManager 会继续向 JobManager 报告状态更新。可以有各种状态,例如开始执行,正在进行或以完成。作业执行完成后,结果将发送回客户端(JobClient)。
每个 worker(TaskManager)都是一个 JVM 进程,可以在单独的线程中执行一个或多个子任务 task。为了控制 worker 接受多少task,worker 具有所谓的 task slot(至少一个)。
每个 task slot 表示 Task Manager 资源的一个固定自己。例如,一个有三个slots 的 Taskmanager 会将其 1/3 的托管内存分配给每个插槽。对资源进行插槽管理意味着子任务不会与来自其他作业的子任务争夺托管内存,而是拥有一定数量的预留托管内存。注意,这里没有发生 CPU 隔离;当前插槽只分割任务的托管内存。
通过调整任务槽的数量,用户可以定义子任务如何彼此隔离。每个 TaskManager 有一个插槽意味着每个人物组运行在单独的 JVM中(例如,可以在单独的容器中启动JVM)。拥有多个插槽意味着更多的子任务共享同一个JVM。相同 JVM中的任务共享 TCP连接(通过多路复用)和心跳消息。 它们还可以共享数据集和数据结构,从而减少每个任务的开销。
默认情况下,Flink 允许子任务共享插槽,即使它们是不同任务的子任务,只要它们来自相同的作业。结果是一个可以容纳作业的整个管道。允许这个插槽共享有两个主要好处:
对于分布式执行,将操作符子任务一起链接到任务中。每个任务由一个线程执行。将操作符链接到任务中是一种有用的优化:它减少了线程到线程切换和缓冲的开销,增加了总体吞吐量,同时降低了延迟,可以对链接行为进行配置。下图中的实例数据流使用 5 个子任务执行,因此使用5个并行线程。
Flink 具有分层架构,其中每个组件都是特定层的一部分。每个层都建立在其他层之上,以实现清晰的抽象。Flink 旨在本地,YARN 集群或云上运行。Runtime 是 Flink 的核心数据处理引擎,它通过 JobGraph 形式的 API 接受程序,在执行 JobGraph 时,Flink 提供了多种候选部署方案(如 local,remote,YARN 等)。JobGraph 即为一个一般化的并行数据流图(data flow),它拥有任意数量的Task 来接收和产生data stream。
Datastream 和 DataSet API 是程序员可用于定义 Job 的接口。编译程序时,这些API 会生成 JobGraphs。编译后,DataSet API 允许优化器生成最佳执行计划,而 DataStream API 使用流构建来实现高效的执行计划。DataStream API 和 DataSet API 都会使用单独编译的处理方式生成 JobGraph。DataSet API 使用 optimizer 来决定针对程序的优化方法,而DataStream API 则使用stream builder 来完成该任务。
然后根据部署模型将优化的 JobGraph 提交给执行程序。可以选择本地,远程或 YARN 部署模式。如果已经运行了 Hadoop 集群,那么最好使用 YARN 部署模式。
Flink 附随了一些产生DataSet或DataStream API 程序的类库和API :处理逻辑表查询的Table,机器学习的FlinkML ,图像处理的 Gelly,复杂事件处理的CEP。
在批处理过程中,数据是划分为块分片去完成的,然后每一个Task 去处理一个分片。当分片执行完成后,把输出聚合起来就是最终的结果。在这个过程当中,对于 state 的需求还是比较小的。在流计算过程中,对 State 有非常高的要求,因为在流系统中输入是一个无限制的流,会持续运行从不间断。在这个过程当中,就需要将状态数据很好的管理起来。Flink 的失败恢复依赖于“检查点机制+可部分重发的数据源”。检查点机制:检查点定期触发,产生快照,快照中记录了:(1)当前检查点开始是数据源(例如Kafka)中消息的offset (2)记录了所有状态的 operator 当前的状态信息(例如 sum 中的数值)。可部分重发的数据源:Flink 选择最近完成的检查点 K。然后系统重放整个分布式的数据流,然后给予每个 operatpr 他们在检查点 k 快照中的状态。数据源被设置为从位置 Sk 开始重新读取流。例如在 Apache Kafka 中,那意味着告诉消费者从偏移量 Sk 开始重新消费。Flink 中有两种基本类型的State,即 Keyed State 和 Operator State。State 可以被记录,在失败的情况下数据还可以恢复。state 一般指一个具体的 task / operator 的状态(state 数据默认保存在 JVM 的堆内存中)
我们写的 wordcount 的程序没有包含状态管理。如果一个 task 在运行中挂掉了,那么它在内存当中的状态数据都会丢失。所有的数据都需要重新计算。从容错和消息处理的语义上,Flink 引入了 State 和 CheckPoint
首先区分两个概念:
State 可以被记录,这样可以在失败的情况下进行恢复
Flink 中有两种State
KeyedState 和 OperatorState 都有两种形式存在
原始状态 RawState
原始状态,是由用户自行管理状态具体的数据结构,框架在做 checkpoint 的时候,使用 byte[] 来读写内容,对其内部数据结构一无所知
托管状态 managedState
托管状态是由 Flink 框架管理的状态
通常,在 DataStream 上的状态,推荐使用托管的状态,当实现一个用户自定义的 Operator 的时候,会使用到原始状态
checkpoint (可以理解为 checkpoint 是把 state 数据持久化存储了),则表示了一个Flink Job 在一个特定时刻的一份全局状态快照,即包含了所有task/operator 的状态
CheckPoint 是 Flink 容错的主要机制。它不断为分布式数据流和 executor 状态拍摄快照。它的思想来自 Chandy-Lamport 算法,但已根据 Flink 的定制要求进行了修改。
Flink 基于 Chandy-Lamport 算法实现了一个分布式的一致性快照,从而提供了一致性的语义。
Chandy-Lamport 算法实际上在 1985 年的时候已经被提出来,但并没有被很广泛的应用,而 Flink 则把这个算法发扬光大了。Spark 最近在实现 Continue streaming,Continue streaming 的目的是为了降低它处理的掩饰,其也需要提供这种一致性的予以。最终采用 Chandy-Lamport 这个算法,说明 Chandy-Lamport 算法在业界得到了一定的肯定。
每个快照状态都会报告给 Flink 作业管理器(JobManager)的检查点协调器。在制作快照时,Flink 处理记录对齐,以避免因任何故障而重新处理相同的记录。这种对齐通常需要几毫秒。但是对于某些要求高的应用程序,即使毫秒级的延迟也是不可接受的,我们可以选择在单个记录处理中选择低延迟。默认情况下,Flink 只处理每个记录一次。如果任何应用程序需要低延迟并且至少在一次交付就可以,我们可以关闭该触发器。这将跳过对齐并将改善延迟。
容错:checkpoint 是很重要的机制,因为 Flink 的检查点是通过分布式快照实现的,所以这里对快照和检查点不进行区分。
分布式数据流的轻量级异步快照
分布式有状态流处理支持在云中部署和执行大规模连续计算,同时针对低延迟和高吞吐量。这种模式最基本的挑战之一是在潜在的失败下提供处理保证。现有方法依赖于可用与故障恢复的周期性全局状态快照。这个方法有两个主要缺点。首先,它们经常会停止影响摄取的整体计算。其次,他们急切地坚持传输中的所有记录以及操作状态,这导致比所需更快的快照。**在这项工作中,提出了异步屏障快照(ABS),这是一种适用于现代数据流执行引擎的轻量级算法,可最大限度地减少空间需求。ABS 仅保留非循环执行拓扑上的运算符状态,同时保持循环数据流额最小记录日志。**我们在 Apache Flink 上实现了 ABS,这是一个支持有状态流处理的分布式分析引擎。我们的评估表明,我们的算法对执行没有太大的影响,保持线性可扩展性并且在频繁的快照中表现良好。
分布式快照的核心概念之一是 barriers。这些 barriers 被注入数据流并与记录一起作为 数据流的一部分向下流动。 barriers 永宣不会超过记录,数据流严格有序。barriers 将数据流中的记录分为进入当前快照的记录和进入下一个快照的记录。每个barriers 都带有快照的ID,并且barriers 之前的记录都进入了该快照。barriers 不会中断流的流动,非常轻量级。来自不同快照的多个 barriers 可以同时在流中出现,这意味着可以同时发生各种快照。
**流 barriers 是 Flink 快照的核心要素。它们被摄取到数据流中而不会影响流量。barriers 永远不会超过记录。他们将记录集合分为快照。每个 barriers 都带有唯一的 ID。**下图显示了如何 将 barriers 注入到快照的数据流中:
基于上图:
Barrier 分为两类:
BarrierBuffer 通过阻塞已接收到barrier 的 input channel 并缓存被阻塞的channel 中后续流入的数据流,直到所有的 barrier 都接收到或者不满足特定的检查点的条件后,才会释放这些被阻塞的channel ,这个机制被称之为-aligning(对齐)。正是这种机制来实现 EXACTLY_ONCE的一致性(它将检查点中的数据精准的隔离开)。
而 Barrier Track 的实现就要简单地多,它仅仅是对数据流中的 barrier 进行跟踪,但是数据流中的元素 buffer 是直接放行的。这种情况会导致同一个检查点中可能会预先混入后续检查点的元素,从而只能提供 AT_LEAST_ONCE 的一致性。
Snapshot 并不仅仅是对数据流做了一个状态的 Checkpoint,它也包含了一个 Operator 内部所持有的状态,这样才能够在保证在流处理系统失败时能够正常地恢复数据流处理。
barrier 作用:它会作为数据流的记录被同等看待,被插入到数据流中,将数据流中记录的进行分组,并沿着数据流的方向向前推进
具体排列过程如下: