原文地址:大数据计算引擎之Flink简介
Apache Flink是为分布式、高性能、随时可用以即准确的流处理应用程序打造的开源处理框架
Apache Flink是一个框架和分布式处理引擎,用于对无界和有界数据进行有状态计算,Flink被设计在所有常见的集群环境中运行,以内存执行速度和任意规模来执行计算。
[外链图片转存失败(img-bWUWJdZh-1567043547838)(en-resource://database/1282:1)]
Flink的几个模块
在流处理技术中,我们常见的Storm,层风靡一时。他是流处理的先锋,Storm提供了低延时的流处理,但是他为了实时性付出了一些代价:很难实现高吞吐,并且其正确性没能达到通常所需的水平,也就是说不能保证 exactly-once语义。
在低延时和高吞吐的流处理系统中维护良好的容错性是非常困难的,因此,开发人员提出将连续事件中的数据分割成一系列微小的批量作业。几遍分割在小,也无法做到完全的实时,这个就是Spark Streaming的使用方法。使用微批处理方法,可以实现exactly-once语义,从而保障状态的一致性。如果一个微批处理作业失败了,它可以重新运行。这比连续的流处理方法更容易。Storm Trident是对Storm的延伸,它的底层流处理引擎就是基于微批处理方法来进行计算的,从而实现了exactly-once语义,但是在延迟性方面付出了很大的代价。
通过间歇性的批处理作业来模拟流处理,会导致开发和运维相互交错。完成间歇性的批处理作业所需的时间和数据到达的时间紧密耦合,任何延迟都可能导致不一致(或者说错误)的结果。这种技术的潜在问题是,时间由系统中生成小批量作业的那一部分全权控制。Spark Streaming等一些流处理框架在一定程度上弱化了这一弊端,但还是不能完全避免。另外,使用这种方法的计算有着糟糕的用户体验,尤其是那些对延迟比较敏感的作业,而且人们需要在写业务代码时花费大量精力来提升性能。
也因此,Flink诞生了。Flink的一个优势是,它拥有诸多重要的流式计算功能。其他项目为了实现这些功能,都不得不付出代价。比如,Storm实现了低延迟,但是做不到高吞吐,也不能在故障发生时准确地处理计算状态; Spark Streaming通过采用微批处理方法实现了高吞吐和容错性,但是牺牲了低延迟和实时处理能力,也不能使窗口与自然时间相匹配,并且表现力欠佳。
看下面一张图,就是Flink , Spark Streaming , Storm三者之间的区别。
Micro Batching 模式(Spark)
该计算模式认为流是批的特例,流计算就是连续不断的批进行持续计算,但是该计算模式在一定程度上可以满足99%的实时计算场景,在该模式的架构实现上有一个自然流数据进入系统进行攒批的过程,这样就增加了延迟。如图所示:
可以看出,把输入流分割成微小的批次,然后一个批次一个批次的处理,一个批次一个批次的输出。
Native Streaming 模式(Flink)
该计算模式认为批是流的特例,其是将每条数据都进行计算,这种计算模式很自然,并且延迟性能更低,如图所示:
数据模型
Spark最早使用的是RDD模型,这个比MapReduce快了100倍的计算模型有着显著的优势。对Hadoop生态大幅升级换代。RDD弹性数据集是分割为固定大小的批数据。
Spark Streaming里的DStream和RDD模型类似,把一个实时进来的无线数据分割为一个小批数据集合DStream,定时器定时通知系统去处理这些微批数据。然而,API少,无法胜任复杂的流计算业务,调大吞吐量而不触发背压是个体力活,不支持乱序处理。
Flink的基本数据模型是数据流,及事件(Event)的序列。数据流作为数据的基本模型可能没有表或者数据块的直观熟悉,但是可以证明是完全等效的。流可以是无边界的无限流,即所谓的流处理。可以说,有边界的有限流,这样就是批处理。
Flink采用Dataflow模型,和Lambda模式不同。Dataflow是纯粹的节点组成的一个图,图中的节点可以执行流计算、批计算、机器学习算法,流数据在节点间流动,被节点上的处理函数实时apply处理,节点间使用Netty连接起来的。两个Netty间Keepalive,网络Buffer是自然反压的关键。经过逻辑优化和物理优化,Dadaflow的逻辑关系和运行的物理拓扑相差不大。这种纯粹的流式设计,时延和吞吐理论山是最优的。
Spark运行时架构
批计算是把DAG划分为不同stage,DAG节点之间有血缘关系,在运行期间一个stage的task任务列表执行完毕,销毁再去执行下一个stage;Spark Streaming则是对持续流入的数据划分一个批次,定时去执行批次的数据运算。Structured Streaming将无限输入流保存在状态存储中,对流数据做微批或实时的计算,跟Dataflow模型比较像。
Flink运行时架构
Flink有统一的runtime,在此之上可以是Batch API、Stream API、ML、Graph、CEP等,DAG中的节点上执行上述模块的功能函数,DAG会一步步转化成ExecutionGraph,即物理可执行的图,最终交给调度系统。节点中的逻辑在资源池中的task上被apply执行,task和Spark中的task类似,都对应线程池中的一个线程。
在DAG的执行上,Spark和Flink有一个比较显著的区别。在Flink的流执行模式中,一个事件在一个节点处理完后的输出就可以发到下一个节点立即处理。这样执行引擎并不会引入额外的延迟。与之相应的,所有节点是需要同时运行的。而Spark的micro batch和一般的batch执行一样,处理完上游的stage得到输出之后才开始下游的stage。
在流计算的运行时架构方面,Flink明显更为统一且优雅一些。
事件驱动型是一类具有状态的应用,他从一个或多个事件流提取数据,并根据到来的事件除法计算、状态更新或其他外部动作。比较典型就是Kafka为代表的的消息对列几乎是事件驱动型应用。
与之不同的是Spark Streaming微批次,如图:
而事件驱动型,如图所示:
批处理的特点是有界、持久、大量,非常适合需要访问全套记录才能完成的计算工作,一般用于离线统计。
流处理的特点是无界、实时,无需针对整个数据集执行操作,而是对通过系统传输的每个数据项执行操作,一般用于实时统计。
在Spark的世界观中,一切都是由批次组成的,离线数据是一个大批次,而实时数据是由一个一个无限的小批次组成的。
而在Flink的世界观中,一切都是由流组成的,离线数据是有界限的流,实时数据是一个没有界限的流,这就是所谓的有界流和无界流。
无界数据流:无界数据流有一个开始但是没有结束,它们不会在生成时终止并提供数据,必须连续处理无界流,也就是说必须在获取后立即处理event。对于无界数据流我们无法等待所有数据都到达,因为输入是无界的,并且在任何时间点都不会完成。处理无界数据通常要求以特定顺序(例如事件发生的顺序)获取event,以便能够推断结果完整性。
有界数据流:有界数据流有明确定义的开始和结束,可以在执行任何计算之前通过获取所有数据来处理有界流,处理有界流不需要有序获取,因为可以始终对有界数据集进行排序,有界流的处理也称为批处理。
这种以流为世界观的架构,获得最大好处就是具有极低的延迟
Flink目前作为批处理还不是主流,不如Spark成熟,因此DataSet使用不是很多,Flink Table API和Flink SQL也并不完善。Flink作为最接近Google DataFlow模型的实现,是流批统一的观点,因此使用DataStream
Apache Flink是一个分布式流处理器,具有直观和富有表现力的API,可实现有状态的流处理应用程序。它以容错的方式有效地大规模运行这些应用程序。
两种数据处理类型:事务处理(OLTP)和分析处理(OLAP)
公司系统通常设计有单独的层,用于数据处理(应用程序本身)和数据存储(事务数据库系统)。应用程序通常连接到外部服务或直接面向用户,并持续处理传入的事件。处理事件时,应用程序会读取数据库的状态,或者通过运行事务来更新它。
一般不会直接在事务数据库上运行分析查询,而是复制数据到数据仓库。数据仓库是对工作负载进行分析和查询的专用数据存储。为了填充数据仓库,需要将事务数据库系统管理的数据复制过来。将数据复制到数据仓库的过程称为extract-transform-load(ETL)。 ETL过程从事务数据库中提取数据,将其转换为某种通用的结构表示,可能包括验证,值的规范化,编码,重复数据删除(去重)和模式转换,最后将其加载到分析数据库中。 ETL过程可能非常复杂,并且通常需要技术复杂的解决方案来满足性能要求。 ETL过程需要定期运行以保持数据仓库中的数据同步。
将数据导入数据仓库后,可以查询和分析数据。通常,在数据仓库上执行两类查询。第一种类型是定期报告查询,用于计算与业务相关的统计信息,比如收入、用户增长或者输出的产量。这些指标汇总到报告中,帮助管理层评估业务的整体健康状况。第二种类型是即席查询,旨在提供特定问题的答案并支持关键业务决策,例如收集统计在投放商业广告上的花费,和获取的相应收入,以评估营销活动的有效性。两种查询由批处理方式由数据仓库执行,
如果我们想要无限处理事件流,并且不愿意繁琐地每收到一个事件就记录一次,那这样的应用程序就需要是有状态的,也就是说能够存储和访问中间数据。当应用程序收到一个新事件时,它可以从状态中读取数据,或者向该状态写入数据,总之可以执行任何计算。原则上讲,我们可以在各种不同的地方存储和访问状态,包括程序变量(内存)、本地文件,还有嵌入式或外部数据库。
Apache Flink将应用程序状态,存储在内存或者嵌入式数据库中。由于Flink是一个分布式系统,因此需要保护本地状态以防止在应用程序或计算机故障时数据丢失。 Flink通过定期将应用程序状态的一致性检查点(check point)写入远程且持久的存储,来保证这一点。状态、状态一致性和Flink的检查点将在后面的章节中更详细地讨论,但是,现在,图1-4显示了有状态的流式Flink应用程序。
有状态的流处理应用程序,通常从事件日志中提取输入事件。事件日志就用来存储和分发事件流。事件被写入持久的仅添加(append-only)日志,这意味着无法更改写入事件的顺序。写入事件日志的流,可以被相同或不同的消费者多次读取。由于日志的仅附加(append-only)属性,事件始终以完全相同的顺序发布给所有消费者。现在已有几种事件日志系统,其中Apache Kafka是最受欢迎的,可以作为开源软件使用,或者是云计算提供商提供的集成服务。
在Flink上运行的有状态的流处理应用程序,是很有意思的一件事。在这个架构中,事件日志会按顺序保留输入事件,并且可以按确定的顺序重播它们。如果发生故障,Flink将从先前的检查点(check point)恢复其状态,并重置事件日志上的读取位置,这样就可以恢复整个应用。应用程序将重放(并快进)事件日志中的输入事件,直到它到达流的尾部。此技术一般用于从故障中恢复,但也可用于更新应用程序、修复bug或者修复以前发出的结果,另外还可以用于将应用程序迁移到其他群集,或使用不同的应用程序版本执行A / B测试。
如前所述,有状态的流处理是一种通用且灵活的设计架构,可用于许多不同的场景。在下文中,我们提出了三类通常使用有状态流处理实现的应用程序:(1)事件驱动应用程序,(2)数据管道应用程序,以及(3)数据分析应用程序。
我们将应用程序分类描述,是为了强调有状态流处理适用于多种业务场景;而实际的应用中,往往会具有以上多种情况的特征。
事件驱动的应用程序是由状态的流应用程序,使用特定的业务逻辑来提取事件流并处理事件。
以较低的延迟,来提取、转换和插入数据是有状态流处理应用程序的另一个常见应用场景。这种类型的应用程序称为数据管道(data pipeline)。数据管道必须能够在短时间内处理大量数据。操作数据管道的流处理器还应具有许多源(source)和接收器(sink)的连接器,以便从各种存储系统读取数据并将数据写入各种存储系统。当然,同样地,Flink完成了所有这些功能
ETL作业定期将数据导入数据存储区,数据的处理是由即席查询(用户自定义查询)或设定好的通常查询来做的。无论架构是基于数据仓库还是基于Hadoop生态系统的组件,这都是批处理。多年来最好的处理方式就是,定期将数据加载到数据分析系统中,但它给分析管道带了的延迟相当大,而且无法避免。
流式分析应用程序不是等待定期触发,而是连续地提取事件流,并且通过纳入最新事件来更新其计算结果,这个过程是低延迟的。这有些类似于数据库中用于更新视图(views)的技术。通常,流应用程序将其结果存储在支持更新的外部数据存储中,例如数据库或键值(key-value)存储。流分析应用程序的实时更新结果可用于驱动监控仪表板(dashboard)应用程序。
流分析应用程序最大的优势就是,将每个事件纳入到分析结果所需的时间短得多。除此之外,流分析应用程序还有另一个不太明显的优势。传统的分析管道由几个独立的组件组成,例如ETL过程、存储系统、对于基于Hadoop的环境,还包括用于触发任务(jobs)的数据处理和调度程序。相比之下,如果我们运行一个有状态流应用程序,那么流处理器就会负责所有这些处理步骤,包括事件提取、带有状态维护的连续计算以及更新结果。此外,流处理器可以从故障中恢复,并且具有精确一次(exactly-once)的状态一致性保证,还可以调整应用程序的计算资源。像Flink这样的流处理器还支持事件时间(event-time)处理,这可以保证产生正确和确定的结果,并且能够在很短的时间内处理大量数据。
Apache Flink是第三代分布式流处理器,它拥有极富竞争力的功能。它提供准确的大规模流处理,具有高吞吐量和低延迟。特别的是,以下功能使Flink脱颖而出:
事件时间(event-time)和处理时间(processing-tme)语义。即使对于无序事件流,事件时间(event-time)语义仍然能提供一致且准确的结果。而处理时间(processing-time)语义可用于具有极低延迟要求的应用程序。
精确一次(exactly-once)的状态一致性保证。
每秒处理数百万个事件,毫秒级延迟。 Flink应用程序可以扩展为在数千个核(cores)上运行。
分层API,具有不同的权衡表现力和易用性。本书介绍了DataStream API和过程函数(process function),为常见的流处理操作提供原语,如窗口和异步操作,以及精确控制状态和时间的接口。本书不讨论Flink的关系API,SQL和LINQ风格的Table API。
连接到最常用的存储系统,如Apache Kafka,Apache Cassandra,Elasticsearch,JDBC,Kinesis和(分布式)文件系统,如HDFS和S3。
由于其高可用的设置(无单点故障),以及与Kubernetes,YARN和Apache Mesos的紧密集成,再加上从故障中快速恢复和动态扩展任务的能力,Flink能够以极少的停机时间 7 * 24全天候运行流应用程序。
能够更新应用程序代码并将作业(jobs)迁移到不同的Flink集群,而不会丢失应用程序的状态。
详细且可自定义的系统和应用程序指标集合,以提前识别问题并对其做出反应。
最后但同样重要的是,Flink也是一个成熟的批处理器。
除了这些功能之外,Flink还是一个非常易于开发的框架,因为它易于使用的API。嵌入式执行模式,可以在单个JVM进程中启动应用程序和整个Flink系统,这种模式一般用于在IDE中运行和调试Flink作业。在开发和测试Flink应用程序时,此功能非常有用。