欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

数据流编程模型v1.4

程序员文章站 2022-04-12 19:58:10
数据流编程模型 抽象级别程序和数据流并行数据流窗口时间有状态操作检查点(checkpoint)容错批量流处理下一步 抽象级别 flink针对 流式/批处理 应用提供了不同的抽象级别。...

数据流编程模型

抽象级别程序和数据流并行数据流窗口时间有状态操作检查点(checkpoint)容错批量流处理下一步

抽象级别

flink针对 流式/批处理 应用提供了不同的抽象级别。

数据流编程模型v1.4

 

这个最低级别的抽象提供了有状态的流式操作。它是通过处理函数嵌入到DataStream API。它允许用户*的处理一个或者多个数据流中的事件,并且使用一致,容错的状态。此外,用户可以注册回调事件时间和处理时间,允许程序实现复杂的计算。实际上,大多数应用不需要上面描述的低级别抽象,而是针对Core APIs(核心API),例如:?DataStream API(有边界和无边界的数据流) 和?DataSet API(有边界的数据集)。这些流畅的API提供通用数据处理,像用户指定的各种形式的transformations(转化),joins(连接),aggregations(聚合),windows(窗口化操作),state(状态)等等。这些API表示在各自的编程语言中为类(class)中的数据类型进行处理。

低阶的处理函数集成了DataStream API,这样就可以针对特性的操作使用低层级的抽象。DataSet API 为有边界的 data sets提供了附加的原语,例如循环/迭代。Table API 是一种声明式的DSL环绕表,它可能会被动态的改变(当处理数据流的时候)。Table API?遵循扩展模型:Table 有一个附加模式(类似于关系型数据库表)并且API提供了类似的操作,例如:select,project,join,group-by,aggregate等等。Table API声明式的定义了 逻辑操作应该怎么做 而不是确切的指定 操作的代码看起来如何。尽管table API是可扩展的通过用户各种形式的自定义函数,它的表现还是不如Core APIs,但是用起来更加的简洁(写更少的代码)。此外,table API 还可以执行一个优化器,适用于优化规则之前执行。

table和dataStream/dataSet之间可以无缝的转换,允许程序组合使用table api和dataStream和dataSet的API。Flink*别的抽象是sql。这种抽象类似于table API 在语义和表达上面,但代表程序SQL查询表达式。SQL抽象与table API 紧密联系在一起,sql查询可以在table API定义的表中执行。

程序和数据流

Flink程序的基本构建模块是streams(流)和transformations(转换)。(需要注意的是,flink的dataSet API所使用的DataSets内部也是流-更多内容将在以后解释)。从概念上讲流(可能没有结束)是一个数据流记录,而转换是一个操作,它取一种或者多种流作为输入,并产生一个或者多个输出流作为结果。

当执行的时候,flink程序映射到streaming dataflows(流数据流),由streams和转换operators组成。每一个数据流开始于一个或者多个source,并且终止于一个或者多个sink。数据流类似于任意的 有向无环图(DAGS)。虽然通过迭代构造运行特定形式的环,但是大多数情况下,简单起见,我们都不考虑这一点。

数据流编程模型v1.4

通常情况下,程序中的转换与数据流中的操作是一一对应的。有时,然而,一个转换可能有多个转换操作构成。

source和sink的文档在streaming connectors 和 batch connectors 。transformation的文档在dataStream operators和dataSet transformation。

并行数据流

Flink程序本质上是并行的和分布式的。在执行过程中,一个流(stream)包含一个或多个流分区 ,而每一个operator包含一个或多个operator子任务 。操作子任务间彼此独立,以不同的线程执行,甚至有可能运行在不同的机器或容器上。

operator子任务的数量即这一特定operator的并行度 。一个流的并行度即其生产operator的并行度。相同程序中的不同的operator可能有不同级别的并行度。

数据流编程模型v1.4

流在两个operator之间传输数据,可以通过一对一(或称 forwarding )模式,或者通过redistributing模式:

一对一流(例如上图中Source与map() opreator之间)保持了元素的分区与排序。那意味着 map() operator的子任务[1]将以与 Source 的子任务[1]生成顺序相同的顺序查看到相同的元素。
Redistributing 流(如上图中 map() 与 keyBy/window 之间,以及 keyBy/window 与 Sink 之间)则改变了流的分区。每一个operator子任务 根据所选择的转换,向不同的目标子任务发送数据。比如 keyBy() (根据key的哈希值重新分区), broadcast() ,或者 rebalance() (随机重分区)。在一次 redistributing 交换中,元素间的排序只保留在每对发送与接受子任务中(比如, map() 的子任务[1]与 keyBy/window 的子任务[2])。因此在这个例子中,每个键的顺序被保留下来,但是并行确实引入了对于不同键的聚合结果到达sink的顺序的不确定性。

窗口

聚合事件(比如计数、求和)在流上的工作方式与批处理不同。比如,对流中的所有元素进行计数是不可能的,因为通常流是无限的(*的)。相反,流上的聚合需要由 窗口 来划定范围,比如 “计算过去的5分钟” ,或者 “最后100个元素的和” 。

窗口可以是 事件驱动的 (比如:每30秒)或者 数据驱动的 (比如:每100个元素)。窗口通常被区分为不同的类型,比如 滚动窗口 (没有重叠), 滑动窗口 (有重叠),以及 会话窗口 (由不活动的间隙所打断)

数据流编程模型v1.4

时间

当提到流程序(例如定义窗口)中的时间时,你可以参考不同的时间概念:

事件时间 是事件创建的时间。它通常由事件中的时间戳描述,例如附接在生产传感器,或者生产服务。Flink通过时间戳分配器访问事件时间戳。
摄入时间 是事件进入Flink数据流源算符的时间。
处理事件 是每一个执行时间操作的operator的本地时间。

数据流编程模型v1.4

有状态操作

尽管数据流中的很多操作一次只查看一个独立的事件(比如事件解析器),有些操作却会记录多个事件间的信息(比如窗口算符)。 这些操作被称为 有状态的 。

有状态操作的状态保存在一个可被视作嵌入式键/值存储的部分中。状态由有状态operator读取的流一起被严格地分区与分布。因此,只能访问一个 keyBy() 函数之后的 keyed streams 的键/值状态,并且仅限于与当前事件键相关联的值。调整流和状态的键确保了所有状态更新都是本地操作,以在没有事务开销的情况下确保一致性。这种对齐还使得Flink可以透明地重新分配状态与调整流的分区。

数据流编程模型v1.4

检查点(checkpoint)容错

Flink使用 流重放 与 检查点 的结合实现了容错。检查点与每一个输入流及其相关的每一个算符的状态的特定点相关联。一个数据流可以从一个检查点恢复出来,其中通过恢复operator状态并从检查点重放事件以保持一致性 (一次处理语义)

检查点间隔是以恢复时间(需要重放的事件数量)来消除执行过程中容错的开销的一种手段

容错内部的描述提供了更多关于flink管理检查点和相关的话题。启用和配置检查点的详细信息请查看这个文档checkpointing API docs。

批量流处理

Flink将批处理程序作为流处理程序的特殊情况来执行,只是流是有界的(有限个元素)。 DataSet 内部被视为数据流。上述适用于流处理程序的概念同样适用于批处理程序,除了一些例外:

批处理程序的容错不再使用检查点。而是通过完全地重放流来恢复。因为输入是有界的,因此这是可行的。这种方法使得恢复的成本增加,但是由于避免了检查点,因而使得正常处理的开销更小。
DataSet API中的有状态操作使用简化的im-memory/out-of-core数据结构,而不是键/值索引。
DataSet API引入了特殊的同步(superstep-base)迭代,而这种迭代仅仅能在有界流上执行。细节可以查看迭代文档。

下一步

继续学习Flink的分布式运行时的基本概念