先来说说Flink的发展史!
“Flink是由德国几所大学发起的的学术项目,后来不断发展壮大,并于2014年末成为Apache顶级项目。Flink主要面向流处理,如果说Spark是批处理界的王者,那么Flink就是流处理领域的冉冉升起的新星。在 Flink之前,不乏流式处理引擎,比较著名的有Storm、Spark Streaming,但某些特性远不如Flink。
”
其次看一下流处理框架演进史!
“第一代被广泛采用的流处理框架是Strom。在多项基准测试中,Storm的数据吞吐量和延迟都远逊于Flink。Storm只支持"at least once"和"at most once",即数据流里的事件投递只能保证至少一次或至多一次,不能保证只有一次。对于很多对数据准确性要求较高的应用,Storm有一定劣势。第二代非常流行的流处理框架是Spark Streaming。Spark Streaming使用mini-batch的思想,每次处理一小批数据,一小批数据包含多个事件,以接近实时处理的效果。因为它每次计算一小批数据,因此总有一些延迟。但Spark Streaming的优势是拥有Spark这个靠山,用户从Spark迁移到Spark Streaming的成本较低,因此能给用户提供一个批量和流式于一体的计算框架。
Flink是与上述两代框架都不太一样的新一代计算框架,它是一个支持在有界和无界数据流上做有状态计算的大数据引擎。它以事件为单位,并且支持SQL、State、WaterMark等特性。它支持"exactly once",即事件投递保证只有一次,不多也不少,这样数据的准确性能得到提升。比起Storm,它的吞吐量更高,延迟更低,准确性能得到保障;比起Spark Streaming,它以事件为单位,达到真正意义上的实时计算,且所需计算资源相对更少。
之前提到,数据都是以流的形式产生的。数据可以分为有界(bounded)和无界(unbounded),批量处理其实就是一个有界的数据流,是流处理的一个特例。Flink基于这种思想,逐步发展成一个可支持流式和批量处理的大数据框架。
经过几年的发展,Flink的API已经非常完善,可以支持Java、Scala和Python,并且支持SQL。Flink的Scala版API与Spark非常相似,有Spark经验的程序员可以用一个小时的时间熟悉Flink API。
与Spark类似,Flink目前主要面向计算,并且可以与Hadoop生态高度集成。Spark和Flink各有所长,也在相互借鉴,一边竞争,一边学习,究竟最终谁能一统江湖,我们拭目以待。
”
一、初遇Flink
1.1 Flink是什么
“Apache Flink 是由 Apache 软件基金会开发的开源流处理框架,其核心是用 Java 和 Scala 编写的分布式流数据流引擎。Flink 以数据并行和流水线方式执行任意流数据程序,Flink 的 流水线运行时系统可以执行批处理和流处理程序。此外,Flink 的运行时本身也支持迭代算 法的执行。
”
Flink的官网主页地址: https://flink.apache.org/
1.2 为什么选择Flink
“流数据更真实的反映了我们的生活方式
传统的数据架构是基于有限数据集的
针对无限和有限数据流进行有状态计算的分布式执行引擎框架。集群部署,随意扩容;内存计算,速度快。
”
1.3 流处理应用的基本组件
“可以由流处理框架构建和执行的应用程序类型是由框架对 流、状态、时间 的支持程度来决定的。在下文中,我们将对上述这些流处理应用的基本组件逐一进行描述,并对 Flink 处理它们的方法进行细致剖析。
”
流 | |
状态 | 在一定时间内存储所接收的事件或中间结果 |
时间 | 事件时间,根据事件本身自带的时间戳进行结果的计算,保证结果的准确性和一致性。 处理时间,根据处理引擎的机器时钟触发计算,低延迟需求,并且能够容忍近似结果。 |
1.3.1 应用场景
事件驱动型应用 | 从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。 |
数据分析应用 | 从原始数据中提取有价值的信息和指标。 |
数据管道应用 | 数据管道和 ETL 作业的用途相似,都可以转换、丰富数据,并将其从某个存储系统移动到另一个。但数据管道是以持续流模式运行,而非周期性触发。 |
提取-转换-加载(ETL):一种在存储系统之间进行数据转换和迁移的常用方法。ETL 作业通常会周期性地触发,将数据从事务型数据库拷贝到分析型数据库或数据仓库。 |
1.3.2 流式数据处理的发展和演变
- 流处理和批处理
“数据处理有不同的方式。
对于具体应用来说,有些场景数据是一个一个来的,是一组有序的数据序列,我们把它叫作“数据流”;而有些场景的数据,本身就是一批同时到来,是一个有限的数据集,这就是批量数据(有时也直接叫数据集)。
处理数据流,应该“来一个就处理一个”,这种数据处理模式就叫作流处理;因为这种处理是即时的,所以也叫实时处理。与之对应,处理批量数据自然就应该一批读入、一起计算,这种方式就叫作批处理,也叫作离线处理。
流数据更真实地反映了我们的生活方式。真实场景中产生的,一般都是数据流。
”
- 传统事务处理
“IT互联网公司往往会用不同的应用程序来处理各种业务。比如内部使用的企业资源规划(ERP)系统、客户关系管理(CRM)系统,还有面向客户的Web应用程序。
”
“这些应用程序在处理数据的模式上有共同之处:接收的数据是持续生成的事件,比如用户的点击行为,客户下的订单,或者操作人员发出的请求。处理事件时,应用程序需要先读取远程数据库的状态,然后按照处理逻辑得到结果,将响应返回给用户,并更新数据库状态。一般来说,一个数据库系统可以服务于多个应用程序,它们有时会访问相同的数据库或表。这就是传统的“事务处理”架构。
”
- 有状态的流处理
“我们可以把流处理需要的额外数据保存成一个“状态”,然后针对这条数据进行处理,并且更新状态。这就是所谓的“有状态的流处理”。
为了加快访问速度,我们可以直接将状态保存在本地内存。当应用收到一个新事件时,它可以从状态中读取数据,也可以更新状态。而当状态是从内存中读写的时候,这就和访问本地变量没什么区别了,实时性可以得到极大的提升。
另外,数据规模增大时,我们也不需要做重构,只需要构建分布式集群,各自在本地计算就可以了,可扩展性也变得更好。
因为采用的是一个分布式系统,所以还需要保护本地状态,防止在故障时数据丢失。我们可以定期地将应用状态的一致性检查点(checkpoint)存盘,写入远程的持久化存储,遇到故障时再去读取进行恢复,这样就保证了更好的容错性。
”
有状态的流处理是一种通用而且灵活的设计架构,可用于许多不同的场景。具体来说,有以下几种典型应用。
- 事件驱动型(Event-Driven)应用
- 数据分析(Data Analysis)型应用
- 数据管道(Data Pipeline)型应用
“有状态的流处理架构上其实并不复杂,很多用户基于这种思想开发出了自己的流处理系统,这就是第一代流处理器。Apache Storm就是其中的代表。Storm 提供了低延迟的流处理,但很难实现高吞吐,而且无法保证结果的正确性。
”
- Lambda架构
“与批处理器相比,第一代流处理器牺牲了结果的准确性,用来换取更低的延迟。而批处理器恰好反过来,牺牲了实时性,换取了结果的准确。
我们自然想到,如果可以让二者做个结合,不就可以同时提供快速和准确的结果了吗?正是基于这样的思想,产生了所谓的Lambda架构。
”
“Lambda架构主体是传统批处理架构的增强。它的“批处理层”(Batch Layer)就是由传统的批处理器和存储组成,而“实时层”(Speed Layer)则由低延迟的流处理器实现。数据到达之后,一方面由流处理器进行实时处理,另一方面写入批处理存储空间,等待批处理器批量计算。流处理器快速计算出一个近似结果,并将它们写入“流处理表”中。而批处理器会定期处理存储中的数据,将准确的结果写入批处理表,并从快速表中删除不准确的结果。最终,应用程序会合并快速表和批处理表中的结果,并展示出来。
Lambda架构现在已经不再是最先进的,但仍在许多地方使用。它的优点非常明显,就是兼具了批处理器和第一代流处理器的特点,同时保证了低延迟和结果的准确性。而它的缺点同样非常明显。首先,Lambda架构本身就很难建立和维护;而且,它需要我们对一个应用程序,做出两套语义上等效的逻辑实现,因为批处理和流处理是两套完全独立的系统,它们的API也完全不同。
”
- 新一代流处理器
“之前的分布式流处理架构,都有明显的缺陷,人们也一直没有放弃对流处理器的改进和完善。终于,在原有流处理器的基础上,新一代分布式开源流处理器诞生了。为了与之前的系统区分,我们一般称之为第三代流处理器,代表当然就是Flink。
第三代流处理器通过巧妙的设计,完美解决了乱序数据对结果正确性的影响。这一代系统还做到了精确一次(exactly-once)的一致性保障,是第一个具有一致性和准确结果的开源流处理器。另外,先前的流处理器仅能在高吞吐和低延迟中二选一,而新一代系统能够同时提供这两个特性。所以可以说,这一代流处理器仅凭一套系统就完成了Lambda架构两套系统的工作。
”
二、Flink的应用
2.1 Flink在企业中的应用
“Flink为全球许多公司和企业的关键业务应用提供了强大的支持。以下是Flink官网列出的知名企业用户,如图所示,他们在生产环境中有各种各样有趣的应用。
”
2.2 Flink主要的应用场景
“可以看到,各种行业的众多公司都在使用Flink。具体来看,一些行业中的典型应用有:
- 电商和市场营销
举例:实时数据报表、广告投放、实时推荐
- 物联网(IOT)
举例:传感器实时数据采集和显示、实时报警,交通运输业
- 物流配送和服务业
举例:订单状态实时更新、通知信息推送
- 银行和金融业
举例:实时结算和通知推送,实时检测异常行为
”
2.3 Flink的优势及特性
1. Flink优势
“”
- 批流统一
- 支持高吞吐、低延迟、高性能的流处
- 支持带有事件时间的窗口(Window)操作
- 支持有状态计算的 Exactly-once 语义
- 支持高度灵活的窗口(Window)操作,支持基于 time、count、session 窗口操作
- 支持具有 Backpressure 功能的持续流模型
- 支持基于轻量级分布式快照(Snapshot)实现的容错
- 支持迭代计算
- Flink 在 JVM 内部实现了自己的内存管理
- 支持程序自动优化:避免特定情况下 Shuffle、排序等昂贵操作,中间结果有必要进行 缓存
2. Flink特性
Flink是第三代分布式流处理器,它的功能丰富而强大。主要特性如下。
“”
- 高吞吐和低延迟。每秒处理数百万个事件,毫秒级延迟。
- 结果的准确性。Flink提供了事件时间(event-time)和处理时间(processing-time)语义。对于乱序事件流,事件时间语义仍然能提供一致且准确的结果。
- 精确一次(exactly-once)的状态一致性保证。
- 可以连接到最常用的存储系统,如Apache Kafka、Apache Cassandra、Elasticsearch、JDBC、Kinesis和(分布式)文件系统,如HDFS和S3。
- 高可用。本身高可用的设置,加上与K8s,YARN和Mesos的紧密集成,再加上从故障中快速恢复和动态扩展任务的能力,Flink能做到以极少的停机时间7×24全天候运行。
- 能够更新应用程序代码并将作业(jobs)迁移到不同的Flink集群,而不会丢失应用程序的状态。
三、Flink编程 API
除了上述这些特性之外,Flink还是一个非常易于开发的框架,因为它拥有易于使用的分层API,整体API分层如图所示。
“最底层级的抽象仅仅提供了有状态流,它通过处理函数(Process Function)嵌入到DataStream API中。底层处理函数(Process Function) 与 DataStream API 相集成,使其可以对某些特定的操作进行底层的抽象,它允许用户可以自由地处理来自一个或多个数据流的事件,并使用一致的容错的状态。除此之外,用户可以注册事件时间并处理时间回调,从而使程序可以处理复杂的计算。
实际上,大多数应用并不需要底层抽象,而是直接针对核心API(Core APIs) 进行编程,比如DataStream API以及DataSet API。这些API为数据处理提供了通用的构建模块,比如转换(transformations),连接(joins),聚合(aggregations),窗口(windows)操作等。
Table API 是以表为中心的声明式编程,其中表可能会动态变化(在表达流数据时)。Table API遵循关系模型:表有二维数据结构,类似于关系数据库中的表;同时API提供可比较的操作,例如select、project、join、group-by、aggregate等。我们可以在表与 DataStream/DataSet 之间无缝切换,以允许程序将 Table API 与 DataStream 以及 DataSet 混合使用。
Flink提供的最高层级的抽象是SQL。这一层抽象在语法与表达能力上与 Table API 类似,但是是以SQL查询表达式的形式表现程序。SQL抽象与Table API交互密切,同时SQL查询可以直接在Table API定义的表上执行。
目前Flink SQL和Table API还在开发完善的过程中,很多大厂都会二次开发符合自己需要的工具包。而DataSet作为批处理API实际应用较少,2020年12月8日发布的新版本1.12.0, 已经完全实现了真正的流批一体,DataSet API已处于软性弃用(soft deprecated)的状态。用Data Stream API写好的一套代码, 即可以处理流数据, 也可以处理批数据。这与之前版本处理有界流的方式是不一样的,Flink已专门对批处理数据做了优化处理。所以我们以介绍DataStream API为主,采用的是目前的最新版本Flink 1.13.0。
”
四、Flink架构
4.1 架构图
4.2 含义
“
- JobManager
也称之为 Master,用于协调分布式执行,它用来调度 task,协调检查点,协调失败时恢复 等。Flink 运行时至少存在一个 master,如果配置高可用模式则会存在多个 master,它们其 中有一个是 leader,而其他的都是 standby。
- TaskManager
也称之为 Worker,用于执行一个 dataflow 的 task、数据缓冲和 Data Streams 的数据交换, Flink 运行时至少会存在一个 TaskManager。JobManager 和 TaskManager 可以直接运行在物理 机上,或者运行 YARN 这样的资源调度框架,TaskManager 通过网络连接到 JobManager,通 过 RPC 通信告知自身的可用性进而获得任务分配。
- Client
Flink 用来提交任务的客户端,可以用命令提交,也可以用浏览器提交
- Task
Task 是一个阶段多个功能相同 suntask 的集合,类似 spark 中的 taskset
- Subtask
Subtask 是 flink 中任务执行最小单元,是一个 java 类的实例,这份 java 类中有属性和方法, 完成具体的计算逻辑
- Operator chain
没有 shuffle 的多个算子合并在一个 subtask 中就形成了 Operator chain,类似 spark 中的 pipeline
- Slot
Flink 中计算资源进行隔离的单元,一个 slot 中可以运行多个 subtask,但是这些 subtask 必须 是来自同一个 job 的不同 task 的 subtask
- State
Flink 任务运行过程中计算的中间结果
- Checkpoint
Flink 用来将中间结果持久化的指定的存储系统的一种定期执行的机制
- stateBackend
Flink 用来存储中间计算结果的存储系统,flink 支持三种 statebackend。分别是 memory, fsbackend,rocksDB