Flink提供了不一样级别的抽象来开发流/批处理应用程序。数据库
1) 低层级的抽象
最低层次的抽象仅仅提供有状态流。它经过Process函数嵌入到DataStream API中。它容许用户自由地处理来自一个或多个流的事件,并使用一致的容错状态。此外,用户能够注册事件时间和处理时间回调,容许程序实现复杂的计算。编程
2) 核心APIapi
在实践中,大多数应用程序不须要上面描述的低级抽象,而是对核心API进行编程,好比DataStream API(有界或无界数据流)和DataSet API(有界数据集)。这些API提供了用于数据处理的通用构建块,好比由用户定义的多种形式的转换、链接、聚合、窗口、状态等。在这些api中处理的数据类型以类(class)的形式由各自的编程语言所表示。
低级流程函数与DataStream API集成,使得只对某些操做进行低级抽象成为可能。DataSet API为有界数据集提供了额外的原语,好比循环或迭代。数据结构
3) Table API编程语言
Table API是一个以表为中心的声明性DSL,其中表能够动态地改变(当表示流数据时)。表API遵循(扩展)关系模型:表有一个附加模式(相似于关系数据库表)和API提供了相似的操做,如select, project, join, group-by, aggregate 等。Table API 程序以声明的方式定义逻辑操做应该作什么而不是指定操做的代码看起来如何。虽然Table API能够经过各类用户定义函数进行扩展,但它的表达性不如核心API,但使用起来更简洁(编写的代码更少)。此外,Table API程序还能够在执行以前经过应用优化规则的优化器。能够无缝地在Table API和DataStream/DataSet API之间进行切换,容许程序将Table API和DataStream和DataSet API进行混合使用。分布式
4) Sql层
Flink提供的最高级别抽象是SQL。这种抽象在语义和表示方面都相似于Table API,但将程序表示为SQL查询表达式。SQL抽象与表API密切交互,SQL查询能够在表API中定义的表上执行。函数
Flink程序的基本构建模块是streams 和 transformations 。(请注意,Flink的DataSet API中使用的数据集也是内部流——稍后将对此进行详细介绍。)从概念上讲,streams 是数据记录的(多是无限的)流,而transformations是将一个或多个流做为输入并产生一个或多个输出流的操做。优化
执行时,Flink程序被映射到流数据流,由streams 和 transformations 操做符组成。每一个数据流以一个或多个sources开始,以一个或多个sinks结束。数据流相似于任意有向无环图(DAGs)。虽然经过迭代构造容许特殊形式的循环,但为了简单起见,咱们将在大多数状况下忽略这一点。spa
一般在程序中的transformations和数据流中的操做之间是一对一的对应关系。然而,有时一个transformations可能包含多个transformations操做。
在streming链接器和批处理链接器文档中记录了Sources 和 sinks。在DataStream运算和数据集transformations中记录了transformations。.net
Flink中的程序本质上是并行的和分布式的。在执行期间,流有一个或多个流分区,每一个operator 有一个或多个operator subtasks(操做子任务)。operator subtasks相互独立,在不一样的线程中执行,可能在不一样的机器或容器上执行。
operator subtasks的数量是特定运算符的并行度。一个流的并行性老是它的生产操做符的并行性。同一程序的不一样运算符可能具备不一样级别的并行性。
流能够在两个操做符之间以一对一(或转发)模式传输数据,也能够在从新分配模式中传输数据:
One-to-one 流(例如上图中Source和map()运算符之间的流)保持元素的分区和顺序。这意味着map()操做符的subtask[1]将看到与源操做符的subtask[1]生成的元素相同的顺序。
Redistributing 流(如上面的map()和keyBy/window之间,以及keyBy/window和Sink之间)改变流的分区。每一个操做符子任务根据所选的转换将数据发送到不一样的目标子任务。例如keyBy()(经过散列键来从新分区)、broadcast()或balanced()(随机从新分区)。在重分发交换中,元素之间的顺序只保留在每一对发送和接收子任务中(例如map()的子任务[1]和keyBy/window的子任务[2])。所以,在本例中,每一个键中的顺序都是保留的,可是并行性确实引入了关于不一样键的聚合结果到达sink的顺序的不肯定性。
聚合事件(例如计数、求和)在流上的工做方式与批处理不一样。例如,不可能计算流中的全部元素,由于流一般是无限的(无界的)。相反,流上的聚合(计数、求和等)是由窗口限定做用域的,例如“过去5分钟的计数”或“最后100个元素的总和”。
Windows能够是时间驱动(示例:每30秒)或数据驱动(示例:每100个元素)。一个典型的方法是区分不一样类型的窗口,好比翻滚窗户(没有重叠)、滑动窗口(有重叠)和会话窗口(中间有一个不活跃的间隙)。
当提到流程序中的时间(例如定义窗口)时,能够指不一样的时间概念:
虽然一个数据流中有许多操做但只看做一个单独的事件(例如事件解析器),可是一些操做记住了跨多个事件的信息(例如窗口操做符)。这些操做称为有状态操做。
有状态操做的状态被维护在能够认为是嵌入式键/值存储中。状态与有状态操做符读取的流一块儿被严格地分区和分布。所以,在keyBy()函数以后,只能在键控流上访问键/值状态,而且只能访问与当前事件的键相关联的值。对齐流和状态的键确保全部的状态更新都是本地操做,保证一致性而不增长事务开销。这种对齐还容许Flink透明地从新分配状态和调整流分区。
(EventTime是信息自带的时间,再进入消息队列,IngestionTime是进入Flink的时间,Processing是进入Operator的时间)
Flink经过流回放和检查点的组合实现了容错。检查点与每一个输入流中的特定点以及每一个操做符的对应状态相关。经过恢复操做符的状态并从检查点从新播放事件,流数据流能够在检查点恢复,同时保持一致性(准确地说是一次处理语义)。
检查点间隔是在执行期间用恢复时间(须要重放的事件数量)来权衡容错开销的一种方法。
Flink执行批处理程序做为流程序的特殊状况,其中流是有界的(有限的元素数量)。数据集在内部被视为数据流。所以,上述概念一样适用于批处理程序,也适用于流程序,但有少数例外: