听程序员界郭德纲怎么“摆”大数据处理
前言:
号称西蜀吴冠希,是我们团队的段子手,人帅话溜思考深。看他怎么用郭德纲的段子来盘大数据处理的前世今生。一家之言,欢迎讨论,最好带来一个,"XXX是大数据处理群里最好的PHP语言" 的争论。
对于不做大数据的技术人员,也能够很快的从本文中理解这些大数据框架的优缺点,选型策略。
文章10000字以上,阅读需要30分钟,翻过需要10秒。
翻都不想翻?好吧,文末有彩蛋的哦!
大规模数据处理技术如果从MapReduce论文算起,
如果参考人类发展史的划分,
大规模数据处理的技术的五个时代和四代引擎
石器时代
随着互联网的蓬勃发展,数据量在呈指数型增长。 早在2003年之前, 各大厂商都已经严重面临大规模数据的处理难题, 比如Google就已经面对大于600亿的搜索量。 如何从海量的原始数据中挖掘出有效的信息, 如何保证数据挖掘程序的容错性一直困扰着Google的工程师们 。
这个时候大规模数据处理技术还处于仿徨阶段, 每个公司甚至个人都有一套独立的数据处理工具,层次不齐, 纷繁复杂,但是还没有提炼抽象出一个系统的办法。
青铜时代
直到2003年,MapReduce问世, 开启了数据处理的青铜时代(真正意义上的第一代大数据计算引擎) 。Jeff Dean和Sanjay Ghemawat发表革命性的论文MapReduce: Simplified Data Processing on Large Clusters, 从纷繁复杂的业务逻辑中抽象出Map和Reduce这样足够通用 的编程模型。利用这个简单的编程模型编写分布式程序, 跑在那些廉价的机器上。在随后的十年中, MapReduce在Google内部广泛使用,不断优化, 投入了大量的人力物力将这套系统推向了前所未有的高度。
铁器时代
MapReduce虽好,但是对于上层应用来说, 在一些复杂的应用场景下, 编写MapReduce程序会变得越来越复杂, 工程师们想法设法的拆分算法,实现多个Job的串联, 开发维护工作量大。这种弊端催生了DAG(有向无环图) 框架的诞生,支持DAG的框架被划分为第二代计算引擎,如Tez 以及Ooize,此时计算引擎处理的大多数都还是批处理任务。
蒸汽机时代
时代的步伐并不会满足于计算引擎的一点点进步, 计算时间太长的问题一直被诟病。 直到基于分布式内存的Spark作为第三代计算引擎出现, 才逐渐取代了MapReduce的龙头地位(2014年之后, 国际各大互联网厂商几乎都没有人再直接写MapReduce程序 了),并且逐步向流处理开始发力。第三代计算引擎的出现, 促进了上层应用快速发展,如各种迭代计算以及流计算和SQL等。
电气时代
随着时代的前行,上层应用越来越注重实时流处理技术, 以及批流一体化的计算引擎框架。 这时批流一体化的新贵Flink应运而生; 同时Spark也在不断弥补自己在实时流处理上的短板, 增加新特性;而Google也在不断发力,推出Apache Beam。师夷长技以制夷,各大计算引擎相互参考, 不断优化着自己的短板,推出新的特性, 争当第四代计算引擎扛旗手。
石器时代
随着互联网的蓬勃发展,数据量在呈指数型增长。
早在2003年之前, 各大厂商都已经严重面临大规模数据的处理难题, 比如Google就已经面对大于600亿的搜索量。 如何从海量的原始数据中挖掘出有效的信息, 如何保证数据挖掘程序的容错性一直困扰着Google的工程师们 。
这个时候大规模数据处理技术还处于仿徨阶段,每个公司甚至个人都有一套独立的数据处理工具,层次不齐, 纷繁复杂,但是还没有提炼抽象出一个系统的办法。
青铜时代
直到2003年,MapReduce问世,
开启了数据处理的青铜时代(真正意义上的第一代大数据计算引擎) 。Jeff Dean和Sanjay Ghemawat发表革命性的论文MapReduce: Simplified Data Processing on Large Clusters, 从纷繁复杂的业务逻辑中抽象出Map和Reduce这样足够通用 的编程模型。利用这个简单的编程模型编写分布式程序, 跑在那些廉价的机器上。在随后的十年中, MapReduce在Google内部广泛使用,不断优化, 投入了大量的人力物力将这套系统推向了前所未有的高度。
铁器时代
MapReduce虽好,但是对于上层应用来说,
在一些复杂的应用场景下, 编写MapReduce程序会变得越来越复杂, 工程师们想法设法的拆分算法,实现多个Job的串联, 开发维护工作量大。这种弊端催生了DAG(有向无环图) 框架的诞生,支持DAG的框架被划分为第二代计算引擎,如Tez 以及Ooize,此时计算引擎处理的大多数都还是批处理任务。
蒸汽机时代
时代的步伐并不会满足于计算引擎的一点点进步,
计算时间太长的问题一直被诟病。 直到基于分布式内存的Spark作为第三代计算引擎出现, 才逐渐取代了MapReduce的龙头地位(2014年之后, 国际各大互联网厂商几乎都没有人再直接写MapReduce程序 了),并且逐步向流处理开始发力。第三代计算引擎的出现, 促进了上层应用快速发展,如各种迭代计算以及流计算和SQL等。
电气时代
随着时代的前行,上层应用越来越注重实时流处理技术,
以及批流一体化的计算引擎框架。 这时批流一体化的新贵Flink应运而生; 同时Spark也在不断弥补自己在实时流处理上的短板, 增加新特性;而Google也在不断发力,推出Apache Beam。师夷长技以制夷,各大计算引擎相互参考, 不断优化着自己的短板,推出新的特性, 争当第四代计算引擎扛旗手。
如果重登历史的巨轮,
历代计算引擎的问题和创新点
MapReduce
首先从第一代计算引擎开始。MapReduce虽好,
开发复杂度高,只提供了Map和Reduce两个操作
MapReduce 模型的抽象层次低,大量的底层逻辑都需要开发者手工完成。
开发者在使用MapReduce的时候,
需要严格的遵循Map和Reduce步骤,
当构造更为复杂的处理架构时,
往往需要协调多个Map和多个Reduce任务。
很多现实的处理场景并不适合用这个模型来描述。
高昂的维护成本
程序每一步的MapReduce都可能出错,为了处理这些异常,
很多人开始设计自己的协调系统和容错系统,
比如做一个状态机来协调多个MapReduce任务,
这样大大增加了整个系统的复杂度。(如果你Google一下“
MapReduce orchestration”关键字, 你会发现很多书整篇都在讲如何协调MapReduce任务) 配置太复杂,错误的配置最终导致数据
实际的开发过程中,
不是每个人都对MapReduce细微的配置信息了如指掌,
对一个没有用过MapReduce的新手来说是很难发挥好Map
Reduce的性能的。(Google有500多页的关于Map
Reduce的性能调优的说明手册,可见其复杂度之高) 调优的过程也比较漫长。
Google曾在2007年到2012年间做过一个对于1PB数
据的大规模排序,来测试MapReduce的性能。
花了五年时间从12小时优化到0.5个小时,包括缓冲大小,
分片多少,预抓取策略,缓存大小等等。
计算效率低
每一个Job的计算结果都会存储在HDFS文件系统中,
每一步的计算都需要进行硬盘的读写和写入,
大大增加了系统的的延迟。
所以MapReduce对于迭代算法的处理性能很差,
而且很耗资源。
MapReduce只支持数据批处理,
应对流处理的时候不再得心应手
真正的业务系统,批处理和流处理常常是混合共生,
或者频繁切换的。
MapReduce作为分布式数据处理的开山鼻祖,
虽然有很多缺陷,但是它的思想不仅没有过时,
而且还影响了新的数据处理系统的设计,如Spark,
Storm,Presto,Impala等。
传统的MapReduce任务之所以运行速度慢,
主要是由于需要将计算的中间结果落地到硬盘这种稳定的存储介质中
来防止运行结果丢失,每一次获取中间结果,
都需要进行一次硬盘的读取,
反复读写操作以及潜在的数据复制和序列化操作大大的提高了计算的
延迟。
Tez
作为第二代计算引擎的代表Tez是一个运行在Yarn上支持DA
但Tez并不直接面向最终用户,
Spark
作为第三代计算引擎的Spark几乎解决了上面列出的MapRe
相较与MapReduce的数据模型,
首先,它尽可能的把数据存在内存中,
大大的提高了数据处理的效率;
其次,它是分区存储,天然支持并行处理
它存储了每一步骤计算结果之间的依赖关系,
大大提升了数据容错性和错误恢复的正确率,是Spark更加可靠
与编写MapReduce程序一样,
从发展历史角度来看,RDD API是在Spark设计之初就有的,
是整个Spark框架的基石。 为了方便熟悉数据库和SQL的开发人员使用,在RDD的基础上, Spark创建了DataFrame API,开发人员可以方便的对数据的列进行操作。在Spark 1.6中,引入了DataSet, 它在DataFrame的基础上添加了对数据每一列的类型的限制 。在Spark2.0中, DataFrame和DataSet被统一。 DataFrame作为DataSet[Row]存在。
DataSet和DataFrame都是基于RDD的,
无论是DataFrame API还是DataSet API,都是基于批处理模式对静态数据进行处理的。
Spark Streaming提供了一个对流数据的抽象DStream(
数据容错性,如果RDD某些分区丢失了,
可以通过依赖信息重新计算恢复
运行速度,DSteam可以通过持久化方法将数据流放在内存中,
在遇到需要多次迭代计算的程序中,速度优势十分明显
作为Spark生态的一部分,可以和Spark核心引擎、
Spark SQL、MLib无缝衔接
但是Spark Streaming由于不支持太小的批处理时间间隔而带来的秒级
Spark Streaming提供的DStream API与RDD API比较类似,相对比较低level,前面已经提到RDD API开发的程序需要开发者自己构造RDD的DAG执行图,
依赖开发者自己去优化。
既然Spark已经提供了DataFrame,
DataSet这种高级API,可以自动优化Spark程序了,
那么能否将他们应用在流处理中呢?答案是肯定的。2016年,
Spark在2.0版本中推出了结构化流数据处理模块Structured Streaming。Structured Streaming是基于Spark SQL引擎实现的,依赖Spark Streaming,在开发者眼里,
流数据和静态数据是没有区别的,
开发者可以像处理批处理静态数据那样去处理流数据。
随着流数据的持续输入,借助于Spark SQL的优化引擎,Spark SQL引擎会帮助我们持续地处理新数据,更新计算结果。
所以Structured Streaming的应用程序性能很好。(现在Spark社区几
乎停止了关于Spark Streaming的更新,将重心投放到Structured Streaming上了)。 实时性,其次Spark Streaming是准实时的,它能做到最小延迟在一秒左右,
虽然Structured Streaming的思想类似,但是相比Spark Streaming来说,它能做到更小的时间间隔,最小延迟在1
00毫秒左右,在Spark2.3版本中。Structured Streaming引入了连续处理模式, 可以做到真正的毫秒级延迟,拓展了Structured Streaming的应用广度。 对事件时间的支持,Spark Streaming把数据接收到的时间切分成一个个RDD进行批
处理,所以它很难基于数据本省的产生时间来进行处理。
而Structured Streaming对基于事件时间的处理有很好的支持。
Structured Streaming还有其它优点,比如它有更好的容错性,
保证了端到端的exactly once语义等
无论是Spark Streaming还是Structured Streaming,Spark流处理的实时性还是不够,
Flink
想要在流处理的实时性上提升,就不能继续用微批处理的模式,
Flink中最核心的数据结构Stream,
它代表一个运行在多个分区上的并行流, 与Spark的RDD不同的是, Stream代表一个数据流而不是静态数据的集合, 它包含的数据是随着时间增长变化的。
Flink提供两个核心API:用于做批处理的DataSet API和和流处理的Data Stream API。
Flink和Spark都有很多相同点:
都基于内存计算
都有统一的批处理和流处理API,都支持类似SQL的编程接口
都支持很多相同的转换操作,编程都是类似于Scala Collection API的函数式编程模式
都有完善的错误恢复机制
都支持Exactly once的语义一致性
当然也有很多不同点:
从流处理的角度来讲,Spark是基于微批处理,
把流数据看成一个个小的批处理数据块分别处理,
延迟性只能做到秒级。Flink基于每个时间处理,
每当有新的数据输入都会立即处理,是真正的流式计算,
支持毫秒级计算。基于同样的原因,
Spark只能支持基于时间的窗口操作(处理时间或者事件时间)
,而Flink支持的窗口操作非常灵活,不仅支持时间窗口,
还支持基于数据本身的窗口,开发者可以自定义想要的窗口操作
从SQL功能的角度来讲,
Spark和Flink分别提供SparkSQL和Table API提供的SQL交互支持。相比而言,Spark SQL支持更好,相应的优化、拓展和性能更好,
Flink在这方面还有很大提升空间
从机器学习迭代计算的角度来讲,
Spark对机器学习的支持很好,
可以在内存中缓存中间计算结果加速机器学习算法的运行。
但是大部分机器学习算法其实是一个有环的数据流,
然而Spark是用无环图来标示的。
Flink支持在运行时间总的有环数据流,
从而可以更有效的对机器学习算法进行运行
从生态系统角度来讲,Spark的社区更加活跃,
Spark有着Apache旗下最多的开源贡献者,
有很多不同的库用在不同场景。Flink比较新,
社区活跃度不如Spark活跃,
各种库的功能不如Spark全面。
但是Flink在国内背后有阿里、华为、美团的加持,
相信这块这后面会不断完善。
Beam
在Spark和Flink分别发力争当下一代计算引擎的领头羊时
Beam提供了一套统一的API来处理这两种数据处理模式,
Apache Beam和其它开源项目不太一样,它不是一个数据处理平台,
窗口(Window):
窗口将无边界的数据更具时间实践分成了一个个有限的数据集
水印(Watermark):
用来表示与数据事件时间相关联的输入完整性的概念。
在数据处理中,水印是用来测量数据进度的。
对于事件时间为X的水印表示数据处理逻辑已经得到了所有事件时间
小于X的无边界数据
触发器(Triggers):表示具体在什么时候,
数据处理逻辑会真正的触发窗口中的数据倍计算。
累加模式(Accumulation):
如果我们在同一个窗口中得到多个运算结果, 如何处理这些运行结果,是丢弃、追加,还是直接覆盖
大规模数据处理计算引擎该有的样子
世界上最好的样子,莫过于我喜欢的样子,你都有。
—-徐志摩没有说过
历史的篇章就翻到这里。让我们回到最初的问题:
下面站在工程师的角度来简单归纳一下:
编程简单,易维护 你需要提供一种让多步骤数据处理变得易于维护抽象技术
作为工程师的我们或许可以用有向无环图(DAG)来抽象表达。
因为有向图能为多个步骤的数据处理依赖关系,建立很好的模型。
支持SQL语言。现在机器学习都能SQL化了,
Kakfa也能SQL化了,能一行SQL解决的问题,
为什么还要去写多行代码?
支持多语言的客户端
自优化 你已经是一个成熟的计算引擎了,我不想要复杂的配置,
你需要能自动进行性能优化
业务逻辑描述和计算分离 你可以把数据处理的描述语言,
与背后的运行引擎解耦合开来
在使用有向无环图进行数据抽象描述之后,
数据处理描述语言部分已经可以和运算引擎部分分离了。
有向图可以作为数据处理描述语言和运算引擎的前后端分离协议。
业务团队可以使用不用语言的客户端进行数据描述,计算引擎由C+
+实现,由数据底层团队维护并高度优化
数据描述可以在本地写,计算引擎在云端执行
批流一体化 你要提供统一批处理和流处理的编程模型,
我不想再写两套代码了
批处理处理的是有界离散的数据,比如处理一个文本文件;
流处理处理的是无界连续的数据,比如每时每刻的支付宝交易数据。
真正的业务系统,批处理和流处理常常是混合共生,或者频繁切换的
不论是批处理还是流处理的,都用统一的数据结构表示。
编程的API也需要统一。不论业务需求怎么样,
开发者只需要学习一套API
自监控 你要在架构层面提供异常处理和数据监控的能力,
对数据处理的每一步提供自动的监控平台
做过大规模数据处理系统的人都很明白:
一个复杂的数据处理系统中,难的不是开发系统,而是异常处理。
下一代大规模数据处理框架要有一套基本的数据监控能力,
对于数据处理的每一步提供自动的监控平台
故事就讲到这里了,下面插播一下前文中提到的题外话。
在那个MapReduce横行的时代,
大部分开发人员最熟悉的还是传统的关系型数据库,
MapReduce的开发对于他们来讲使用难度较大,
所以Hive就应运而生了,Hive提供类似SQL的编程接口,
HQL语句经过语法解析、逻辑计划、
物理计划转换成MapReduce程序运行,
使开发人员很容易对HDFS上存储的数据进行查询和分析。
Spark刚问世的时候,
也开发了一个Shark来支持SQL语言查询,
它的本质是Hive,修改了Hive的内存管理模块,
大幅度优化了运行速度,是Hive的10-100倍。
但是Shark对于Hive的依赖严重影响了Spark的发展。
Spark想要的不只是一个SQL,
而是想要定义一个统一的技术栈和完整的生态,
眼睛里面揉不得沙子的Spark不可能允许有这样的外在依赖,
所以就将Shark交给Hive进行管理,
转而开发SparkSQL
摒弃了Shark将SQL语句转化为Spark RDD的执行引擎,就想脱缰的野马一样跑的“飞快”。Spark SLQ不仅将关系型数据库的处理模式和Spark的函数式编程相
结合,还兼容了Hive、RDD、JSON、 CSV等多种数据格式
看起来Flink在数据处理这块的能力完爆Spark,但是在下
数据量非常大而且逻辑复杂的批数据处理,
并且对计算效率有较高要求(比如个性化推荐、广告精准营销)
基于历史数据的交互式查询,要求相应较快
基于实时数据量的数据处理,延迟性要求在数百毫秒到数秒之间
What result are calculated?*: 我们要计算什么?
比如经典例子WordCount就是要计算每个词出现的次数
Where in event time are calculated?: 计算什么时间范围的数据?一般通过窗口来表示,
比如计算的一点两点的访问量
When in processing are result materialized?: 何时将计算结果输出?可以通过水印和触发器配合触发计算。
可根据时间信号或者窗口元素计数来触发,
比如定义好固定窗口为1个小时,元素个数为10,从凌晨0:
00开始,每当1:00,2:00或者窗口内个数超过10时,
就会触发计算将结果输出
How do refinement of result related?: 后续数据处理结果如何影响之前的处理结果?
这个可以通过累加模式解决(丢弃,累积)
Apache Beam最早来自于Google内部产生的FlumeJava。
FlumeJava的思想是将所有的数据都抽象为一个叫PCol
但是FlumeJava有一个弊端,就是只能支持批处理的任务,
但是Dataflow Model的程序需要运行在Google的云平台上,
首先统一计算平台和批流一体化已经是主要趋势了。
对于Spark来说,它是很优秀的一个引擎,依靠强大的社区、
而Flink,的确因为阿里的运营,在国内火了。
再来看看Beam,不可否认Beam的新颖性和所站的高度,
干货预告:行业第一个卡牌类精益数据创新工作坊,即将开班,名额有限,先到先得