Flink的一些核心概念

初识 Flink,我觉得需要了解一些基本的概念,对后续开发 Flink 程序有帮助

1、抽象层级

flink 对开发流式 / 批处理应用提供了不同的抽象层级
在这里插入图片描述

  • 最底层的抽象仅仅提供了 stateful streaming ,它利用 process function 嵌入到 DataStream API 里,允许用户可以自由地处理来自一个或多个流数据的事件,并使用一致、容错的状态。除此之外,用户可以注册事件时间和处理事件回调,从而使程序可以实现复杂的计算。
  • 实际上,大多数应用并不需要处理以上最底层的抽象,而是针对核心API进行编程,例如 DataSet API 或者 DataStream API,这些流畅的API为数据处理提供了通用的构建模块,比如由用户定义的多种形式的转换(transformations),连接(joins),聚合(aggregations),窗口操作(windows),状态(state)等等。这些API处理的数据类型以类(classes)的形式由各自的编程语言所表示。
  • Table API 是以表为中心的声明式DSL,其中表可能会动态变化(在表达流数据时)。Table API 遵循(扩展的)关系模型:表具有附加的模式(类似于关系数据库中的表),同时API提供可比较的操作,例如select、project、join、group-by、aggregate等。Table API 程序声明式地定义了 什么逻辑操作应该执行 而不是准确地确定 这些操作代码的看上去如何 。 尽管 Table API 可以通过多种类型的用户定义的函数进行扩展,其仍不如 核心API 更具表达能力,但是使用起来却更加简洁(代码量更少)。除此之外,Table API 程序还可以在执行之前通过应用优化规则的优化器。
  • Flink提供的最高层级的抽象是 SQL 。这一层抽象在语法与表达能力上与 Table API 类似,但是是以SQL查询表达式的形式表现程序。SQL抽象与Table API交互密切,同时SQL查询可以直接在Table API定义的表上执行。
2、程序与数据流

Flink 程序的基础构建块是streams)和转换transformations),注意一下,Flink DataSet API里用到的 DataSet 内部也是一个流。概念上来说,streams 是(可能永无止境)数据记录流,而 transformations 是一种拿到一个或多个数据流作为输入,产生一个或多个数据流作为结果输出的操作。

执行时,Flink程序映射到 streaming dataflows ,由 streams 以及 transformations operators 构成。每一个数据流起始于一个或多个 source,并终止于一个或多个 sink。数据流类似于任意的 有向无环图 (DAG) 。虽然通过 迭代 构造允许特定形式的环,但是大多数情况下,简单起见,我们都不考虑这一点。

在这里插入图片描述
上面的程序大致描述了一个数据流的进入–> 转化–> 输出的过程。
通常,程序中的转换与数据流中的操作之间是一对一的关系。有时,然而,一个转换可能由多个转换操作构成。

3、并行数据流

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

算子子任务的数量即这一特定算子的并行度 。一个流的并行度即其生产算子的并行度。相同程序中的不同的算子可能有不同级别的并行度。
在这里插入图片描述
流可以在两个算子之间利用一对一模式(one-to-one),或者重分配模式(redistribution)传输数据

  • 一对一流(例如上图中 Source 与 map() 算符之间)保持了元素的分区与排序。那意味着 map() 算子的子任务[1]将看到与 Source 的子任务[1]生成顺序相同的元素。

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

4、窗口

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

窗口可以是 事件驱动的 (比如:每30秒)或者 数据驱动的 (比如:每100个元素)。窗口通常被区分为不同的类型,比如 滚动窗口 (没有重叠), 滑动窗口 (有重叠),以及 会话窗口 (由不活动的间隙所打断)。更多细节参考这里
在这里插入图片描述

5、时间

Flink 流里有三个时间概念

  • 事件时间(event time):指事件创建的时间,它通常由事件中的时间戳描述,例如附接在生产传感器,或者生产服务。Flink通过时间戳分配器访问事件时间戳。
  • 摄入时间(ingestion time):是事件进入Flink数据流源算子的时间
  • 操作时间(processing time):是一个基于时间操作的算子的本地时间

在这里插入图片描述

6、有状态操作

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

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

在这里插入图片描述

7、容错检查点

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

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

8、流上的批处理

Flink 将批处理程序作为一种特别的流程序来处理,只是这个流是有界的(有限个元素),DataSet在内部被认为是一个数据流,上述适用于流处理程序的概念同样适用于批处理程序,除了一些例外。

  • 批处理程序的容错并不使用检查点,通过全部重放事件来恢复,这是可行的,因为数据是有限的,这种方法增加了恢复的一点成本,但是因为避开了检查点,使得常规处理更加廉价。
  • DataSet API 里的有状态操作使用简化的 in-memory/out-of-core 数据结构,而不是键值索引
  • DataSet API 引入了特殊的同步迭代,但是只在有界的数据流上可行,细节可以参考这里
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值