文章目录
- [1、Flink 介绍](#1、Flink 介绍)
- [2、Flink 概述](#2、Flink 概述)
- [3、Flink 组件介绍](#3、Flink 组件介绍)
-
- [3.1、Deploy 物理部署层](#3.1、Deploy 物理部署层)
- [3.2、Runtime 核心层](#3.2、Runtime 核心层)
- [3.3、API&Libraries 层](#3.3、API&Libraries 层)
- 3.4、扩展库
- [4、Flink 四大基石](#4、Flink 四大基石)
- [5、Flink 的应用场景](#5、Flink 的应用场景)
-
- [5.1、Event-driven Applications【事件驱动】](#5.1、Event-driven Applications【事件驱动】)
- [5.2、Data Analytics Applications【数据分析】](#5.2、Data Analytics Applications【数据分析】)
- [5.3、Data Pipeline Applications【数据管道】](#5.3、Data Pipeline Applications【数据管道】)
- [6、Flink 的优势](#6、Flink 的优势)
- [7、Flink 编程模型](#7、Flink 编程模型)
-
- 7.1、抽象的层级
- 7.2、程序和数据流
- 7.3、并行的数据流
- 7.4、窗口(Windows)
- 7.5、时间(Time)
- [7.6、有状态的数据操作(Stateful Operations)](#7.6、有状态的数据操作(Stateful Operations))
- [7.7、容错的 Checkpoint](#7.7、容错的 Checkpoint)
- 7.8、流上的批处理
- [8、Flink 分布式执行环境](#8、Flink 分布式执行环境)
-
- [8.1、任务和运算(算子)链(Tasks and Operator Chains)](#8.1、任务和运算(算子)链(Tasks and Operator Chains))
- [8.2、Job Managers,Task Managers,Clients](#8.2、Job Managers,Task Managers,Clients)
- [8.3、Task Slots 和资源](#8.3、Task Slots 和资源)
- 8.4、状态后端
- 8.5、保存点(Savepoints)
1、Flink 介绍
Apache Flink是一个框架和分布式处理引擎,用于对无限制和有限制的数据流进行有状态的计算。Flink被设计为可以在所有常见的集群环境中运行,以内存速度和任何规模执行计算。
官网中文:https://flink.apache.org/zh/
本示例以 1.12 版本进行介绍,当前版本更新至 1.17 。
2、Flink 概述
Apache Flink是一个面向数据流处理和批量数据处理的可分布式的开源计算框架,它基于同一个Flink流式执行模型(streaming execution model),能够支持流处理和批处理两种应用类型。由于流处理和批处理所提供的SLA(服务等级协议)是完全不相同, 流处理一般需要支持低延迟、Exactly-once保证,而批处理需要支持高吞吐、高效处理,所以在实现的时候通常是分别给出两套实现方法,或者通过一个独立的开源框架来实现其中每一种处理方案。比较典型的有:实现批处理的开源方案有MapReduce、Spark;实现流处理的开源方案有Storm;Spark的Streaming 其实本质上也是微批处理。
Flink在实现流处理和批处理时,与传统的一些方案完全不同,它从另一个视角看待流处理和批处理,将二者统一起来:Flink是完全支持流处理,也就是说作为流处理看待时输入数据流是无界的;批处理被作为一种特殊的流处理,只是它的输入数据流被定义为有界的。
Flink 官方提供了Java、Scala、Python 语言接口用以开发 Flink 应用程序,但是 Flink 的源码是使用 Java 语言进行开发的,且 Flink 被阿里收购后(2019 年1 月 8 日),未来的主要编程语言可能主要会是 Java,且 GitHub 上关于 Flink 的项目,大多数是使用 Java 语言编写的。
3、Flink 组件介绍
3.1、Deploy 物理部署层
Flink 支持本地运行、能在独立集群或者在被 YARN 管理的集群上运行, 也能部署在云上,该层主要涉及 Flink 的部署模式,目前 Flink 支持多种部署模式:本地、集群(Standalone、YARN)、云(GCE/EC2)、Kubenetes。Flink 能够通过该层能够支持不同平台的部署,用户可以根据需要选择使用对应的部署模式。
3.2、Runtime 核心层
Runtime 层提供了支持 Flink 计算的全部核心实现,为上层 API 层提供基础服务,该层主要负责对上层不同接口提供基础服务,也是 Flink 分布式计算框架的核心实现层,支持分布式 Stream 作业的执行、JobGraph 到 ExecutionGraph 的映射转换、任务调度等。将 DataSteam 和 DataSet 转成统一的可执行的 Task Operator,达到在流式引擎下同时处理批量计算和流式计算的目的。
3.3、API&Libraries 层
Flink 首先支持了 Scala 和 Java 的 API、Python 。DataStream、DataSet、Table、SQL API,作为分布式数据处理框架,Flink 同时提供了支撑计算和批计算的接口,两者都提供给用户丰富的数据处理高级 API ,例如 Map、FlatMap 操作等,也提供比较低级的 Process Function API,用户可以直接操作状态和时间等底层数据。
3.4、扩展库
Flink 还包括用于复杂事件处理的CEP,机器学习库 FlinkML,图处理库 Gelly等。Table 是一种接口化的 SQL 支持,也就是 API 支持(DSL),而不是文本化的 SQL 解析和执行。
4、Flink 四大基石
Flink 之所以能这么流行,离不开它最重要的四个基石:Checkpoint
、State
、Time
、Window
。
4.1、Checkpoint
这是 Flink 最重要的一个特性。
Flink基于 Chandy-Lamport 算法实现了一个分布式的一致性的快照,从而提供了一致性的语义。
Chandy-Lamport算法实际上在1985年的时候已经被提出来,但并没有被很广泛的应用,而Flink则把这个算法发扬光大了。
Spark 最近在实现 Continue streaming,Continue streaming 的目的是为了降低处理的延时,其也需要提供这种一致性的语义,最终也采用了 Chandy-Lamport 这个算法,说明Chandy-Lamport 算法在业界得到了一定的肯定。(https://zhuanlan.zhihu.com/p/53482103)
4.2、State
提供了一致性的语义之后,Flink 为了让用户在编程时能够更轻松、更容易地去管理状态,还提供了一套非常简单明了的 State API,包括里面的有 ValueState、ListState 、MapState ,近期添加了 BroadcastState ,使用 State API 能够自动享受到这种一致性的语义。
4.3、Time
除此之外,Flink 还实现了 Watermark 的机制,能够支持基于事件的时间的处理,能够容忍迟到/乱序的数据。
4.4、Window
另外流计算中一般在对流数据进行操作之前都会先进行开窗,即基于一个什么样的窗口上做这个计算。Flink提供了开箱即用的各种窗口,比如滑动窗口、滚动窗口、会话窗口以及非常灵活的自定义的窗口。
5、Flink 的应用场景
Flink 功能强大,支持开发和运行多种不同种类的应用程序。它的主要特性包括:批流一体化、精密的状态管理、事件时间支持以及精确一次的状态一致性保障等。Flink 不仅可以运行在包括 YARN、 Mesos、Kubernetes 在内的多种资源管理框架上,还支持在裸机集群上独立部署。在启用高可用选项的情况下,它不存在单点失效问题。事实证明,Flink 已经可以扩展到数千核心,其状态可以达到 TB 级别,且仍能保持高吞吐、低延迟的特性。世界各地有很多要求严苛的流处理应用都运行在 Flink 之上。
https://flink.apache.org/zh/use-cases/
5.1、Event-driven Applications【事件驱动】
事件驱动型应用是一类具有状态的应用,它从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。
事件驱动型应用是在计算存储分离的传统应用基础上进化而来。在传统架构中,应用需要读写远程事务型数据库。相反,事件驱动型应用是基于状态化流处理来完成。在该设计中,数据和计算不会分离,应用只需访问本地(内存或磁盘)即可获取数据。
系统容错性的实现依赖于定期向远程持久化存储写入 checkpoint。下图描述了传统应用和事件驱动型应用架构的区别。
从某种程度上来说,所有的实时的数据处理或者是流式数据处理都应该是属于Data Driven,流计算本质上是Data Driven 计算。应用较多的如风控系统,当风控系统需要处理各种各样复杂的规则时,Data Driven 就会把处理的规则和逻辑写入到Datastream 的API 或者是ProcessFunction 的API 中,然后将逻辑抽象到整个Flink 引擎,当外面的数据流或者是事件进入就会触发相应的规则,这就是Data Driven 的原理。在触发某些规则后,Data Driven 会进行处理或者是进行预警,这些预警会发到下游产生业务通知,这是Data Driven 的应用场景,Data Driven 在应用上更多应用于复杂事件的处理。
典型实例:
- 欺诈检测(Fraud detection)
- 异常检测(Anomaly detection)
- 基于规则的告警(Rule-based alerting)
- 业务流程监控(Business process monitoring)
- Web应用程序(社交网络)
5.2、Data Analytics Applications【数据分析】
数据分析任务需要从原始数据中提取有价值的信息和指标。如下图所示,Flink 同时支持流式及批量分析应用。
Data Analytics Applications
:包含 Batch analytics (批处理分析)和 Streaming analytics (流处理分析)
Batch analytics
:可以理解为周期性查询:Batch Analytics 就是传统意义上使用类似于 Map Reduce、Hive、Spark Batch 等,对作业进行分析、处理、生成离线报表。比如Flink应用凌晨从 Recorded Events 中读取昨天的数据,然后做周期查询运算,最后将数据写入 Database 或者 HDFS ,或者直接将数据生成报表供公司上层领导决策使用。
Streaming analytics
:可以理解为连续性查询:比如实时展示双十一天猫销售 GMV(Gross Merchandise Volume 成交总额),用户下单数据需要实时写入消息队列,Flink 应用源源不断读取数据做实时计算,然后不断的将数据更新至 Database 或者 K-VStore ,最后做大屏实时展示。
典型实例:
- 电信网络质量监控
- 移动应用中的产品更新及实验评估分析
- 消费者技术中的实时数据即席分析
- 大规模图分析
5.3、Data Pipeline Applications【数据管道】
什么是数据管道?
提取-转换-加载(ETL)是一种在存储系统之间进行数据转换和迁移的常用方法。ETL 作业通常会周期性地触发,将数据从事务型数据库拷贝到分析型数据库或数据仓库。数据管道和 ETL 作业的用途相似,都可以转换、丰富数据,并将其从某个存储系统移动到另一个。但数据管道是以持续流模式运行,而非周期性触发。因此数据管道支持从一个不断生成数据的源头读取记录,并将它们以低延迟移动到终点。
例如:数据管道可以用来监控文件系统目录中的新文件,并将其数据写入事件日志;另一个应用可能会将事件流物化到数据库或增量构建和优化查询索引。和周期性 ETL 作业相比,持续数据管道可以明显降低将数据移动到目的端的延迟。此外,由于它能够持续消费和发送数据,因此用途更广,支持用例更多。下图描述了周期性 ETL 作业和持续数据管道的差异。
Periodic ETL
:比如每天凌晨周期性的启动一个 Flink ETL Job,读取传统数据库中的数据,然后做ETL,最后写入数据库和文件系统。
Data Pipeline
:比如启动一个 Flink 实时应用,数据源(比如数据库、Kafka )中的数据不断的通过 Flink Data Pipeline 流入或者追加到数据仓库(数据库或者文件系统),或者 Kafka 消息队列。Data Pipeline 的核心场景类似于数据搬运并在搬运的过程中进行部分数据清洗或者处理,而整个业务架构图的左边是 Periodic ETL,它提供了流式 ETL 或者实时 ETL,能够订阅消息队列的消息并进行处理,清洗完成后实时写入到下游的 Database 或 File system 中。
典型实例:
- 电子商务中的持续 ETL(实时数仓)
当下游要构建实时数仓时,上游则可能需要实时的 Stream ETL。这个过程会进行实时清洗或扩展数据,清洗完成后写入到下游的实时数仓的整个链路中,可保证数据查询的时效性,形成实时数据采集、实时数据处理以及下游的实时 Query。 - 电子商务中的实时查询索引构建(搜索引擎推荐)
搜索引擎这块以淘宝为例,当卖家上线新商品时,后台会实时产生消息流,该消息流经过Flink 系统时会进行数据的处理、扩展。然后将处理及扩展后的数据生成实时索引,写入到搜索引擎中。这样当淘宝卖家上线新商品时,能在秒级或者分钟级实现搜索引擎的搜索。
6、Flink 的优势
6.1、主要优势
- Flink 具备统一的框架处理有界和无界两种数据流的能力
- 部署灵活,Flink 底层支持多种资源调度器,包括Yarn、Kubernetes 等。Flink 自身带的Standalone 的调度器,在部署上也十分灵活。
- 极高的可伸缩性,可伸缩性对于分布式系统十分重要,阿里巴巴双 11 大屏采用 Flink 处理海量数据,使用过程中测得 Flink 峰值可达17 亿条/秒。
- 极致的流式处理性能。Flink 相对于 Storm 最大的特点是将状态语义完全抽象到框架中,支持本地状态读取,避免了大量网络 IO,可以极大提升状态存取的性能。
6.2、其他优势
-
同时支持高吞吐、低延迟、高性能
Flink 是目前开源社区中唯一一套集高吞吐、低延迟、高性能三者于一身的分布式流式数据处理框架。Spark 只能兼顾高吞吐和高性能特性,无法做到低延迟保障,因为Spark是用批处理来做流处理; Storm 只能支持低延时和高性能特性,无法满足高吞吐的要求。下图显示了 Apache Flink 与 Apache Storm 在完成流数据清洗的分布式任务的性能对比。
-
支持事件时间(Event Time)概念
在流式计算领域中,窗口计算的地位举足轻重,但目前大多数框架窗口计算采用的都是系统时间(Process Time),也就是事件传输到计算框架处理时,系统主机的当前时间。Flink 能够支持基于事件时间(Event Time)语义进行窗口计算,这种基于事件驱动的机制使得事件即使乱序到达甚至延迟到达,流系统也能够计算出精确的结果,保持了事件原本产生时的时序性,尽可能避免网络传输或硬件系统的影响。
-
支持有状态计算
Flink1.4开始支持有状态计算,所谓状态就是在流式计算过程中将算子的中间结果保存在内存或者文件系统中,等下一个事件进入算子后可以从之前的状态中获取中间结果,计算当前的结果,从而无须每次都基于全部的原始数据来统计结果,极大的提升了系统性能,状态化意味着应用可以维护随着时间推移已经产生的数据聚合。
-
支持高度灵活的窗口(Window)操作
Flink 将窗口划分为基于 Time 、Count 、Session、以及Data-Driven等类型的窗口操作,窗口可以用灵活的触发条件定制化来达到对复杂的流传输模式的支持,用户可以定义不同的窗口触发机制来满足不同的需求。
-
基于轻量级分布式快照(Snapshot/Checkpoints)的容错机制
Flink 能够分布运行在上千个节点上,通过基于分布式快照技术的Checkpoints,将执行过程中的状态信息进行持久化存储,一旦任务出现异常停止,Flink 能够从 Checkpoints 中进行任务的自动恢复,以确保数据处理过程中的一致性,Flink 的容错能力是轻量级的,允许系统保持高并发,同时在相同时间内提供强一致性保证。
-
基于 JVM 实现的独立的内存管理
Flink 实现了自身管理内存的机制,通过使用散列,索引,缓存和排序有效地进行内存管理,通过序列化/反序列化机制将所有的数据对象转换成二进制在内存中存储,降低数据存储大小的同时,更加有效的利用空间。使其独立于 Java 的默认垃圾收集器,尽可能减少 JVM GC 对系统的影响。
-
基于 JVM 实现的独立的内存管理
Flink 实现了自身管理内存的机制,通过使用散列,索引,缓存和排序有效地进行内存管理,通过序列化/反序列化机制将所有的数据对象转换成二进制在内存中存储,降低数据存储大小的同时,更加有效的利用空间。使其独立于 Java 的默认垃圾收集器,尽可能减少 JVM GC 对系统的影响。
-
SavePoints 保存点
对于 7 * 24 小时运行的流式应用,数据源源不断的流入,在一段时间内应用的终止有可能导致数据的丢失或者计算结果的不准确。比如集群版本的升级,停机运维操作等。值得一提的是,Flink 通过SavePoints 技术将任务执行的快照保存在存储介质上,当任务重启的时候,可以从事先保存的 SavePoints 恢复原有的计算状态,使得任务继续按照停机之前的状态运行 。Flink 保存点提供了一个状态化的版本机制,使得能以无丢失状态和最短停机时间的方式更新应用或者回退历史数据。
-
灵活的部署方式,支持大规模集群
Flink 被设计成能用上千个点在大规模集群上运行。除了支持独立集群部署外,Flink 还支持 YARN 和 Mesos 方式部署。
-
Flink 的程序内在是并行和分布式的
数据流可以被分区成 stream partitions,operators 被划分为 operator subtasks;这些 subtasks 在不同的机器或容器中分不同的线程独立运行;operator subtasks 的数量就是operator的并行计算数,不同的 operator 阶段可能有不同的并行数;如下图所示,source operator 的并行数为 2,但最后的 sink operator 为1;
-
丰富的库
Flink 拥有丰富的库来进行机器学习,图形处理,关系数据处理等。
7、Flink 编程模型
7.1、抽象的层级
- 有状态的数据流处理层
最底层的抽象仅仅提供有状态的数据流,它通过处理函数(Process Function)嵌入到数据流api(DataStream API). 用户可以通过它自由的处理单流或者多流,并保持一致性和容错。同时用户可以注册事件时间和处理时间的回调处理,以实现复杂的计算逻辑。 - 核心API层
它提供了数据处理的基础模块,像各种transformation, join,aggregations,windows,stat 以及数据类型等等 - Table API层
定了围绕关系表的DSL(领域描述语言)。Table API遵循了关系模型的标准:Table类型关系型数据库中的表,API也提供了相应的操作,像select,project,join,group-by,aggregate等。Table API声明式的定义了逻辑上的操作(logical operation)不是code for the operation;Flink会对Table API逻辑在执行前进行优化。同时代码上,Flink允许混合使用Table API和DataStram/DataSet API - SQL层
它很类似Table API的语法和表达,也是定义与Table API层次之上的,但是提供的是纯SQL的查询表达式。
7.2、程序和数据流
用户实现的 Flink 程序是由 Stream 和 Transformation 这两个基本构建块组成,其中 Stream 是一个中间结果数据,而 Transformation 是一个操作,它对一个或多个输入 Stream 进行计算处理,输出一个或多个结果 Stream 。当一个Flink程序被执行的时候,它会被映射为 Streaming Dataflow 。一个 Streaming Dataflow 是由一组 Stream 和 Transformation Operator 组成,它类似于一个 DAG 图,在启动的时候从一个或多个 Source Operator 开始,结束于一个或多个 Sink Operator。
下面是一个由 Flink 程序映射为 Streaming Dataflow 的示意图,如下所示:
上图中,FlinkKafkaConsumer 是一个 Source Operator,map、keyBy、timeWindow、apply是Transformation Operator,RollingSink 是一个 Sink Operator。
7.3、并行的数据流
在 Flink 中,程序天生是并行和分布式的:一个 Stream 可以被分成多个 Stream 分区(Stream Partitions),一个 Operator 可以被分成多个 Operator Subtask ,每一个 Operator Subtask 是在不同的线程中独立执行的。一个 Operator 的并行度,等于 Operator Subtask 的个数,一个 Stream 的并行度总是等于生成它的 Operator 的并行度。有关 Parallel Dataflow 的实例,如下图所示:
上图 Streaming Dataflow 的并行视图中,展现了在两个 Operator 之间的 Stream 的两种模式:
- One-to-one 模式:比如从 Source[1] 到 map()[1] ,它保持了 Source 的分区特性(Partitioning)和分区内元素处理的有序性,也就是说 map()[1] 的 Subtask 看到数据流中记录的顺序,与 Source[1] 中看到的记录顺序是一致的。
- Redistribution 模式 :这种模式改变了输入数据流的分区,比如从 map()[1] 、map()[2] 到keyBy()/window()/apply()[1]、keyBy()/window()/apply()[2],上游的 Subtask 向下游的多个不同的 Subtask 发送数据,改变了数据流的分区,这与实际应用所选择的 Operator 有关系。
另外,Source Operator 对应 2 个 Subtask,所以并行度为 2 ,而 Sink Operato r的 Subtask 只有1个,故而并行度为 1 。
7.4、窗口(Windows)
流处理中的聚合操作(counts,sums等等)不同于批处理,因为数据流是无限,无法在其上应用聚合,所以通过限定窗口(window)的范围,来进行流的聚合操作。例如:5分钟的数据计数,或者计算100个元素的总和等等。
窗口可以由时间驱动 (every 30 seconds) 或者数据驱动(every 100 elements)。如:滚动窗口tumbling windows(无叠加),滑动窗口sliding windows(有叠加),以及会话窗口session windows(被无事件活动的间隔隔开)。
7.5、时间(Time)
三种不同的时间概念:
- 事件时间 Event Time:事件的创建时间,通常通过时间中的一个时间戳来描述
- 摄入时间 Ingestion time: 事件进入Flink 数据流的source的时间
- 处理时间 Processing Time:Processing Time表示某个Operator对事件进行处理时的本地系统时间(是在TaskManager节点上)
7.6、有状态的数据操作(Stateful Operations)
在流处理中,有些操作仅仅在某一时间针对单一事件(如事件转换map),有些操作需要记住多个事件的信息并进行处理(window operators),后者的这些操作称为有状态的操作。有状态的操作一般被维护在内置的 key/value 存储中。这些状态信息会跟数据流一起分区并且分布存储,并且可以通过有状态的数据操作来访问。因此这些 key/value 的状态信息仅在带 key 的数据流(通过 keyBy() 函数处理过)中才能访问到。数据流按照 key 排列能保证所有的状态更新都是本地操作,保证一致性且无事务问题。同时这种排列方式使 Flink 能够透明的再分发状态信息和调整数据流分区。
7.7、容错的 Checkpoint
Flink 通过流回放和设置检查点的方式实现容错。一个checkpoint关联了输入流中的某个记录和相应状态和操作。数据流可以从checkpoint中进行恢复,并保证一致性(exactly-once 的处理语义)。 Checkpoint的间隔关系到执行是的容错性和恢复时间。
7.8、流上的批处理
Flink 把批处理作为特殊的流处理程序来执行,许多概念也都可以应用的批处理中,除了一些小的不同:
- 批处理的API(DataSet API )不使用 checkpoints ,恢复通过完整的流回放来实现;
- DataSet API 的有状态操作使用简单的内存和堆外内存 的数据结构,而不是key/value 的索引;
- DataSet API 引入一种同步的迭代操作,这个仅应用于有界数据流。
8、Flink 分布式执行环境
Flink 部署方式:
- Local --- 本地单机模式,学习测试时使用;
- Standalone --- 独立集群模式,Flink 自带集群,开发测试环境使用;
- StandaloneHA --- 独立集群高可用模式,Flink 自带集群,开发测试环境使用;
- On Yarn --- 计算资源统一由 Hadoop YARN 管理,生产环境使用。部署前提,最新版本1.17要求 java 11 以上版本,1.12 还可以使用 java 8 版本。
8.1、任务和运算(算子)链(Tasks and Operator Chains)
在 Flink 分布式执行环境中,会将多个运算子任务 Operator Subtask 串起来组成一个 Operator Chain ,实际上就是一个运算链。每个运算会在TaskManager 上一个独立的线程中执行。将算子串连到任务中是一种很好的优化:它能减少线程间的数据交接和缓存,并且提高整体的吞吐,降低处理的时延。这种串联的操作,可以通过 API 来进行配置。如下图的数据流就有 5 个子任务,通过5个并行的线程来执行,所示:
8.2、Job Managers,Task Managers,Clients
Flink的运行时,由两种类型的进程组成:
- JobManagers: 也就是 masters ,协调分布式任务的执行 。用来调度任务,协调 checkpoints ,协调错误恢复等等。至少需要一个 JobManager ,高可用的系统会有多个,一个 leader ,其他是 standby;
- TaskManagers: 也就是 workers ,用来执行数据流任务或者子任务,缓存和交互数据流。至少需要一个 TaskManager;
- Client : Client 不是运行是和程序执行的一部分,它是用来准备和提交数据流到JobManagers。之后,可以断开连接或者保持连接以获取任务的状态信息。
从上图可以分析出 Flink 运行时的整体状态。 Flink 的 Driver 程序会将代码逻辑构建成一个 Program Dataflow(区分source,operator,sink等等),在通过 Graph Builder 构建 DAG 的 Dataflow graph, 构建 job ,划分出 task 和subtask 等等。 Client 将 job 提交到 JobManager。Client 通过 Actor System 和 JobManager 进行消息通讯,接收 JobManager 返回的状态更新和任务执行统计结果。JobMangaer 按照 Dataflow 的 Task 和 Subtask 的划分,将任务调度分配到各个 TaskManager 中进行执行。TaskManager 会将内存抽象成多个 TaskSlot,用于执行 Task 任务。 JobManagers 与 TaskManagers 之间的任务管理,Checkpoints 的触发,任务状态,心跳等等消息处理都是通过 ActorSystem。
8.3、Task Slots 和资源
每个Worker(Task Manager)是一个JVM进程,通常会在单独的线程里执行一个或者多个子任务。为了控制一个Worker能够接受多少个任务,会在Worker上抽象多个Task Slot (至少一个)。每个Task Slot代表固定的资源子集。比如一个TaskManager有3个Slots,每个Slot能管理对这个Worker分配的资源的3分之1的内存。 对资源分槽,意味着Subtask不会同其他Subtasks竞争内存,同时可以预留一定的可用内存。目前Task Slot没有对CPU进行隔离,仅是针对内存。通过动态的调整task slots的个数,用户可以定义哪些子任务可以相互隔离。只有一个slot的TaskManager意味着每个任务组运行在一个单独JVM中。 在拥有多个slot的TaskManager上,subtask共用JVM,可以共用TCP连接和心跳消息,同时可以共用一些数据集和数据结构,从而减小任务的开销。
默认情况下,Flink允许子任务共享slots,即便它们是不同任务的子任务,只要属于同一个job。这样的结果就是一个slot会负责一个job的整个pipeline。共用slot有两个好处:
- Flink 集群的task slot的个数就是job的最高并行度。
- 更实现更好的资源利用。没有共享的slots,非密集的 source/map() subtask 会占用和 window 这类密集型的 subtask 同样多的资源。 使用共享的slot的将充分的利用分槽的资源,使代价较大的 subtask 能够均匀的分布在 TaskManager 上。如,下图中的共享slot的执行模式中可以并行运行6个pipeline而上图的只可以运行2个pipeline。同时APIs也提供了资源组的机制,可以实现不想进行资源隔离的情况。实践中,比较好的每个TaskManager的task slot的默认数量最好是CPU的核数。
8.4、状态后端
数据的 KV 索引信息存储在设定的状态后端的存储中。一种是内存中的Hash map,另一种是存在 Rocksdb(KV存储)中。另外,状态后端还是实现了在时间点上对 KV 状态的快照,并作为 Checkpoint 的一部分存储起来。
8.5、保存点(Savepoints)
通过 Data Stream API 编写的程序可以从一个保存点重新开始执行。即便你更新了你的程序和Flink集群都不会有状态数据丢失。
保存点是手动触发的,触发时会将它写入状态后端。 Savepoints 的实现也是依赖 Checkpoint 的机制。Flink 程序在执行中会周期性的在worker 节点上进行快照并生成Checkpoint。因为任务恢复的时候只需要最后一个完成的 Checkpoint 的,所以旧有的 Checkpoint 会在新的 Checkpoint 完成时被丢弃。
Savepoints 和周期性的 Checkpoint 非常的类似,只是有两个重要的不同。一个是由用户触发,而且不会随着新的 Checkpoint 生成而被丢弃。