Flink1.7之Dataflow编程模型

x33g5p2x  于2020-10-20 发布在 Flink  
字(3.4k)|赞(0)|评价(0)|浏览(910)

抽象层次

Flink提供了不同级别的抽象来开发流/批处理应用程序。

编程抽象层

  • 最低层次的抽象仅提供 有状态流. 它通过 Process Function嵌入到 DataStream API . 它允许用户自由处理来自一个或多个流的事件,并使用一致的容错 state。此外,用户可以注册事件时间和处理时间回调,允许程序实现复杂的计算。

  • 在实践中,大多数应用程序不需要上面描述的低级抽象,而是根据Core APIs编写程序,比如DataStream API(有界/无界流)和DataSet API(有界数据集)。这些连贯api为数据处理提供了通用的构建块,比如各种形式的用户指定的转换、连接、聚合、窗口、状态等。在这些api中处理的数据类型表示为各自编程语言中的类。

    低级的 Process Function 函数与 DataStream API 集成,使得仅对某些操作进行低级抽象成为可能。DataSet API 在有界数据集上提供了额外的原语,比如循环/迭代。

  • Table API 是一个以 tables 为中心的声明性DSL,它可以动态地更改表(在表示流时)。Table API遵循(扩展的)关系模型:表具有附加的模式(类似于关系数据库中的表),API提供了类似的操作,如select、project、join、group-by、aggregate等。表API程序声明性地定义了应该做什么逻辑操作,而不是确切地指定操作代码的样子。尽管表API可由各种类型的用户定义函数扩展,但它的表现力不如 Core APIs ,但使用起来更简洁(编写的代码更少)。此外,Table API程序在执行之前还会经过一个应用优化规则的优化器。

    可以在表和 DataStream/DataSet 之间无缝转换,允许程序混合 Table APIDataStreamDataSet api。

  • Flink提供的最高级别抽象是SQL。这种抽象在语义和表达性上都类似于 Table api ,但是将程序表示为SQL查询表达式。SQL抽象与表API紧密交互,SQL查询可以在 Table API 中定义的表上执行。

程序和数据流

Flink程序的基本构建块是streamstransformations。(请注意,Flink的DataSet API中使用的数据集也是内部流——稍后将对此进行更多介绍)。从概念上讲,_stream_是一个(潜在的永无休止的)数据记录流,transformation 是一个以一个或多个流作为输入并生成一个或多个输出流的操作。

当执行时,Flink程序被映射到 streaming dataflows,包括streams和转换operators。每个数据流从一个或多个sources开始,以一个或多个sinks结束。数据流类似于任意directed acyclic graphs(DAGs)。尽管通过 iteration 构造允许特殊形式的循环,但为了简单起见,我们将在大多数情况下对此进行解释。

一个数据流程序及其数据

通常在程序中的转换和数据流中的操作符之间存在一对一的对应关系。然而,有时一个转换可能由多个转换操作符组成。

源和接收器在流连接器和批连接器文档中有文档说明。转换被记录在DataStream操作符和数据集转换中。

并行数据流

Flink中的程序本质上是并行和分布式的。在执行期间,stream 有一个或多个stream partitions,每个 operator 有一个或多个operator subtasks。运算符子任务彼此独立,在不同的线程中执行,也可能在不同的机器或容器中执行。

运算符子任务的数量是该运算符的parallelism。流的并行性始终是其生成操作符的并行性。同一程序的不同运算符可能具有不同级别的并行性。

并行数据流

流可以在_一对一(或 forwarding )模式或 redistributing 模式中的两个操作符之间传输数据:

  • One-to-one流(例如上图中的 Sourcemap() 操作符之间的流)保留元素的分区和顺序。这意味着 map() 操作符的子任务[1]将以与 Source 操作符的子任务[1]生成的元素相同的顺序看到这些元素。

  • Redistributing流(如上面的 map()keyBy/window 之间以及 keyBy/windowSink 之间)更改流的分区。每个 operator subtask 将数据发送到不同的目标子任务,具体取决于所选的转换。例如 keyBy() (通过散列键重新分区)、broadcast()rebalance() (随机重新分区)。在更改 redistributing 中,元素之间的顺序仅保存在每对发送和接收子任务中(例如,map() 的子任务[1]和 keyBy/window 的子任务[2])。所以在这个例子中,每个键内的顺序是保留的,但是并行性确实引入了关于不同键的聚合结果到达sink的顺序的不确定性。

关于配置和控制并行性的详细信息可以在parallel execution。

Windows

聚合事件(例如, counts, sums)在流上的工作方式与在批处理中不同。例如,不可能计算流中的所有元素,因为流通常是无限的(无界的)。相反,流上的聚合(计数、和等)的作用域是windows,例如 “count over the last 5 minutes”“sum of the last 100 elements”

Windows可以是 time driven (示例:每30秒)或 data driven (示例:每100个元素)。通常可以区分不同类型的窗口,例如 scroll windows (没有重叠)、滑动windows(有重叠)和 session windows (中间有不活动的间隙)。

更多窗口示例可以在这篇找到 blog post

Time

当在流媒体程序中引用时间(例如定义窗口)时,可以引用不同的时间概念:

  • Event Time是创建事件的时间。它通常由事件中的时间戳描述,例如由生产传感器或生产服务附加的时间戳。Flink通过timestamp assigners访问事件时间戳。

  • Ingestion time是事件在源操作符上进入Flink数据流的时间。

  • Processing Time是执行基于时间的操作的每个操作符的本地时间。

Event Time, Ingestion Time, and Processing Time

关于如何处理时间的更多细节见event time docs

有状态操作

虽然数据流中的许多操作每次只查看单个 event at a time(例如事件解析器),但有些操作会记住多个事件(例如窗口操作符)之间的信息。这些操作称为stateful

有状态操作的状态是在可以认为是嵌入式键/值存储区中维护的。状态与有状态操作符读取的流一起严格地分区和分布。因此,只能在 keyBy() 函数之后的 keyed streams 上访问键/值状态,并且只能访问与当前事件的键关联的值。对流和状态的键进行对齐可以确保所有的状态更新都是本地操作,从而保证一致性而不存在事务开销。这种对齐还允许Flink重新分配状态并透明地调整流分区。

有关更多信息,请参阅有关的文档 state.

容错检查点

Flink使用 stream replaycheckpointing的组合实现容错。检查点与每个输入流中的特定点以及每个操作符的对应状态相关。流数据流可以从检查点恢复,同时通过恢复操作符的状态并从检查点重新播放事件来保持一致性 (exactly-once processing semantics)

检查点间隔是一种平衡执行期间容错开销和恢复时间(需要重播的事件数量)的方法。

fault tolerance internals 提供了关于Flink如何管理检查点和相关主题的更多信息。有关启用和配置检查点的详细信息见 checkpointing API docs

流式批处理

Flink将 batch programs 作为流程序的一种特殊情况执行,流是有界的(元素的数量是有限的)。DataSet 在内部作为数据流处理。因此,上述概念同样适用于批处理程序,也适用于流媒体程序,但有少数例外:

  • Fault tolerance for batch programs不使用检查点。恢复是通过完全重播流来实现的。这是可能的,因为输入是有界的。这使得恢复的成本更高,但是常规处理更便宜,因为它避免了检查点。

  • 数据集API中的有状态操作使用简化的内存/内核数据结构,而不是键/值索引。

  • 数据集API引入了特殊的同步(基于超步的)迭代,这只有在有界流上才能实现。有关详细信息,请查看iteration docs

转自https://github.com/apachecn/flink-doc-zh/

相关文章