什么是批处理和流处理,然后由传统数据处理架构为背景引出什么是有状态的流处理,为什么需要流处理,而什么又是有状态的流处理。进而再讲解流处理的发展和演变。而Flink作为新一代的流处理器,它有什么优势?它的相关背景及概念和特性又是什么?有哪些应用场景?
有界数据流
有开始有结束,在有限数据个数或者有限时间内的数据。
无界数据流
有开始无结束,数据源源不断。
批处理
可以认为是对有界数据流的处理。每一次处理有限个或者有限时间内的数据。
流处理
可以认为是对无界数据流的处理。数据来一个处理一个。
备注:从这个定义来说的话,既然批处理是每次处理有限个,那么每次处理一个也可以,但是这不就是和流处理一样了吗?我认为单从功能实现上来说的话,的确是可以这么说的。因为只要能把数据来一个处理一个就行了,而怎么实现的不管。但是在实现层面,批处理和流处理是两种不同的模式,实现当然也就有所区别。就好像spark和flink的区别一样,这个小伙伴可以自行了解。
举例解释:
数据原本上都是流式产生的,比如你浏览网页,没人知道你会浏览多久、浏览多少,就像我们每天看新闻每天都会产生数据。所以数据其实原本是源源不断的。再比如温度传感器,时时刻刻监测温度,源源不断发送数据过来。但是我们在处理的时候可以人为的去定义界限。比如:传感器来一个数据处理一个,这就叫做流处理。而我们也可以定义一个界限比如每次攒够10个数据再处理,这就叫做批处理。而来一个处理一个的源源不断的数据就是无界数据流,10个一批的处理的一批批的数据就是有界流。
为什么需要流处理?
答:因为原本数据都是流式产生的,而且很多业务中要求我们需要具有实时性,即来一个处理一个,并且能够快速返回结果。而批处理需要攒一批数据再处理这和实时返回相违背,所以我们需要流处理。
既然,现实中很多公司有这种实时业务,需要流处理。那么我们原有的实时场景,是怎么处理、实现的呢?
这是互联网行业应用程序最经典的处理流程。比如订单系统,用户通过订单系统进行了下单操作,那订单系统就会访问数据库,将订单进行保存,然后向客户响应是否下单成功等等这些操作都需要很好的实时性,能够快速向客户响应。
**优点:**简单明了,数据规模小时实时性较高。
缺点:
1.当数据规模越来越大,数据查询、还有联表查询等的效率就比较依赖于表的结构的设计和SQL调优,否则可能导致不能及时返回结果。
2.更改表的结构或者对数据库进行扩缩容影响会比较大
系统所处理的连续不断的事件,其实就是一个数据流。而对于每一个事件,系统都在收到之后进行相应的处理,这也是符合流处理的原则的。所以可以说,传统的事务处理,就是最基本的流处理架构。
在传统的事务处理架构中,后台系统总是需要去查询和更新数据库。这样当数据规模比较大的时候效率就会比较低。为了加快访问速度,我们可以把这个数据存到本地内存中,从内存中读写,效率极高。而这个数据我们称为状态。
状态
中间结果或者额外的辅助数据
有状态的流处理
通过存储和访问中间结果的流处理
举例:计算流式数据[4,2,6,1,8,4,…]累加和
第一个数据4,此时和为4,我们把这个和存入内存 sum=4
下一个数据2,此时从内存取出sum=4,加当前数2,sum=4+2=6 更新内存中sum的值。
下一个数6,此时从内存取出sum=6,加上当前数6,sum=6+6=12 更新内存中sum的值。
…
在这里,内存中的sum就是状态。
优点:
1.通过将数据存储在内存中,从内存读写数据效率高,不需要去优化SQL和考虑表设计问题。
2.现代流式处理架构往往都是分布式的,可以通过提高并行度或者增加服务器,方便扩展。
缺点:
适合更少需要历史数据的业务,大量的历史数据查询,如果在内存中存大量的历史数据,那将耗费大量资源。比如:累加和的例子,我们不需要前面的加过了的所有数字,只需要记录加过了的数字的和即可,所以想要知道前面加了哪些哪些数字就需要把前面的数字存起来。而如果我们用传统的事务处理我们是可以查询表数据把原来加过的所有数字都查出来的。现实使用中,流式处理也可以通过结合数据库来操作(比如历史输入数据、或者历史结果),流式的处理的状态往往偏向于业务或者功能实现而不是存储功能。
为什么需要有状态的流式处理?
答:在大数据处理中,往往数据规模比较大,而传统的事务处理架构存在一些缺陷——见【传统事务处理架构——原始的流式处理架构】,而有状态的流处理可以解决这些问题。
时间:2011年,代表:storm
特点:
1.专注于毫秒级延迟处理并保证系统故障时事件不会丢失
2.没有对结果的准确性和一致性提供保障
3.虽然数据出错时不会丢失,但是可能重复处理———即只能保证至少一次(at-least-once)语义
1.为什么说没有对结果的准确性和一致性提供保障?
答:在分布式里,由于网络传输等延迟,数据发送到各个服务器的上被处理的时间是不一样的,所以有的数据先产生,但是不一定就会被先处理。而第一代流处理架构并没有考虑这种情况,所以结果取决于事件到达事件和顺序。所以结果的准确性和一致性没有得到保障。
2.一致性语义
at-most-once:最多一次,数据最多会被处理一次,有可能数据丢失。
at-least-once:最少一次,数据最少会被处理一次,有可能被重复处理。
exactly-once:精确一次,数据会且只会被处理一次。
时间:2013年,为了解决第一代流处理架构的缺陷,于是有了Lambda架构,成为第二代开源流处理架构。
对于有状态的流处理,当数据越来越多时,我们必须用分布式的集群架构来获取更大的吞吐量。但是分布式架构会带来另一个问题:怎样保证数据处理的顺序是正确的呢?这也是第一代流处理存在的问题。第二代开源流处理器旨在解决这一问题。
对于批处理来说,这并不是一个问题。因为所有数据都已收集完毕,我们可以根据需要选择、排列数据,得到想要的结果,所以不会受到顺序的影响,但是缺点是延迟大。在流处理中,因为来一个处理一个所以其结果就受到了数据到来的顺序的影响,其结果的正确性难以保障,但是延迟小。
如何保障结果的正确并且延迟低呢?
所以Lambda架构就结合了流处理和批处理,架构图如下:
Lambda架构同时使用了流处理和批处理两套架构,流处理不管结果是否正确,来一个数据处理一个并快速输出,这个结果受到数据到来的时间和顺序的影响可能得到的“不是很准确的结果”。而批处理不受数据到达时间和顺序的影响,因为可以存一批再处理。所以得到的是正确的结果。最后会拿着这个数据去修正流处理的结果。
举例:
流数据产生[1,2,3,4,5,6,7…](按顺序),实际达到为[1,4,2,3,5,6,7…],每3个数据记录一次三个数的和
批处理来说,我可以先攒数据[1,4,2,3,5,6,7],然后按数据产生时间排序后[1,2,3,4,5,6,7],然后结果输出为[[6],[15]]
而流处理,[1,4,2]达到后,输出[7],[3,5, 6]到达后,输出[14],结果为[[7],[14]]。
然后通过批处理的结果去修正流处理的结果[7]->[6],[14]->[15]
优点:
a.保障了结果的正确性,同时满足低延迟
b.同时也做到了精确一次性保障
缺点:
a.难以配置和维护。需要维护批和流两套相同实现逻辑的代码,一旦业务改了,需要去修改两套处理,并且要保证两套程序在业务逻辑上等同。
b.更多的开发工作量。需要我们对一个应用程序, 做出两套语义上等效的逻辑实现,因为批处理和流处理是两套完全独立的系统,它们的 API 也完全不同。为了实现一个应用,付出了双倍的工作量。
时间:2015年 代表:Flink
(1)真正的从流处理上解决了结果对事件到来时间及顺序的依赖
为什么第二代不算?第二代虽然通过批处理分支保证了结果的正确性,但是对于用户看到的,只是流处理分支的近似正确的结果,而流处理其结果是受到事件时间和顺序影响的
(2)流批一体(不用像第二代一样搞批和流两套),高吞吐和低延迟
(3)真正的精确一次(exactly-once)的一致性保障
为什么第二代不算呢?因为它是借助了批处理来实现的,而新一代是真正的直接在流处理上做到了精确一致性
如何实现这些特性?将在后面一一叙述。
新一代流处理器还在不断添加新的功能:例如高可用、与资源管理框架紧密集成、动态扩容等 (这部分暂不叙述)
Flink的前身是一个叫做“Stratosphere”的项目。它起源于德国柏林工业大学(Technische Universität Berlin)Volker Markl教授于2008年提出的构想——>这个项目一群博士生从09年就是开始搞,到2014年才基本成熟——>2015 年阿里巴巴开始使用 Flink 并持续贡献社区(阿里内部还基于Flink做了一套Blink),2019年1月8日,阿里巴巴以 9000 万欧元(7亿元人民币)收购了创业公司 Data Artisans。从此Flink开始了新一轮的乘风破浪!
Apache Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。Flink 被设计为在所有常见的集群环境中运行,以内存中的速度和任何规模执行计算。
(1)高吞吐和低延迟。每秒处理数百万个事件,毫秒级延迟
(2)结果的准确性。Flink 提供了事件时间(event-time)和处理时间(processing-time) 语义。对于乱序事件流,事件时间语义仍然能提供一致且准确的结果。
(3)精确一次(exactly-once)的状态一致性保证
(4)可以连接到最常用的存储系统,如 Apache Kafka、Apache Cassandra、Elasticsearch、JDBC、Kinesis 和(分布式)文件系统,如 HDFS 和 S3
(5)高可用。本身高可用的设置,加上与 K8s,YARN 和 Mesos 的紧密集成,再加上从故障中快速恢复和动态扩展任务的能力,Flink 能做到以极少的停机时间 7×24 全天候运行。
(6)能够更新应用程序代码并将作业(jobs)迁移到不同的 Flink 集群,而不会丢失应用程序的状态。
大概看下有个印象即可,等对flink有了深入的了解,这些特性就很好理解了。
三类常见的应用
事件驱动型应用是在计算存储分离的传统应用基础上进化而来。在传统架构中,应用需要读写远程事务型数据库。事件驱动型应用是一类具有状态的应用,它从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。在传统架构中,应用需要读写远程事务型数据库。相反,事件驱动型应用是基于状态化流处理来完成。在该设计中,数据和计算不会分离,应用只需访问本地(内存或磁盘)即可获取数据。系统容错性的实现依赖于定期向远程持久化存储写入 checkpoint。下图描述了传统应用和事件驱动型应用架构的区别。
优势:
事件驱动型应用无须查询远程数据库,本地数据访问使得它具有更高的吞吐和更低的延迟。而由于定期向远程持久化存储的 checkpoint 工作可以异步、增量式完成,因此对于正常事件处理的影响甚微。事件驱动型应用的优势不仅限于本地数据访问。传统分层架构下,通常多个应用会共享同一个数据库,因而任何对数据库自身的更改(例如:由应用更新或服务扩容导致数据布局发生改变)都需要谨慎协调。反观事件驱动型应用,由于只需考虑自身数据,因此在更改数据表示或服务扩容时所需的协调工作将大大减少。
典型的事件驱动型应用实例
据分析任务需要从原始数据中提取有价值的信息和指标。传统的分析方式通常是利用批查询,或将事件记录下来并基于此有限数据集构建应用来完成。为了得到最新数据的分析结果,必须先将它们加入分析数据集并重新执行查询或运行应用,随后将结果写入存储系统或生成报告。
借助一些先进的流处理引擎,还可以实时地进行数据分析。和传统模式下读取有限数据集不同,流式查询或应用会接入实时事件流,并随着事件消费持续产生和更新结果。这些结果数据可能会写入外部数据库系统或以内部状态的形式维护。仪表展示应用可以相应地从外部数据库读取数据或直接查询应用的内部状态。
如下图所示,Apache Flink 同时支持流式及批量分析应用
优势:
和批量分析相比,由于流式分析省掉了周期性的数据导入和查询过程,因此从事件中获取指标的延迟更低。不仅如此,批量查询必须处理那些由定期导入和输入有界性导致的人工数据边界,而流式查询则无须考虑该问题。
另一方面,流式分析会简化应用抽象。批量查询的流水线通常由多个独立部件组成,需要周期性地调度提取数据和执行查询。如此复杂的流水线操作起来并不容易,一旦某个组件出错将会影响流水线的后续步骤。而流式分析应用整体运行在 Flink 之类的高端流处理系统之上,涵盖了从数据接入到连续结果计算的所有步骤,因此可以依赖底层引擎提供的故障恢复机制。
典型的数据分析应用实例
什么是数据管道?
提取-转换-加载(ETL)是一种在存储系统之间进行数据转换和迁移的常用方法。ETL 作业通常会周期性地触发,将数据从事务型数据库拷贝到分析型数据库或数据仓库。
数据管道和 ETL 作业的用途相似,都可以转换、丰富数据,并将其从某个存储系统移动到另一个。但数据管道是以持续流模式运行,而非周期性触发。因此它支持从一个不断生成数据的源头读取记录,并将它们以低延迟移动到终点。例如:数据管道可以用来监控文件系统目录中的新文件,并将其数据写入事件日志;另一个应用可能会将事件流物化到数据库或增量构建和优化查询索引。
下图描述了周期性 ETL 作业和持续数据管道的差异
优势:
和周期性 ETL 作业相比,持续数据管道可以明显降低将数据移动到目的端的延迟。此外,由于它能够持续消费和发送数据,因此用途更广,支持用例更多。
典型的数据管道应用实例
附:内容概要