01 引言
在上一节《01、Flink教程 - Flink知识图谱》,我们知道了Flink
的知识大纲,明白了需要学习的主要内容,本专栏以后都是围绕以下内容来讲 :
- Flink介绍
- Flink环境准备(安装部署)
- Flink编程模型
- DataStream API
- Flink状态管理与容错
- DataSet API
- Table API & SQL
- Flink组件栈
- Flink部署与应用
- Flink监控与性能优化
- Flink框架版本:https://flink.apache.org/blog/
- Flink编程语言:https://ci.apache.org/projects/flink/flink-docs-release-1.12/
- Flink GitHub:https://github.com/apache/flink
本文主要开始讲解Flink
一些入门概念。
02 Flink概述
2.1 产生缘由
随着大数据时代的发展,海量数据和多种业务的实时处理需求激增,比如:
- 实时监控报警系统;
- 实时风控系统;
- 实时推荐系统等等。
传统的批处理方式和早期的流式处理框架因其自身的局限性,难以在延迟性、吞吐量、容错能力,以及使用便捷性等方面满足业务日益苛刻的要求。
在这种形势下,Flink
以其独特的天然 流式计算特性和更为先进的架构设计 ,极大地改善了以前的流式处理框架所存在的问题。
2.2 Flink 定义
Apache Flink :是一个分布式流处理器,具有直观和富有表现力的 API
,可实现有状态的流处理应用程序,它以容错的方式有效地大规模运行这些应用程序,还提供了有状态的计算,支持状态管理,支持强一致性的数据语义以及支持基于Event Time
的WaterMark
对延迟或乱序的数据进行处理等。
Flink的官方地址: https://flink.apache.org/
03 Flink 组件栈
Flink
分层的组件栈如下图所示(每一层所包含的组件都提供了特定的抽象,用来服务于上层组件):
主要分为如下几层:
- 物理部署层
- Runtime核心层
- API&Libraries层
- 扩展
3.1 物理部署层
Flink
支持的部署模式:
- 本地:本地运行
- 集群:独立集群(Standalone)、Yarn管理的集群
- 云上:GCE/EC2
- 容器化部署:Kubenetes
Flink
能够通过该层能够支持不同平台的部署,用户可以根据需要选择使用对应的部署模式。
3.2 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解析和执行。
04 Flink 四大基石
如上图,Fink
有四大基石,分别为:
- Checkpoint
- State
- Time
- Window
4.1 Checkpoint
Checkpoint是Flink
最重要的一个特性。
Flink
基于 Chandy-Lamport 算法实现了一个分布式的一致性的快照,从而提供了一致性的语义。
Chandy-Lamport算法实际上在1985年的时候已经被提出来,但并没有被很广泛的应用,而Flink
则把这个算法发扬光大了。
Spark
最近在实现Continue streaming
,Continue streaming
的目的是为了降低处理的延时,其也需要提供这种一致性的语义,最终也采用了Chandy-Lamport
这个算法,说明Chandy-Lamport
算法在业界得到了一定的肯定。
4.2 State
在提供了一致性的语义之后,Flink
为了让用户在编程时能够更轻松、更容易地去管理状态,还提供了一套非常简单明了的State API,包括里面的有ValueState
、ListState
、MapState
,及BroadcastState
。
使用State API能够自动享受到这种一致性的语义。
4.3 Time
除此之外,Flink
还实现了Watermark
的机制,能够支持基于事件的时间(Time)的处理,能够容忍迟到/乱序的数据。
4.4 Window
另外流计算中一般在对流数据进行操作之前都会先进行开窗(Window),即:基于一个什么样的窗口上做这个计算。
Flink
提供了开箱即用的各种窗口,比如滑动窗口、滚动窗口、会话窗口以及非常灵活的自定义的窗口。
05 Flink 应用场景
Flink的应用场景主要在这三个方面:
- 事件驱动:Event-driven Applications
- 数据分析:Data Analytics Applications
- 数据管道:Data Pipeline Applications
5.1 事件驱动(Event-driven Applications)
5.1.1 事件驱动应用与传统应用的区别
事件驱动型应用(Event-driven Applications):是一类具有状态的应用,它从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。
- 事件驱动型应用是在计算存储分离的传统应用基础上进化而来;
- 在传统架构中,应用需要读写远程事务型数据库,相反,事件驱动型应用是基于状态化流处理来完成。
- 在该设计中,数据和计算不会分离,应用只需访问本地(内存或磁盘)即可获取数据;
- 系统容错性的实现依赖于定期向远程持久化存储写入 checkpoint。
下图描述了传统应用和事件驱动型应用架构的区别:
从某种程度上来说,所有的实时的数据处理或者是流式数据处理都应该是属于Data Driven
,流计算本质上是Data Driven
计算。
5.1.2 风控系统案例
风控系统案例:
1、 当风控系统需要处理各种各样复杂的规则时,DataDriven
就会把处理的规则和逻辑写入到Datastream
的API
或者是ProcessFunction
的API
中;
2、 然后将逻辑抽象到整个Flink
引擎,当外面的数据流或者是事件进入就会触发相应的规则,这就是DataDriven
的原理;
3、 在触发某些规则后,DataDriven
会进行处理或者是进行预警,这些预警会发到下游产生业务通知,这是DataDriven
的应用场景,DataDriven
在应用上更多应用于复杂事件的处理![ ][nbsp5];
5.1.3 典型案例
- 欺诈检测(Fraud detection)
- 异常检测(Anomaly detection)
- 基于规则的告警(Rule-based alerting)
- 业务流程监控(Business process monitoring)
- Web应用程序(社交网络)
5.2 数据分析(Data Analytics Applications)
5.2.1 批处理和流处理分析
数据分析任务:需要从原始数据中提取有价值的信息和指标。
如下图所示,Apache Flink
同时支持流式及批量分析应用:
Data Analytics Applications包含以下两种分析:
- 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.2.2 典型案例
- 电信网络质量监控
- 移动应用中的产品更新及实验评估分析
- 消费者技术中的实时数据即席分析
- 大规模图分析
5.3 数据管道(Data Pipeline Applications)
5.3.1 什么是数据管道
首先我们了解下ETL(提取-转换-加载):
- ETL是一种在存储系统之间进行数据转换和迁移的常用方法;
- ETL 作业通常会周期性地触发,将数据从事务型数据库拷贝到分析型数据库或数据仓库;
那什么是数据管道呢?
数据管道和 ETL
作业的用途相似,都可以转换、丰富数据,并将其从某个存储系统移动到另一个,但数据管道是以持续流模式运行,而非周期性触发,因此数据管道支持从一个不断生成数据的源头读取记录,并将它们以低延迟移动到终点。
例如:
- 数据管道可以用来监控文件系统目录中的新文件,并将其数据写入事件日志;
- 另一个应用可能会将事件流物化到数据库或增量构建和优化查询索引;
5.3.1 数据管道与周期性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
中。
5.3.2 典型实例
- 电子商务中的持续 ETL(实时数仓):当下游要构建实时数仓时,上游则可能需要实时的Stream ETL,这个过程会进行实时清洗或扩展数据,清洗完成后写入到下游的实时数仓的整个链路中,可保证数据查询的时效性,形成实时数据采集、实时数据处理以及下游的实时Query。
- 电子商务中的实时查询索引构建(搜索引擎推荐):搜索引擎这块以淘宝为例,当卖家上线新商品时,后台会实时产生消息流,该消息流经过Flink系统时会进行数据的处理、扩展。然后将处理及扩展后的数据生成实时索引,写入到搜索引擎中。这样当淘宝卖家上线新商品时,能在秒级或者分钟级实现搜索引擎的搜索。
06 Flink的优势
6.1 选择Flink的原因
主要原因:
- Flink 具备统一的框架处理有界和无界两种数据流的能力;
- 部署灵活,Flink 底层支持多种资源调度器,包括Yarn、Kubernetes 等。Flink 自身带的Standalone 的调度器,在部署上也十分灵活;
- 极高的可伸缩性,可伸缩性对于分布式系统十分重要,阿里巴巴双11大屏采用 Flink 处理海量数据,使用过程中测得Flink 峰值可达17 亿条/秒。
- 极致的流式处理性能。Flink 相对于Storm 最大的特点是将状态语义完全抽象到框架中,支持本地状态读取,避免了大量网络IO,可以极大提升状态存取的性能。
6.2 支持高吞吐、低延迟、高性能
Flink同时支持高吞吐、低延迟、高性能:
- Flink 是目前开源社区中唯一一套集高吞吐、低延迟、高性能三者于一身的分布式流式数据处理框架;
- Spark 只能兼顾高吞吐和高性能特性,无法做到低延迟保障,因为Spark是用批处理来做流处理;
- Storm 只能支持低延时和高性能特性,无法满足高吞吐的要求。
下图显示了 Apache Flink
与 Apache Storm
在完成流数据清洗的分布式任务的性能对比:
6.3 支持事件时间(Event Time)概念
在流式计算领域中,窗口计算的地位举足轻重,但目前大多数框架窗口计算采用的都是系统时间(Process Time
),也就是事件传输到计算框架处理时,系统主机的当前时间。
Flink
能够支持基于事件时间(Event Time
)语义进行窗口计算:这种基于事件驱动的机制使得事件即使乱序到达甚至延迟到达,流系统也能够计算出精确的结果,保持了事件原本产生时的时序性,尽可能避免网络传输或硬件系统的影响。
6.4 支持有状态计算
Flink1.4开始支持有状态计算:所谓状态就是在流式计算过程中将算子的中间结果保存在内存或者文件系统中,等下一个事件进入算子后可以从之前的状态中获取中间结果,计算当前的结果,从而无须每次都基于全部的原始数据来统计结果,极大的提升了系统性能,状态化意味着应用可以维护随着时间推移已经产生的数据聚合。
6.5 支持高度灵活的窗口(Window)操作
Flink 将窗口划分为基于 Time
、Count
、Session
以及Data-Driven
等类型的窗口操作,窗口可以用灵活的触发条件定制化来达到对复杂的流传输模式的支持,用户可以定义不同的窗口触发机制来满足不同的需求。
6.6 基于轻量级分布式快照(Snapshot/Checkpoints)的容错机制
Flink 能够分布运行在上千个节点上,通过基于分布式快照技术的Checkpoints
,将执行过程中的状态信息进行持久化存储,一旦任务出现异常停止,Flink
能够从 Checkpoints
中进行任务的自动恢复,以确保数据处理过程中的一致性。
Flink 的容错能力是轻量级的,允许系统保持高并发,同时在相同时间内提供强一致性保证。
6.7 基于 JVM 实现的独立的内存管理
Flink 实现了自身管理内存的机制,通过使用散列,索引,缓存和排序有效地进行内存管理,通过序列化/反序列化机制将所有的数据对象转换成二进制在内存中存储,降低数据存储大小的同时,更加有效的利用空间。使其独立于 Java
的默认垃圾收集器,尽可能减少JVM GC
对系统的影响。
6.8 SavePoints 保存点
对于 7 * 24 小时运行的流式应用,数据源源不断的流入,在一段时间内应用的终止有可能导致数据的丢失或者计算结果的不准确,比如集群版本的升级,停机运维操作等。
值得一提的是,Flink
通过SavePoints
技术将任务执行的快照保存在存储介质上,当任务重启的时候,可以从事先保存的 SavePoints
恢复原有的计算状态,使得任务继续按照停机之前的状态运行。
Flink
保存点提供了一个状态化的版本机制,使得能以无丢失状态和最短停机时间的方式更新应用或者回退历史数据。
6.9 灵活的部署方式,支持大规模集群
Flink 被设计成能用上千个点在大规模集群上运行,除了支持独立集群部署外,Flink
还支持YARN
和Mesos
方式部署。
6.10 Flink 的程序内在是并行和分布式的
数据流可以被分区成 stream partitions
,operators
被划分为operator subtasks
,这些 subtasks
在不同的机器或容器中分不同的线程独立运行,operator subtasks
的数量就是operator
的并行计算数,不同的operator
阶段可能有不同的并行数;
如下图所示,source operator
的并行数为 2,但最后的sink operator
为1;
6.11 丰富的库
Flink 拥有丰富的库来进行机器学习,图形处理,关系数据处理等。
7 批流统一
在前面,我们知道了 “批流统一” 是Flink
的优势之一,在了解批流统一之前,很有必要了解大数据框架的发展史。
7.1 大数据计算引擎发展史
在国外一些社区,有很多人将大数据的计算引擎分成了 4 代,如下图:
这几年大数据的飞速发展,出现了很多热门的开源社区,其中著名的有 Hadoop
、Storm
,以及后来的 Spark
,他们都有着各自专注的应用场景。Spark
掀开了内存计算的先河,也以内存为赌注,赢得了内存计算的飞速发展。Spark
的火热或多或少的掩盖了其他分布式计算的系统身影。就像Flink
,也就在这个时候默默的发展着。
7.1.1 第1代 : Hadoop MapReduce
首先第一代的计算引擎,无疑就是 Hadoop
承载的 MapReduce
。它将计算分为两个阶段,分别为 Map
和 Reduce
。对于上层应用来说,就不得不想方设法去拆分算法,甚至于不得不在上层应用实现多个 Job
的串联,以完成一个完整的算法,例如迭代计算。
- 批处理
- Mapper、Reducer
7.1.2 第2代 : DAG框架(Tez) + MapReduce
由于这样的弊端,催生了支持 DAG
框架的产生,因此,支持 DAG
的框架被划分为第二代计算引擎,如Tez
以及更上层的Oozie
。这里我们不去细究各种 DAG
实现之间的区别,不过对于当时的 Tez
和 Oozie
来说,大多还是批处理的任务。
- 批处理
- 1个Tez = MR(1) + MR(2) + ... + MR(n)
- 相比MR效率有所提升
7.1.3 第3代 : Spark
接下来就是以 Spark
为代表的第三代的计算引擎。第三代计算引擎的特点主要是 Job
内部的 DAG
支持(不跨越 Job
),以及强调的实时计算。
在这里,很多人也会认为第三代计算引擎也能够很好的运行批处理的 Job
。
- 批处理、流处理、SQL高层API支持
- 自带DAG
- 内存迭代计算、性能较之前大幅提升
7.1.4 第4代 : Flink
随着第三代计算引擎的出现,促进了上层应用快速发展,例如各种迭代计算的性能以及对流计算和 SQL 等的支持。Flink 的诞生就被归在了第四代。这应该主要表现在 Flink
对流计算的支持,以及更一步的实时性上面。当然Flink
也可以支持 Batch
的任务,以及DAG
的运算。
- 批处理、流处理、SQL高层API支持;
- 自带DAG;
- 流式计算性能更高、可靠性更高。
7.2 流处理vs批处理
7.2.1 数据的时效性
日常工作中,我们一般会先把数据存储在表,然后对表的数据进行加工、分析。既然先存储在表中,那就会涉及到时效性概念。
如果我们处理以年,月为单位的级别的数据处理,进行统计分析,个性化推荐,那么数据的的最新日期离当前有几个甚至上月都没有问题。但是如果我们处理的是以天为级别,或者一小时甚至更小粒度的数据处理,那么就要求数据的时效性更高了。比如:
- 对网站的实时监控
- 对异常日志的监控
这些场景需要工作人员立即响应,这样的场景下,传统的统一收集数据,再存到数据库中,再取出来进行分析就无法满足高时效性的需求了。
7.2.1 流式计算和批量计算
概念:
- 批量计算(Batch Analytics):,右边是 Streaming Analytics, 统一收集数据->
存储到DB\->
对数据进行批量处理,就是传统意义上使用类似于 Map Reduce、Hive、Spark Batch等,对作业进行分析、处理、生成离线报表 - 流式计算(Streaming Analytics) : 顾名思义,就是对数据流进行处理,如使用流式分析引擎如 Storm,Flink实时处理分析数据,应用较多的场景如实时大屏、实时报表。
它们的主要区别:
- 与批量计算那样慢慢积累数据不同,流式计算立刻计算,数据持续流动,计算完之后就丢弃。
- 批量计算是维护一张表,对表进行实施各种计算逻辑。流式计算相反,是必须先定义好计算逻辑,提交到流式计算系统,这个计算作业逻辑在整个运行期间是不可更改的。
- 计算结果上,批量计算对全部数据进行计算后传输结果,流式计算是每次小批量计算后,结果可以立刻实时化展现。
7.3 批流统一
在大数据处理领域,批处理任务与流处理任务一般被认为是两种不同的任务,一个大数据框架一般会被设计为只能处理其中一种任务:
- MapReduce只支持批处理任务;
- Storm只支持流处理任务;
- Spark Streaming采用micro-batch架构,本质上还是基于Spark批处理对流式数据进行处理
Flink通过灵活的执行引擎,能够同时支持批处理任务与流处理任务
在执行引擎这一层,流处理系统与批处理系统最大不同在于节点间的数据传输方式:
1、 对于一个流处理系统,其节点间数据传输的标准模型是:当一条数据被处理完成后,序列化到缓存中,然后立刻通过网络传输到下一个节点,由下一个节点继续处理;
2、 对于一个批处理系统,其节点间数据传输的标准模型是:当一条数据被处理完成后,序列化到缓存中,并不会立刻通过网络传输到下一个节点,当缓存写满,就持久化到本地硬盘上,当所有数据都被处理完成后,才开始将处理后的数据通过网络传输到下一个节点;
这两种数据传输模式是两个极端,对应的是流处理系统对低延迟的要求和批处理系统对高吞吐量的要求。
Flink
的执行引擎采用了一种十分灵活的方式,同时支持了这两种数据传输模型:
- Flink以固定的缓存块为单位进行网络数据传输,用户可以通过设置缓存块超时值指定缓存块的传输时机。
- 如果缓存块的超时值为0,则Flink的数据传输方式类似上文所提到流处理系统的标准模型,此时系统可以获得最低的处理延迟
- 如果缓存块的超时值为无限大/-1,则Flink的数据传输方式类似上文所提到批处理系统的标准模型,此时系统可以获得最高的吞吐量
- 同时缓存块的超时值也可以设置为0到无限大之间的任意值。缓存块的超时阈值越小,则Flink流处理执行引擎的数据处理延迟越低,但吞吐量也会降低,反之亦然。通过调整缓存块的超时阈值,用户可根据需求灵活地权衡系统延迟和吞吐量
- 默认情况下,流中的元素并不会一个一个的在网络中传输,而是缓存起来伺机一起发送(默认为32KB,通过taskmanager.memory.segment-size设置),这样可以避免导致频繁的网络传输,提高吞吐量,但如果数据源输入不够快的话会导致后续的数据处理延迟,所以可以使用env.setBufferTimeout(默认100ms),来为缓存填入设置一个最大等待时间。等待时间到了之后,即使缓存还未填满,缓存中的数据也会自动发送。
- timeoutMillis > 0 表示最长等待 timeoutMillis 时间,就会flush
- timeoutMillis = 0 表示每条数据都会触发 flush,直接将数据发送到下游,相当于没有Buffer了(避免设置为0,可能导致性能下降)
- timeoutMillis = -1 表示只有等到 buffer满了或 CheckPoint的时候,才会flush。相当于取消了 timeout 策略
总结: Flink
以缓存块为单位进行网络数据传输,用户可以设置缓存块超时时间和缓存块大小来控制缓冲块传输时机,从而控制Flink的延迟性和吞吐量。
08 脑图总结
下面整理了一张脑图,方便大家回顾本文:
本文主要讲解Flink
的一些入门知识,谢谢大家的阅读,本文完!