Flink提供不一样级别的抽象来开发流/批处理应用程序。html
Statefule Stream Processing: 是最低级别(底层)的抽象,只提供有状态的流。它经过ProcessFunction嵌入到DataStream API之中。它使得用户能够自由处理来源于一个或者多个流的事件数据库
DataStream/DataSet API: 在咱们的实际工做中,大多数的应用程序是不须要上文所描述的低级别(底层)抽象,而是相对于诸如DataStream API(有界/无界流)和DataSet API(有界数据集)的Core API进行编程。这些API提供了用于数据处理的通用模块,如各类指定的transformations, joins, aggregations, windows, state等。在API中,这些处理的数据类型都是一个具体的实体类(class)。apache
底层的Process Function与DataStream API集成在一块儿,能够仅对一些操做进行底层抽象。编程
Table API: 是围绕着table的申明性DSL,能够被动态的改变(当其表示流时)。Table API遵循(扩展)关系模型:表有一个模式连接(相似与在关系数据库中的表),API也提供了一些相似的操做:select, project, join, group-by, aggregate等。Table API程序申明定义了怎么作是规范的,而不是明确指定应该是什么样子的。虽然Table API能够经过各类类型的用户定义的函数进行扩展,但它比Core API表达的更少,但使用起来更简洁(少写代码)。另外,Table API程序也会经过一个优化器,在执行以前应用优化规则。windows
能够在表和DataStream / DataSet之间进行无缝转换,容许程序混合使用Table API和DataStream 和DataSet API。session
Flink提供的最高级抽象是SQL。 这种抽象在语义和表现力方面与Table API相似,可是将程序表示为SQL查询表达式。在SQL抽象与Table API紧密地相互做用,另外,SQL查询能够在Table API中定义的表上执行。数据结构
Flink能够说是由流(streams)和转换(transformations)为基础构建的(请注意,Flink的DataSet API中使用的数据集也是内部的流 )。从概念上讲,流是数据记录(多是永无止境的)流,而转换是将一个或多个流做为输入,并产生一个或多个输出流。函数
执行时,Flink程序被映射到由流和转换运算符组成的流式数据流。每一个数据从一个或多个源(sources)开始,并在一个或者多个接收器(sinks)中结束。数据流相似于一个任意有向无环图(DAG)。尽管经过迭代构造容许特殊形式的循环,可是为了简单起见,咱们姑且先忽视这种状况。优化
程序中的转换与数据流中的操做符一般是一一对应的。然而,有时候,一个转换可能由多个转换操做符组成。线程
信号源(sources)和接收器(sinks)记录在流式链接器和批量链接器文档中。DataStream运算符和DataSet转换中记录了转换。
Flink中的程序本质上是并行和分布的。在执行过程当中,一个流有一个或者多个流分区,每一个运算符有一个或者多个子任务。操做符子任务彼此独立,而且在不一样的线程中执行,而且可能在不一样的机器或容器上执行。
操做符子任务的数量是该特定操做符的并行度。流的并行性老是由生产它的操做符决定。同一个程序的不一样运算符可能有不一样的并行级别。
流能够以一对一(One-to-one)或者从新分配(Redistributing)的模式在两个操做符之间传输:
One-to-one: 保留了元素的分区和顺序,如上图中source —>map。这意味着map运算符的subtask[1]将按照源运算符的subtask[1]所产生顺序相同。
Redistributing: 如上图所示,map和keyBy/window之间,以及keyBy/window和Sink之间从新分配流,将会改变流的分区。每一个操做符子任务根据所选的转换将数据发送到不一样的目标子任务。好比 keyBy()(其经过哈希从新分区),broadcast(), or rebalance() (其随机从新分区)。在从新分配 交换中,元素之间的排序只保存在每对发送和接收的子任务中(例如map() 的subtask[1] 和 keyBy /window的subtask [2])。因此在这个例子里,每一个关键字中的排序都被保留下来,可是并行性确实形成了不一样关键字汇总结果后顺序的非肯定性。
有关配置和控制并行的细节能够在并行执行的文档中找到。
聚合事件(如:sum,count,etc)在流上的工做方式与批处理中的不一样。例如,咱们不可以去统计流中的全部元素,由于流通常是无限的(无界的)。于是,流中的一些aggregate操做,是由Windows控制的,例如:计算过去五分钟或者最后100个元素的总和。
Windows能够是由时间驱动的(例如,每30秒)或者数据驱动(例如每100个元素)。这能够用来区分不一样类型的Windows,例如:tumbling windows (no overlap), sliding windows (with overlap), and session windows (punctuated by a gap of inactivity).
更多的窗口示例能够在这篇博客文章中找到。更多细节在窗口文档。
当咱们在流式编程中谈及时间时,能够参考不一样的时间概念:
Event Time, 是事件建立的时间,一般用时间戳表示。Flink经过时间戳分配器来访问事件时间戳。
Ingestion time, 是事件进入Flink的时间,在源操做中每一个记录都会得到源的当前时间做为时间戳,后续基于时间的操做(如: time window)会依赖这个时间戳
Processing Time, 是指each operator 执行程序时对应的物理机的系统时间
有关如何处理时间的更多细节,请参阅event time 文档。
尽管数据流中不少操做看起来像一个单独的事件,可是一些操做会跨越几个事件记下相关的的信息(好比像window operators)。这种操做被称为有状态的(stateful)。
这种有状态的操做,被保存在一种key/value的存储结构之中。状态与有状态操做符读取的流严格分区和分配。只有在keyed()函数以后才能访问key/value状态。而且仅限于与当前事件的键相关的值。流和状态的keys的匹配保证了全部状态更新都是本地操做,保证了一致性,因此不须要事务的开销。这种匹配还容许flink从新分配状态,并公开的调整分区。
有关更多信息,请参阅有关状态的文档。
Flink使用流重播(stream replay) 和 检查点(checkpointing) 的组合来实现容错。检查点与每一个输入流中的特定点以及每一个操做元的相应状态有关。数据流能够从检查点恢复,同时保持一致性(exactly-once processing语义),方法是恢复operators 的状态并从检查点重放事件。
检查点间隔是在执行恢复时间(须要被重放的事件的数量)的状况下折衷的容错开销手段。
容错内部的描述提供了有关Flink如何管理检查点和相关主题的更多信息。有关启用和配置检查点的详细信息位于检查点API文档中。
Flink执行批处理程序做为流程序的特殊状况,它是有限的(元素是有限的)。ADataSet 在内部视为数据流。所以,上述概念一样适用于批处理程序,就像适用于流式处理程序同样,但有一点例外:
批处理程序的容错不使用检查点。经过彻底重放流来恢复。这是可能的,由于输入是有限的。这将成本更多推向recovery,可是使常规地处理更便宜,由于它避免了检查点。
DataSet API中的有状态操做使用简化的内存/外核数据结构,而不是键/值索引。
DataSet API引入了特殊的同步(超级)iterations,这只能在有界的流上进行。有关详细信息,请查看iterations文档。