大数据如果从 Google 对外发布 MapReduce 论文算起,已经前后跨越十五年,我打算在本文和你蜻蜓点水般一起浏览下大数据的发展史,我们从最开始 MapReduce 计算模型开始,一路走马观花看看大数据这十五年关键发展变化,同时也顺便会讲解流式处理这个领域是如何发展到今天的这幅模样。这其中我也会加入一些我对一些业界知名大数据处理系统 (可能里面有些也不那么出名) 的观察和评论,同时考虑到我很有可能简化、低估甚至于忽略了很多重要的大数据处理系统,我也会附带一些参考材料帮助大家学习更多更详细的知识。
另外,我们仅仅讨论了大数据处理中偏 MapReduce/Hadoop 系统及其派系分支的大数据处理。我没有讨论任何 SQL 引擎 [1],我们同样也没有讨论 HPC 或者超级计算机。尽管我这章的标题听上去领域覆盖非常广泛,但实际上我仅仅会讨论一个相对比较垂直的大数据领域。
同样需要提醒的一件事情是,我在本文里面或多或少会提到一些 Google 的技术,不用说这块是因为与我在谷歌工作了十多年的经历有关。 但还有另外两个原因:1)大数据对谷歌来说一直很重要,因此在那里创造了许多有价值的东西值得详细讨论,2)我的经验一直是 谷歌以外的人似乎更喜欢学习 Google 所做的事情,因为 Google 公司在这方面一直有点守口如瓶。 所以,当我过分关注我们一直在"闭门造车"的东西时,姑且容忍下我吧。
图 10-1 本章讨论各个大数据系统时间表
为了使我们这一次大数据旅行显得更加具体有条理,我们设计了图 10-1 的时间表,这张时间表概括地展示了不同系统的诞生日期。
在每一个系统介绍过程中,我会尽可能说明清楚该系统的简要历史,并且我会尝试从流式处理系统的演化角度来阐释该系统对演化过程的贡献。最后,我们将回顾以上系统所有的贡献,从而全面了解上述系统如何演化并构建出现代流式处理系统的。
MapReduce
我们从 MapReduce 开始我们的旅程。
图 10-2 MapReduce 的时间表
我认为我们可以很确定地说,今天我们讨论的大规模数据处理系统都源自于 2003 年 MapReduce。当时,谷歌的工程师正在构建各种定制化系统,以解决互联网时代下大数据处理难题。当他们这样尝试去解决这些问题时候,发现有三个难以逾越的坎儿:
数据处理很难 只要是数据科学家或者工程师都很清楚。如果你能够精通于从原始数据挖掘出对企业有价值的信息,那这个技能能够保你这辈子吃喝不愁。
可伸缩性很难 本来数据处理已经够难了,要从大规模数据集中挖掘出有价值的数据更加困难。
容错很难 要从大规模数据集挖掘数据已经很难了,如果还要想办法在一批廉价机器构建的分布式集群上可容错地、准确地方式挖掘数据价值,那真是难于上青天了。
在多种应用场景中都尝试解决了上述三个问题之后,Google 的工程师们开始注意到各自构建的定制化系统之间颇有相似之处。最终,Google 工程师悟出来一个道理: 如果他们能够构建一个可以解决上述问题二和问题三的框架,那么工程师就将可以完全放下问题二和三,从而集中精力解决每个业务都需要解决的问题一。于是,MapReduce 框架诞生了。
MapReduce 的基本思想是提供一套非常简洁的数据处理 API,这套 API 来自于函数式编程领域的两个非常易于理解的操作:map 和 reduce(图 10-3)。使用该 API 构建的底层数据流将在这套分布式系统框架上执行,框架负责处理所有繁琐的可扩展性和容错性问题。可扩展性和容错性问题对于分布式底层工程师来说无疑是非常有挑战的课题,但对于我们普通工程师而言,无益于是灾难。
图 10-3 MapReduce 作业原理图
我们已经在第 6 章详细讨论了 MapReduce 的语义,所以我们在此不再赘述。仅仅简单地回想一下,我们将处理过程分解为六个离散阶段(MapRead,Map,MapWrite,ReduceRead,Reduce,ReduceWrite)作为对于流或者表进行分析的几个步骤。我们可以看到,整体上 Map 和 Reduce 阶段之间差异其实也不大 ; 更高层次来看,他们都做了以下事情:
从表中读取数据,并转换为数据流 (译者注: 即 MapRead、ReduceRead)
针对上述数据流,将用户编写业务处理代码应用于上述数据流,转换并形成新的一个数据流。 (译者注: 即 Map、Reduce)
将上述转换后的流根据某些规则分组,并写出到表中。 (译者注: 即 MapWrite、ReduceWrite)
随后,Google 内部将 MapReduce 投入生产使用并得到了非常广泛的业务应用,Google 认为应该和公司外的同行分享我们的研究成果,最终我们将 MapReduce 论文发表于 OSDI 2004(见图 10-4)。
图 10-4 MapReduce 论文发表在 OSDI 2004 上
论文中,Google 详细描述了 MapReduce 项目的历史,API 的设计和实现,以及有关使用了 MapReduce 框架的许多不同生产案例的详细信息。当然,Google 没有提供任何实际的源代码,以至于最终 Google 以外的人都认为:“是的,这套系统确实牛啊!”,然后立马回头去模仿 MapReduce 去构建他们的定制化系统。
在随后这十年的过程中,MapReduce 继续在谷歌内部进行大量开发,投入大量时间将这套系统规模推进到前所未有的水平。如果读者朋友希望了解一些更加深入更加详细的 MapReduce 说明,我推荐由我们的 MapReduce 团队中负责扩展性、性能优化的大牛 Marián Dvorský撰写的文章《History of massive-scale sorting experiments at Google》(图 10-5)
图 10-5 MariánDvorský的《History of massive-scale sorting experiments》博客文章
我这里希望强调的是,这么多年来看,其他任何的分布式架构最终都没有达到 MapReduce 的集群规模,甚至在 Google 内部也没有。从 MapReduce 诞生起到现在已经跨越十载之久,都未能看到真正能够超越 MapReduce 系统规模的另外一套系统,足见 MapReduce 系统之成功。14 年的光阴看似不长,对于互联网行业已然永久。
从流式处理系统来看,我想为读者朋友强调的是 MapReduce 的简单性和可扩展性。 MapReduce 给我们的启发是:MapReduce 系统的设计非常勇于创新,它提供一套简便且直接的 API,用于构建业务复杂但可靠健壮的底层分布式数据 Pipeline,并足够将这套分布式数据 Pipeline 运行在廉价普通的商用服务器集群之上。
Hadoop
我们大数据旅程的下一站是 Hadoop(图 10-6)。需要着重说明的是:我为了保证我们讨论的重心不至于偏离太多,而压缩简化讨论 Hadoop 的内容。但必须承认的是,Hadoop 对我们的行业甚至整个世界的影响不容小觑,它带来的影响远远超出了我在此书讨论的范围。
图 10-6 Hadoop 的时间表
Hadoop 于 2005 年问世,当时 Doug Cutting 和 Mike Cafarella 认为 MapReduce 论文中的想法太棒了,他们在构建 Nutch webcrawler 的分布式版本正好需要这套分布式理论基础。在这之前,他们已经实现了自己版本的 Google 分布式文件系统(最初称为 Nutch 分布式文件系统的 NDFS,后来改名为 HDFS 或 Hadoop 分布式文件系统)。因此下一步,自然而然的,基于 HDFS 之上添加 MapReduce 计算层。他们称 MapReduce 这一层为 Hadoop。
Hadoop 和 MapReduce 之间的主要区别在于 Cutting 和 Cafarella 通过开源(以及 HDFS 的源代码)确保 Hadoop 的源代码与世界各地可以共享,最终成为 Apache Hadoop 项目的一部分。雅虎聘请 Cutting 来帮助将雅虎网络爬虫项目升级为全部基于 Hadoop 架构,这个项目使得 Hadoop 有效提升了生产可用性以及工程效率。自那以后,整个开源生态的大数据处理工具生态系统得到了蓬勃发展。与 MapReduce 一样,相信其他人已经能够比我更好地讲述了 Hadoop 的历史。我推荐一个特别好的讲解是 Marko Bonaci 的《The history of Hadoop》,它本身也是一本已经出版的纸质书籍(图 10-7)。
图 10-7 Marko Bonaci 的《The history of Hadoop》
在 Hadoop 这部分,我期望读者朋友能够了解到围绕 Hadoop 的开源生态系统对整个行业产生的巨大影响。通过创建一个开放的社区,工程师可以从早期的 GFS 和 MapReduce 论文中改进和扩展这些想法,这直接促进生态系统的蓬勃发展,并基于此之上产生了许多有用的工具,如 Pig,Hive,HBase,Crunch 等等。这种开放性是导致我们整个行业现有思想多样性的关键,同时 Hadoop 开放性生态亦是直接促进流计算系统发展。
Flume
我们现在再回到 Google,讨论 Google 公司中 MapReduce 的官方继承者:Flume([图 10-8],有时也称为 FlumeJava,这个名字起源于最初 Flume 的 Java 版本。需要注意的是,这里的 Flume 不要与 Apache Flume 混淆,这部分是面向不同领域的东西,只是恰好有同样的名字)。
图 10-8 Flume 的时间表
Flume 项目由 Craig Chambers 在 2007 年谷歌西雅图办事处成立时发起。Flume 最初打算是希望解决 MapReduce 的一些固有缺点,这些缺点即使在 MapReduce 最初大红大紫的阶段已经非常明显。其中许多缺点都与 MapReduce 完全限定的 Map→Shuffle→Reduce 编程模型相关 ; 这个编程模型虽然简单,但它带来了一些缺点:
由于单个 MapReduce 作业并不能完成大量实际上的业务案例,因此许多定制的编排系统开始在 Google 公司内部出现,这些编排系统主要用于协调 MapReduce 作业的顺序。这些系统基本上都在解决同一类问题,即将多个 MapReduce 作业粘合在一起,创建一个解决复杂问题的数据管道。然而,这些编排系统都是 Google 各自团队独立开发的,相互之间也完全不兼容,是一类典型的重复造轮子案例。
更糟糕的是,由于 MapReduce 设计的 API 遵循严格结构,在很多情况下严格遵循 MapReduce 编程模型会导致作业运行效率低下。例如,一个团队可能会编写一个简单地过滤掉一些元素的 MapReduce,即,仅有 Map 阶段没有 Reduce 阶段的作业。这个作业下游紧接着另一个团队同样仅有 Map 阶段的作业,进行一些字段扩展和丰富 (仍然带一个空的 Reduce 阶段作业)。第二个作业的输出最终可能会被第三个团队的 MapReduce 作业作为输入,第三个作业将对数据执行某些分组聚合。这个 Pipeline,实际上由一个合并 Map 阶段 (译者注: 前面两个 Map 合并为一个 Map),外加一个 Reduce 阶段即可完成业务逻辑,但实际上却需要编排三个完全独立的作业,每个作业通过 Shuffle 和 Output 两个步骤链接在一起。假设你希望保持代码的逻辑性和清洁性,于是你考虑将部分代码进行合并,但这个最终导致第三个问题。
为了优化 MapReduce 作业中的这些低效代码,工程师们开始引入手动优化,但不幸的是,这些优化会混淆 Pipeline 的简单逻辑,进而增加维护和调试成本。
Flume 通过提供可组合的高级 API 来描述数据处理流水线,从而解决了这些问题。这套设计理念同样也是 Beam 主要的抽象模型,即 PCollection 和 PTransform 概念,如图 10-9 所示。
图 10-9 Flume 的高层抽象模型(图片来源:Frances Perry)
这些数据处理 Pipeline 在作业启动时将通过优化器生成,优化器将以最佳效率生成 MapReduce 作业,然后交由框架编排执行。整个编译执行原理图可以在图 10-10 中看到。
图 10-10 从逻辑管道到物理执行计划的优化
也许 Flume 在自动优化方面最重要的案例就是是合并(Reuven 在第 5 章中讨论了这个主题),其中两个逻辑上独立的阶段可以在同一个作业中顺序地(消费者 - 生产者融合)执行或者并行执行(兄弟融合),如图 10-11 所示。
图 10-11 合并优化将顺序或并行操作 (算子) 组合在一起,到同一个操作 (算子)。
将两个阶段融合在一起消除了序列化 / 反序列化和网络开销,这在处理大量数据的底层 Pipeline 中非常重要。
另一种类型的自动优化是 combiner lifting(见图 10-12),当我们讨论增量合并时,我们已经在第 7 章中讨论了这些机制。combiner lifting 只是我们在该章讨论的多级组合逻辑的编译器自动优化:以求和操作为例,求和的合并逻辑本来应该运算在分组 (译者注: 即 Group-By) 操作后,由于优化的原因,被提前到在 group-by-key 之前做局部求和(根据 group-by-key 的语义,经过 group-by-key 操作需要跨网络进行大量数据 Shuffle)。在出现数据热点情况下,将这个操作提前可以大大减少通过网络 Shuffle 的数据量,并且还可以在多台机器上分散掉最终聚合的机器负载。
图 10-12: combiner lifting 在数据上游直接进行局部聚合后再发送给下游端进行二次聚合。
由于其更清晰的 API 定义和自动优化机制,在 2009 年初 Google 内部推出后 FlumeJava 立即受到巨大欢迎。之后,该团队发表了题为《Flume Java: Easy, Efficient Data-Parallel Pipelines》(https://storage.googleapis.com/pub-tools-public-publication-data/pdf/35650.pdf) 的论文(参见图 10-13),这篇论文本身就是一个很好的学习 FlumeJava 的资料。
图 10-13 FlumeJava 的论文
Flume C++ 版本很快于 2011 年发布。之后 2012 年初,Flume 被引入为 Google 的所有新工程师提供的 Noogler6 培训内容。MapReduce 框架于是最终被走向被替换的命运。
从那时起,Flume 已经迁移到不再使用 MapReduce 作为执行引擎 ; 相反,Flume 底层基于一个名为 Dax 的内置自定义执行引擎。 工作本身。不仅让 Flume 更加灵活选择执行计划而不必拘泥于 Map→Shuffle→Reduce MapReduce 的模型,Dax 还启用了新的优化,例如 Eugene Kirpi-chov 和 Malo Denielou 的《No shard left behind》博客文章(https://cloud.google.com/blog/products/gcp/no-shard-left-behind-dynamic-work-rebalancing-in-google-cloud-dataflow) 中描述的动态负载均衡(图 10-14)。
图 10-14 帖子 《No shard left behind》
尽管那篇博客主要是基于 Google DataFlow 框架下讨论问题,但动态负载均衡(或液态分片,Google 内部更习惯这样叫)可以让部分已经完成工作的 Worker 能够从另外一些繁忙的 Worker 手中分配一些额外的工作。在 Job 运行过程中,通过不断的动态调整负载分配可以将系统运行效率趋近最优,这种算法将比传统方法下有经验工程师手工设置的初始参数性能更好。Flume 甚至为 Worker 池变化进行了适配,一个拖慢整个作业进度的 Worker 会将其任务转移到其他更加高效的 Worker 上面进行执行。Flume 的这些优化手段,在 Google 内部为公司节省了大量资源。
最后一点,Flume 后来也被扩展为支持流语义。除 Dax 作为一个批处理系统引擎外,Flume 还扩展为能够在 MillWheel 流处理系统上执行作业(稍后讨论)。在 Google 内部,之前本书中讨论过的大多数高级流处理语义概念首先被整合到 Flume 中,然后才进入 Cloud Dataflow 并最终进入 Apache Beam。
总而言之,本节我们主要强调的是 Flume 产品给人引入高级管道概念,这使得能够让用户编写清晰易懂且自动优化的分布式大数据处理逻辑,从而让创建更大型更复杂的分布式大数据任务成为了可能,Flume 让我们业务代码在保持代码清晰逻辑干净的同时,自动具备编译器优化能力。
Storm
接下来是 Apache Storm(图 10-15),这是我们研究的第一个真正的流式系统。 Storm 肯定不是业界使用最早的流式处理系统,但我认为这是整个行业真正广泛采用的第一个流式处理系统,因此我们在这里需要仔细研究一下。
图 10-15 Storm 的时间轴
Storm 是 Nathan Marz 的心血结晶,Nathan Marz 后来在一篇题为《History of Apache Storm and lessons learned》的博客文章(http://nathanmarz.com/blog/history-of-apache-storm-and-lessons-learned.html) 中记录了其创作历史(图 10-16)。 这篇冗长的博客讲述了 BackType 这家创业公司一直在自己通过消息队列和自定义代码去处理 Twitter 信息流。Nathan 和十几年前 Google 里面设计 MapReduce 相关工程师有相同的认识:实际的业务处理的代码仅仅是系统代码很小一部分,如果有个统一的流式实时处理框架负责处理各类分布式系统底层问题,那么基于之上构建我们的实时大数据处理将会轻松得多。基于此,Nathan 团队完成了 Storm 的设计和开发。
值得一提的是,Storm 的设计原则和其他系统大相径庭,Storm 更多考虑到实时流计算的处理时延而非数据的一致性保证。后者是其他大数据系统必备基础产品特征之一。Storm 针对每条流式数据进行计算处理,并提供至多一次或者至少一次的语义保证;同时不提供任何状态存储能力。相比于 Batch 批处理系统能够提供一致性语义保证,Storm 系统能够提供更低的数据处理延迟。对于某些数据处理业务场景来说,这确实也是一个非常合理的取舍。
图 10-16 《History of Apache Storm and lessons learned》
不幸的是,人们很快就清楚地知道他们想要什么样的流式处理系统。他们不仅希望快速得到业务结果,同时希望系统具有低延迟和准确性,但仅凭 Storm 架构实际上不可能做到这一点。针对这个情况,Nathan 后面又提出了 Lambda 架构。
鉴于 Storm 的局限性,聪明的工程师结合弱一致语义的 Storm 流处理以及强一致语义的 Hadoop 批处理。前者产生了低延迟,但不精确的结果,而后者产生了高延迟,但精确的结果,双剑合璧,整合两套系统整体提供的低延迟但最终一致的输出结果。我们在第 1 章中了解到,Lambda 架构是 Marz 的另一个创意,详见他的文章《“如何击败 CAP 定理”》(http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html) (图 10-17)。
图 10-17 《How to beat the CAP theorem》
我已经花了相当多的时间来分析 Lambda 架构的缺点,以至于我不会在这里啰嗦这些问题。但我要重申一下:尽管它带来了大量成本问题,Lambda 架构当前还是非常受欢迎,仅仅是因为它满足了许多企业一个关键需求:系统提供低延迟但不准确的数据,后续通过批处理系统纠正之前数据,最终给出一致性的结果。从流处理系统演变的角度来看,Storm 确实为普罗大众带来低延迟的流式实时数据处理能力。然而,它是以牺牲数据强一致性为代价的,这反过来又带来了 Lambda 架构的兴起,导致接下来多年基于两套系统架构之上的数据处理带来无尽的麻烦和成本。
撇开其他问题先不说,Storm 是行业首次大规模尝试低延迟数据处理的系统,其影响反映在当前线上大量部署和应用各类流式处理系统。在我们要放下 Storm 开始聊其他系统之前,我觉得还是很有必要去说说 Heron 这个系统。在 2015 年,Twitter 作为 Storm 项目孵化公司以及世界上已知最大的 Storm 用户,突然宣布放弃 Storm 引擎,宣称正在研发另外一套称之为 Heron 的流式处理框架。Heron 旨在解决困扰 Storm 的一系列性能和维护问题,同时向 Storm 保持 API 兼容,详见题为《Twitter Heron:Stream Processing at scale》的论文(https://www.semanticscholar.org/paper/Twitter-Heron%3A-Stream-Processing-at-Scale-Kulkarni-Bhagat/e847c3ec130da57328db79a7fea794b07dbccdd9) (图 10-18)。
图 10-18 Heron 的论文
Heron 本身也是开源产品(但开源不在 Apache 项目中)。鉴于 Storm 仍然在社区中持续发展,现在又冒出一套和 Storm 竞争的软件,最终两边系统鹿死谁手,我们只能拭目以待了。
Spark
继续走起,我们现在来到 Apache Spark(图 10-19)。再次,我又将大量简化 Spark 系统对行业的总体影响探讨,仅仅关注我们的流处理领域部分。
图 10-19 Spark 的时间轴
Spark 在 2009 年左右诞生于加州大学伯克利分校的著名 AMPLab。最初推动 Spark 成名的原因是它能够经常在内存执行大量的计算工作,直到作业的最后一步才写入磁盘。工程师通过弹性分布式数据集(RDD)理念实现了这一目标,在底层 Pipeline 中能够获取每个阶段数据结果的所有派生关系,并且允许在机器故障时根据需要重新计算中间结果,当然,这些都基于一些假设 a)输入是总是可重放的,b)计算是确定性的。对于许多案例来说,这些先决条件是真实的,或者看上去足够真实,至少用户确实在 Spark 享受到了巨大的性能提升。从那时起,Spark 逐渐建立起其作为 Hadoop 事实上的继任产品定位。
在 Spark 创建几年后,当时 AMPLab 的研究生 Tathagata Das 开始意识到:嘿,我们有这个快速的批处理引擎,如果我们将多个批次的任务串接起来,用它能否来处理流数据?于是乎,Spark Streaming 诞生了。
关于 Spark Streaming 的真正精彩之处在于:强大的批处理引擎解决了太多底层麻烦的问题,如果基于此构建流式处理引擎则整个流处理系统将简单很多,于是世界又多一个流处理引擎,而且是可以独自提供一致性语义保障的流式处理系统。换句话说,给定正确的用例,你可以不用 Lambda 架构系统直接使用 Spark Streaming 即可满足数据一致性需求。为 Spark Streaming 手工点赞!
这里的一个主要问题是“正确的用例”部分。早期版本的 Spark Streaming(1.x 版本)的一大缺点是它仅支持特定的流处理语义:即,处理时间窗口。因此,任何需要使用事件时间,需要处理延迟数据等等案例都无法让用户使用 Spark 开箱即用解决业务。这意味着 Spark Streaming 最适合于有序数据或事件时间无关的计算。而且,正如我在本书中重申的那样,在处理当今常见的大规模、以用户为中心的数据集时,这些先决条件看上去并不是那么常见。
围绕 Spark Streaming 的另一个有趣的争议是“microbatch 和 true streaming”争论。由于 Spark Streaming 建立在批处理引擎的重复运行的基础之上,因此批评者声称 Spark Streaming 不是真正的流式引擎,因为整个系统的处理基于全局的数据切分规则。这个或多或少是实情。尽管流处理引擎几乎总是为了吞吐量而使用某种批处理或者类似的加大吞吐的系统策略,但它们可以灵活地在更精细的级别上进行处理,一直可以细化到某个 key。但基于微批处理模型的系统在基于全局切分方式处理数据包,这意味着同时具备低延迟和高吞吐是不可能的。确实我们看到许多基准测试表明这说法或多或少有点正确。当然,作业能够做到几分钟或几秒钟的延迟已经相当不错了,实际上生产中很少有用例需要严格数据正确性和低延迟保证。所以从某种意义上说,Spark 瞄准最初目标客户群体打法是非常到位的,因为大多数业务场景均属于这一类。但这并未阻止其竞争对手将此作为该平台的巨大劣势。就个人而言,在大多数情况下,我认为这只是一个很小问题。
撇开缺点不说,Spark Streaming 是流处理的分水岭:第一个广泛使用的大规模流处理引擎,它也可以提供批处理系统的正确性保证。 当然,正如前面提到的,流式系统只是 Spark 整体成功故事的一小部分,Spark 在迭代处理和机器学习领域做出了重要贡献,其原生 SQL 集成以及上述快如闪电般的内存计算,都是非常值得大书特书的产品特性。
如果您想了解有关原始 Spark 1.x 架构细节的更多信息,我强烈推荐 Matei Zaharia 关于该主题的论文《 “An Architecture for Fast and General Data Processing on Large Clusters》(图 10-20)。 这是 113 页的 Spark 核心讲解论文,非常值得一读。
图 10-20 Spark 的学位论文
时至今日,Spark 的 2.x 版本极大地扩展了 Spark Streaming 的语义功能,其中已经包含了本书中描述流式处理模型的许多部分,同时试图简化一些更复杂的设计。 Spark 甚至推出了一种全新的、真正面向流式处理的架构,用以规避掉微批架构的种种问题。但是曾经,当 Spark 第一次出现时,它带来的重要贡献是它是第一个公开可用的流处理引擎,具有数据处理的强一致性语义,尽管这个特性只能用在有序数据或使用处理时间计算的场景。
MillWheel
接下来我们讨论 MillWheel,这是我在 2008 年加入 Google 后的花 20%时间兼职参与的项目,后来在 2010 年全职加入该团队(图 10-21)。
图 10-21 MillWheel 时间表
MillWheel 是 Google 最早的通用流处理架构,该项目由 Paul Nordstrom 在 Google 西雅图办事处开业时发起。 MillWheel 在 Google 内的成功与长期以来一直致力于为无序数据提供低延迟,强一致的处理能力不无关系。在本书的讲解中,我们已经多次分别讨论了促使 MillWheel 成为一款成功产品的方方面面。
第五章,Reuven 详细讨论过数据精准一次的语义保证。精准一次的语义保证对于正确性至关重要。
第七章,我们研究了状态持久化,这为在不那么靠谱的普通硬件上执行的长时间数据处理业务并且需要保证正确性奠定了基础。
第三章,Slava 讨论了 Watermark。Watermark 为处理无序数据提供了基础。
第七章,我们研究了持久性计时器,它们提供了 Watermark 与业务逻辑之间的某些关联特性。
有点令人惊讶的是,MillWheel 项目最开始并未关注数据正确性。保罗最初的想法更接近于 Storm 的设计理论:具有弱一致性的低延迟数据处理。这是最初的 MillWheel 客户,一个关于基于用户搜索数据构建会话和另一个对搜索查询执行异常检测(来自 MillWheel 论文的 Zeitgeist 示例),这两家客户迫使项目走向了正确的方向。两者都非常需要强一致的数据结果:会话用于推断用户行为,异常检测用于推断搜索查询的趋势 ; 如果他们提供的数据不靠谱,两者效果都会显着下降。最终,幸运的是,MillWheel 的设计被客户需求导向追求数据强一致性的结果。
支持乱序数据处理,这是现代流式处理系统的另一个核心功能。这个核心功能通常也被认为是被 MillWheel 引入到流式处理领域,和数据准确性一样,这个功能也是被客户需求推动最终加入到我们系统。 Zeitgeist 项目的大数据处理过程,通常被我们拿来用作一个真正的流式处理案例来讨论。Zeitgeist 项目希望检测识别搜索查询流量中的异常,并且需要捕获异常流量。对于这个大数据项目数据消费者来说,流计算将所有计算结果产出并让用户轮询所有 key 用来识别异常显然不太现实,数据用户要求系统直接计算某个����,���� key 出现异常的数据结果,而不需要上层再来轮询。对于异常峰值(即查询流量的增加),这还相对来说比较简单好解决:当给定查询的计数超过查询的预期值时,系统发出异常信号。但是对于异常下降(即查询流量减少),问题有点棘手。仅仅看到给定搜索词的查询数量减少是不够的,因为在任何时间段内,计算结果总是从零开始。在这些情况下你必须确保你的数据输入真的能够代表当前这段时间真实业务流量,然后才将计算结果和预设模型进行比较。
真正的流式处理
上一篇: 最有趣的机器学习可视化图集 下一篇: 外媒:谷歌Dragonfly项目仍在推进,6-9个月内推出中国版搜索引擎