Flink定义
Apache Flink is a framework and distributed processing engine for stateful computations over unbounded and bounded data streams.
Apache Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行状态计算。
Flink相关概念
批处理是有界数据流处理的范例。在这种模式下,你可以选择在计算结果输出之前输入整个数据集,这也就意味着你可以对整个数据集的数据进行排序、统计或汇总计算后再输出结果。
流处理正相反,其涉及无界数据流。至少理论上来说,它的数据输入永远不会结束,因此程序必须持续不断地对到达的数据进行处理。
Flink架构
在Flink中执行应用程序主要涉及三个实体:Client,JobManager和TaskManagers。
Client
client不是运行时和程序执行的一部分,而是用于准备数据流并将其发送给 JobManager。之后,客户端可以断开连接(分离模式),或保持连接来接收进程报告(附加模式)
JobManager
-
控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的JobManager 所控制执行。
-
JobManager 会先接收到要执行的应用程序,这个应用程序会包括:作业图(JobGraph)、逻辑数据流图(logical dataflow graph)和打包了所有的类、库和其它资源的JAR包。
-
JobManager 会把JobGraph转换成一个物理层面的数据流图,这个图被叫做“执行图”(ExecutionGraph),包含了所有可以并发执行的任务。
-
JobManager 会向资源管理器(ResourceManager)请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(slot)。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的TaskManager上。而在运行过程中,JobManager会负责所有需要中央协调的操作,比如说检查点(checkpoints)的协调。
ResourceManager
-
主要负责管理任务管理器(TaskManager)的插槽(slot),TaskManger 插槽是Flink中定义的处理资源单元。
-
Flink为不同的环境和资源管理工具提供了不同资源管理器,比如YARN、Mesos、K8s,以及standalone部署。
-
当JobManager申请插槽资源时,ResourceManager会将有空闲插槽的TaskManager分配给JobManager。如果ResourceManager没有足够的插槽来满足JobManager的请求,它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器。
Dispatcher
-
可以跨作业运行,它为应用提交提供了REST接口。
-
当一个应用被提交执行时,分发器就会启动并将应用移交给一个JobManager。
-
Dispatcher也会启动一个Web UI,用来方便地展示和监控作业执行的信息。
-
Dispatcher在架构中可能并不是必需的,这取决于应用提交运行的方式。
JobMaster
JobMaster负责管理单个JobGraph的执行。Flink 集群中可以同时运行多个作业,每个作业都有自己的 JobMaster。
TaskManager
-
Flink中的工作进程。通常在Flink中会有多个TaskManager运行,每一个TaskManager都包含了一定数量的插槽(slots)。插槽的数量限制了TaskManager能够执行的任务数量。
-
启动之后,TaskManager会向资源管理器注册它的插槽;收到资源管理器的指令后,TaskManager就会将一个或者多个插槽提供给JobManager调用。JobManager就可以向插槽分配任务(tasks)来执行了。
-
在执行过程中,一个TaskManager可以跟其它运行同一应用程序的TaskManager交换数据。
时间语义
Flink 明确支持以下三种时间语义:
-
事件时间(event time): 事件产生的时间,记录的是设备生产(或者存储)事件的时间
-
摄取时间(ingestion time): Flink 读取事件时记录的时间
-
处理时间(processing time): Flink pipeline 中具体算子处理事件的时间
在 Flink 的流式处理中,绝大部分的业务都会使用 eventTime。
我们知道,流处理从事件产生,到流经 source,再到 operator,中间是有一个过程和时间的,虽然大部分情况下,流到 operator 的数据都是按照事件产生的时间顺序来的,但是也不排除由于网络、分布式等原因,导致乱序的产生,所谓乱序,就是指 Flink 接收到的事件的先后顺序不是严格按照事件的 Event Time 顺序排列的。
window
出现乱序数据,首先想到的是要排序,但是流式数据中不能等待所有数据都到达再进行排序,而是要将数据流切分为数据集,并对数据集进行排序,由此引入窗口的概念。 窗口是一种切割无限数据为有限块进行处理的手段,是无限数据流处理的核心。
Flink 有一些内置的窗口分配器,如下所示:
可以对窗口内收集到的数据做聚合或者其他处理操作,主要非为两大类:
-
增量聚合函数(incremental aggregation functions):每条数据到来就进行计算,保持一个简单的状态。
-
全窗口函数(full window functions):先把窗口所有数据收集起来,等到计算的时候会遍历所有数据。
Flink提供了丰富的window API:
Watermark
窗口操作虽然可以解决乱序问题,但是依然存在迟到数据的现象,由此引入Watermark。
当一个窗口戳到了关闭时间,不应该立刻触发窗口计算,而是等待一段时间,等迟到的数据来了再关闭窗口。数据流中的 Watermark 用于表示 timestamp 小于 Watermark 的数据都已经到达了,因此,window 的执行也是由 Watermark 触发的。
watermarks 给了开发人员一种选择,使开发者做流处理时可以控制延迟和结果正确性之间的权衡。
-
如果watermark设置的延迟太大,收到结果的速度可能就会很慢,解决办法是在水位线到达之前输出一个近似结果(增量聚合)。
-
如果watermark到达得太小,则可能收到错误结果,不过 Flink 可以通过侧输出流、允许的延迟(allowed lateness)的间隔解决这个问题。
State Backends
由于有效的状态访问对于处理数据的低延迟至关重要,因此每个并行任务都会在本地维护其状态,以确保快速的状态访问。每传入一条数据,有状态的算子任务都会读取和更新状态。状态的存储、访问以及维护,由一个可插入的组件决定,这个组件就叫做状态后端(state backend) 。如果发生故障,Flink 可以恢复应用程序的完整状态并继续处理。
状态后端主要负责两件事:本地的状态管理,以及将检查点(checkpoint)状态写入远程存储。
名称 | 状态存储位置 | checkpoint存储位置 | 快照 | 特点 |
---|---|---|---|---|
RocksDBStateBackend | RocksDB | RocksDB | 全量 / 增量 | 支持大于内存大小的状态经验法则:比基于堆的后端慢10倍 |
FsStateBackend | TM JVM Heap | 分布式文件系统 | 全量 | 快速,需要大的堆内存受限制于 GC 同时拥有内存级的本地访问速度,和更好的容错保证 |
MemoryStateBackend | TM JVM Heap | JM JVM Heap | 全量 | 适用于小状态(本地)的测试和实验 快速、低延迟,但不稳定 |
算子状态的作用范围限定为算子任务,由同一并行任务所处理的所有数据都可以访问到相同的状态,如聚合每分钟的事件时,可将一分钟内数据的增量聚合结果作为状态保存。
Checkpoint
Checkpoint是由 Flink 自动执行的快照,Flink 故障恢复机制的核心就是应用状态的一致性检查点。有状态流应用的一致检查点,其实就是所有任务的状态,在某个时间点的一份拷贝(一份快照),这个时间点,应该是所有任务都恰好处理完一个相同的输入数据的时候。
在执行流应用程序期间,Flink 会定期保存状态的一致检查点。如果发生故障, Flink 将会使用最近的检查点来一致恢复应用程序的状态,并重新启动处理流程
遇到故障之后,第一步就是重启应用
第二步是从 checkpoint 中读取状态,将状态重置。从检查点重新启动应用程序后,其内部状态与检查点完成时的状态完全相同
第三步:开始消费并处理检查点到发生故障之间的所有数据,这种检查点的保存和恢复机制可以为应用程序状态提供“精确一次”(exactly-once)的一致性,因为所有算子都会保存检查点并恢复其所有状态,这样一来所有的输入流就都会被重置到检查点完成时的位置。
Savepoint
一个 Savepoint,就是一个应用服务状态的一致性快照,因此其与checkpoint组件的很相似,但是与checkpoint相比,Savepoint 需要手动触发启动,而且当流应用服务停止时,它并不会自动删除。Savepoint 常被应用于启动一个已含有状态的流服务,并初始化其(备份时)状态。
Savepoint 有以下特点:
-
便于升级应用服务版本: Savepoint 常在应用版本升级时使用,当前应用的新版本更新升级时,可以根据上一个版本程序记录的 Savepoint 内的服务状态信息来重启服务。它也可能会使用更早的 Savepoint 还原点来重启服务,以便于修复由于有缺陷的程序版本导致的不正确的程序运行结果。
-
方便集群服务移植: 通过使用 Savepoint,流服务应用可以自由的在不同集群中迁移部署。
-
方便Flink版本升级: 通过使用 Savepoint,可以使应用服务在升级Flink时,更加安全便捷。
-
增加应用并行服务的扩展性: Savepoint 也常在增加或减少应用服务集群的并行度时使用。
-
便于A/B测试及假设分析场景对比结果: 通过把同一应用在使用不同版本的应用程序,基于同一个 Savepoint 还原点启动服务时,可以测试对比2个或多个版本程序的性能及服务质量。
-
暂停和恢复服务: 一个应用服务可以在新建一个 Savepoint 后再停止服务,以便于后面任何时间点再根据这个实时刷新的 Savepoint 还原点进行恢复服务。
-
归档服务: Savepoint 还提供还原点的归档服务,以便于用户能够指定时间点的 Savepoint 的服务数据进行重置应用服务的状态,进行恢复服务。
状态一致性
-
AT-MOST-ONCE(最多一次)
-
AT-LEAST-ONCE(至少一次)
-
EXACTLY-ONCE(精确一次)
Flink内部的状态一致性
Flink 使用了一种轻量级快照机制 —— 检查点(checkpoint)来保证 exactly-once 语义
端到端的状态一致性
流处理应用除了流处理器以外还包含了数据源(例如 Kafka)和输出到持久化系统。端到端的一致性保证,意味着结果的正确性贯穿了整个流处理应用的始终;每一个组件都保证了它自己的一致性。整个端到端的一致性级别取决于所有组件中一致性最弱的组件。
-
内部保证 —— checkpoint
-
source 端 —— 可重设数据的读取位置(kafka可以设置读取的offset)
-
sink 端 —— 从故障恢复时,数据不会重复写入外部系统
为实现目标端数据不重复下写入有以下实现方式:
-
幂等写入:(仅在目标端表有主键的情况下适用)
-
事务写入:构建的事务对应着 checkpoint,等到 checkpoint 真正完成的时候,才把所有对应的结果写入 sink 系统中。
事务写入的两种实现方式:
-
预写日志 (GenericWriteAheadSink)
-
两阶段提交(TwoPhaseCommitSinkFunction )
预写日志:
-
把结果数据先当成状态保存,然后在收到 checkpoint 完成的通知时,一次性写入 sink 系统。
-
简单易于实现,由于数据提前在状态后端中做了缓存,所以无论什么sink 系统,都能用这种方式一批搞定。
缺点:微批处理,不能保证一批数据全部成功。
两阶段提交:
-
对于每个 checkpoint,sink 任务会启动一个事务,并将接下来所有接收的数据添加到事务里。
-
然后将这些数据写入外部 sink 系统,但不提交它们 —— 这时只是“预提交”。
-
当它收到 checkpoint 完成的通知时,它才正式提交事务,实现结果的真正写入。
2PC 对外部 sink 系统的要求
-
外部 sink 系统必须提供事务支持,或者 sink 任务必须能够模拟外部系统上的事务。
-
在 checkpoint 的间隔期间里,必须能够开启一个事务并接受数据写入。
-
在收到 checkpoint 完成的通知之前,事务必须是“等待提交”的状态。 在故障恢复的情况下,这可能需要一些时间。如果这个时候sink系统关闭事务(例如超时了),那么未提交的数据就会丢失。
-
sink 任务必须能够在进程失败后恢复事务。
-
提交事务必须是幂等操作。
部署
部署模式
-
Application Mode
-
Per-Job Mode
-
Session Mode
client load:此过程包括在本地下载应用程序的依赖项,执行用户代码以提取 Flink 的运行时可以理解的应用程序(即JobGraph
),并将依赖项和JobGraph(s)
传送到集群。
部署模式 | client load执行位置 | JM是否隔离 | TM是否隔离 | 原生k8s集群是否支持 |
---|---|---|---|---|
Application Mode | Client | 是 | 是 | 是 |
Per-Job Mode | JM | 是 | 是 | 否 |
Session Mode | JM | 否 | 否 | 是 |
Flink对k8s集群的要求
-
Kubernetes版本大于等于1.9。
-
可以访问列表,创建,删除容器和服务,可以通过进行配置
~/.kube/config
。您可以通过运行来验证权限kubectl auth can-i <list|create|edit|delete> pods
。 -
启用Kubernetes DNS。
-
RBAC:d
efault service account
具有创建,删除Pod的权限。
关注作者公众号,一起讨论更多