Flink作为主流的分布式计算框架,满足批流一体、高吞吐低时延、大规模复杂计算、高可靠的容错和多平台部署能力。本文简要介绍了Flink中的数据流处理流程以及基本部署架构和概念,以加深对分布式计算平台的了解。
Apache Flink是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。在现有的开源计算框架中,流式处理和批量处理会作为不同的应用类型,流处理一般需要低延迟和Extract-one保证,而批量处理需要支持高吞吐和高效处理,因此在实现上一般会采用不同的计算框架,比如流处理使用Storm而批量处理使用MapReduce计算引擎。而Flink能同时支持面向分布式流式处理和批量处理的应用场景,也就是作为流处理看待时输入数据流是无界的;批处理被作为一种特殊的流处理,只是它的输入数据流被定义为有界的。在运行Flink时,分别提供了流式和批处理的API,这两类API也是流处理和批处理应用的基础。
Flink官网:https://flink.apache.org/
核心理念:Apache Flink是为分布式、高性能、随时可用以及准确的流处理应用程序打造的开源流处理框架
Flink支持开发和运行多种不同种类的应用程序,它的主要特性包括:批流一体化、精密的状态管理、事件时间支持以及Exectly-one的状态一致性保障等。Flink不仅可以运行在包括YARN、Mesos、Kubernetes在内的多种资源管理框架上,还支持在裸机集群上独立部署。在启用高可用选项的情况下,它不存在单点失效问题。事实证明,Flink已经可以扩展到数千核心,其状态可以达到TB级别,且仍能保持高吞吐、低延迟的特性。对比其它类的开源计算框架,Flink流处理具有以下特性:
Flink适合以下应用场景:
事件驱动型应用是一类具有状态的应用,它从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。事件驱动型应用是在计算存储分离的传统应用基础上进化而来。在传统架构中,应用需要读写远程事务型数据库。相反,事件驱动型应用是基于状态化流处理来完成。在该设计中,数据和计算不会分离,应用只需访问本地(内存或磁盘)即可获取数据。系统容错性的实现依赖于定期向远程持久化存储写入checkpoint。下图描述了传统应用和事件驱动型应用架构的区别。
相比传统的应用架构,事件驱动型不需要实时访问后端的数据库,而定期向数据库持久化的checkpoint动作也可以异步、增量的方式实现,对数据库性能和架构稳定性依赖更低。不过事件驱动型应用会受制于底层流处理系统对时间和状态的把控能力,Flink提供了一系列丰富的状态操作原语,允许以Exactly-one的一致性语义合并海量规模(TB 级别)的状态数据。此外,Flink还支持事件时间和自由度极高的定制化窗口逻辑,而且它内置的ProcessFunction支持细粒度时间控制,方便实现一些高级业务逻辑。同时,Flink还拥有一个复杂事件处理(CEP)类库,可以用来检测数据流中的模式。
数据分析任务需要从原始数据中提取有价值的信息和指标。传统的分析方式通常是利用批查询,或将事件记录下来并基于此有限数据集构建应用来完成。为了得到最新数据的分析结果,必须先将它们加入分析数据集并重新执行查询或运行应用,随后将结果写入存储系统或生成报告。
和传统模式下读取有限数据集不同,流式查询或应用会接入实时事件流,并随着事件消费持续产生和更新结果。这些结果数据可能会写入外部数据库系统或以内部状态的形式维护。图形化展示应用可以相应地从外部数据库读取数据或直接查询应用的内部状态。
Flink支持实时的流式分析和批量分析,其中内置了标准的SQL接口,将批量和流式的查询接口统一起来,无论是在记录事件的静态数据集上还是实时事件流上,相同SQL查询都会得到一致的结果。
提取-转换-加载(ETL)是一种在存储系统之间进行数据转换和迁移的常用方法。ETL作业通常会周期性地触发,将数据从事务型数据库拷贝到分析型数据库或数据仓库。但数据管道是以持续流模式运行,而非周期性触发,因此它支持从一个不断生成数据的源头读取记录,并将它们以低延迟移动到终点。和周期性ETL作业相比,持续数据管道可以明显降低将数据移动到目的端的延迟。此外,由于它能够持续消费和发送数据,因此用途更广,支持用例更多。
Flink为多种数据存储系统(如:Kafka、Kinesis、Elasticsearch、JDBC数据库系统等)内置了连接器,利用Flink的SQL接口进行数据转换和增强操作。
任何类型的数据都可以形成一种事件流,交易数据、传感器测量、机器日志、网站或移动应用程序上的用户交互记录,所有这些数据都形成一种流。数据可以被作为无界或者有界流来处理。
Flink程序的基本构建块是流和转换,流是数据记录流,而转换是将一个或多个流进行转换的操作。
Flink应用程序结构如上图所示,分为三部分:Source、Transformation和Sink
Flink中数据流是核心数据的抽象,在Flink中使用DataStream表示数据流,在DataStream上定义了常见的数据处理操作API。Flink程序在执行的时候,会被映射成一个Streaming Dataflow,一个Streaming Dataflow是由一组Stream和Transformation Operator组成的。在启动时从一个或多个Source Operator开始,结束于一个或多个Sink Operator。
Flink在本质上是并行和分布式处理,当数据量超过单个节点的处理能力时,需要将一份数据切分到多个分区上,每个分区分布在一台服务器。上图展示了数据流从逻辑视图转换为物理执行图,map()算子在每个分区上都有一个算子子任务,算子子任务之间是相互独立的,每个算子子任务在不同的线程中独立执行,图中并行度为2,表示有2个并行执行的任务。
Flink中的所有操作称为算子,客户端在提交任务的时候会对算子进行优化操作,能进行合并的算子会被合并为一个,合并后的算子称为算子链,实际上就是一个执行链,每个执行链会在TaskManager上一个独立的线程中执行。将算子链接成task能够减少线程间切换、缓冲的开销,并且减少延迟的同时增加整体吞吐量。
Flink集群是由一个JobManager和多个TaskManager组成的:Client用来提交任务给JobManager,JobManager分发任务给TaskManager去执行,然后TaskManager会以心跳的方式汇报任务状态。从架构图去看,JobManager很像Hadoop中的JobTracker,TaskManager也很像Hadoop中的TaskTracker。
JobClient不是Flink程序执行的内部部分,它是任务执行的起点。主要职责如下:
JobManager是主进程(也称为作业管理器)协调和管理程序的执行。JobManager决定何时调度下一个task、对完成的task或执行失败做出反应、协调checkpoint、并且协调从失败中恢复等等。在整个集群中至少有一个Master,负责调度task,协调checkpoints和容灾。如果是高可用架构可以设置多个Master,但是只有一个是Leader,其它是standby。
JobManager进程由三个不同的组件组成:
TaskManager从JobManager处接收需要部署的Task,并部署和启动任务, 接收上游的数据并处理,是实际负责执行计算的节点。
TaskSlot即任务槽,是TaskManager中资源调度的最小单位,task slot的数量表示并发处理task的数量。类似YARN当中的Container,用于资源的封装,但是在Flink中,taskSlot只负责封装内存的资源,不包含CPU的资源。
Flink基本工作流程如上图所示:
每个 worker(TaskManager)都是一个 JVM 进程,可以在单独的线程中执行一个或多个 subtask。为了控制一个TaskManager中接受多少个task,就有了所谓的 task slots(至少一个)。
默认情况下,Flink允许subtask共享slot,即便它们是不同的task的subtask,只要是来自于同一作业即可。结果就是一个slot可以持有整个作业管道。允许slot共享有两个主要优点:
Flink具有分层架构,其中每个组件都是特定层的一部分,每层都建立在其他层之上,以实现清晰的抽象。Flink组件栈分为4层:Deploy层、Runtime层、API层和上层工具
1)Deploy部署层
Flink支持多种部署模式,包括local、cluster以及cloud部署
2)Runtime运行时层
Runtime层是Flink最底层也是最核心的组件,为Flink各类计算提供了实现。
3)API层
API层主要实现了流处理DataStream和批处理DataSet的API,DataStream和DataSet API是程序员可用于定义 Job 的接口。编译程序时,这些API会生成JobGraphs。
4)上层工具
Flink在流处理和批处理API之上,提供了丰富的工具,包括面向流处理的CEP、面向批处理的图计算、面向SQL的table API、 机器学习的FlinkML等。
参考资料: