Lambda架构的质疑

Nathan Marz 写了一篇非常受欢迎的博客文章,描述了 Lambda 架构(如何打破CAP定理)。Lambda 架构是一种在 MapReduce 和 Storm 或类似系统之上构建流处理应用程序的方法。

1. 什么是Lambda架构

Lambda架构类似于下图:

这种架构的工作方式是接收日志,并将其并行输入批处理系统和流处理系统。我们需要两次逻辑处理,一次在批处理系统中,一次在流处理系统中。我们可以在查询时将两个系统的结果融合在一起来产生完整的答案。

上述 Lambda 架构可以有很多变化,在这做了一些简化。例如,我们可以切换到与 Kafka、Storm 和 Hadoop 等类似的系统上,并使用两个不同的数据库来存储输出表,其中一个针对实时做特定优化,另一个针对批次更新做特定优化。

Lambda 架构针对复杂异步转换构建的应用程序,这些应用程序需要以低延迟(例如几秒钟到几小时)运行。一个很好的例子就是新闻推荐系统,该系统需要抓取各种新闻源,处理和规范化所有输入,然后对它进行索引,排序和存储以进行服务。

我曾在 LinkedIn 参与构建许多实时数据系统以及管道。其中有一些也是以这种方式工作,经过思考后我认为这不是我最好的方法。我认为有必要陈述一下该架构的优缺点,并给出我喜欢的替代方案。

2. 优点

我赞同 Lambda 架构强调保持输入数据的不变性。我认为将数据处理建模为一系列的物化阶段具有很多优点。这是使大型 MapReduce 工作流易于处理的原因之一,因为它使我们能够独立调试每个阶段。我在 The Log: What every software engineer should know about real-time data’s unifying abstraction 写了一些有关接收和转换不可变数据流的想法。

我也喜欢这种架构解决了数据重处理(Reprocessing)的问题。重处理是流处理的主要挑战之一,但经常被忽略。’重处理’ 是指再一次处理输入数据以重新获取输出结果。这是一个显而易见但又经常被忽略的要求。代码可能会一直更改。因此,如果我们有从输入流中获取输出数据的代码,只要代码更改,就需要重新计算输出以查看更改的效果。

为什么代码会发生更改?可能是应用程序在不断演进,我们想计算以前不需要的新字段。或者我们发现了一个错误并需要修改。无论如何,我们都需要重新计算输出。我们发现,许多尝试构建实时数据处理系统的人对此问题并没有过多的思考,最终因为无法方便地重处理数据而无法快速发展。Lambda 结构值得一提,因为它解决了这个问题。

Lambda 结构还提出了许多其他目标,但我认为没有太大意义。其中一个是,实时处理与批处理相比,本质上是近似的,但功能较弱且消耗更大。实际上我并不赞同。确实,现有的流处理框架还不如 MapReduce 成熟,但我们没有理由说流处理系统不能像批处理系统那样提供强大的语义保证。

我听到的另一个解释是,Lambda 结构允许混合使用具有不同权衡取舍的数据系统,从而在某种程度上’击败了CAP定理’。长话短说,尽管在流处理中肯定存在延迟与可用性之间的权衡,但因为这是异步处理架构,所计算的结果不会立即与输入数据保持一致。不幸的是,CAP定理仍然没有打破。

3. 劣势

Lambda 架构的问题在于,在两个复杂的分布式系统中维护产生相同结果的代码会非常痛苦。我认为这个问题不会得到解决。

在像 Storm 和 Hadoop 这样的分布式框架中进行编程一般会比较复杂。不可避免地针对其所运行的框架进行专门的代码编程。似乎每一个人都会认为实现 Lambda 架构会带来操作复杂性。

为什么不能对流处理系统进行改进来处理全部的问题呢?解决这个问题的一个建议方法是要有一种同时可以对实时框架和批处理框架进行抽象的语言或框架。我们使用这种更高层次的框架编写代码,然后对其进行编译来在后台进行流处理 或 MapReduce。Summingbird 就是这样的一个框架,肯定会使事情变得更容易,但我认为这同样不能解决问题。

最终,即使我们可以避免对应用程序进行两次编码,但运行和调试两个系统的操作负担也非常高。而且任何新的抽象都只能提供两个系统所支持的功能的交集。更糟糕的是,致力于这种新的超级框架会与 Hadoop 生态系统(Hive,Pig,Crunch,Cascading,Oozie等)隔离开来。

类比,想想跨数据库 ORM 框架臭名昭著的困难。并考虑到这只能在非常相似的系统上进行抽象,使用(几乎)标准化的接口语言提供几乎相同的功能。在勉强稳定的分布式系统之上构建完全不同的编程范例的抽象要困难很多。

4. 实践

实际上,我们已经在 LinkedIn 上进行了几轮这样的尝试。我们建立了各种混合 Hadoop 架构,甚至建立了特定领域的 API,可以允许’透明’地在实时或在 Hadoop 中运行。这些方法都行得通,但没有一个是令人高兴或富有成效的。要使在两个不同系统中编写的代码完全同步非常困难。

隐藏底层框架的 API 被证明是抽象的最大漏洞。最终,我们必须需要具备丰富的 Hadoop 知识以及对实时层深入了解,并增加了新的要求,即在调试问题或尝试调优性能时,我们需要对API如何转换为底层系统必须有足够的了解。

我的建议是,如果您对延迟不敏感,则使用像 MapReduce 这样的批处理框架,如果敏感,则使用流处理框架,除非必须使用,否则不要尝试同时使用这两者。

那么,我们为什么对 Lambda 架构感兴趣呢?我认为是因为人们越来越需要构建复杂的低延迟处理系统。他们拥有的两个系统并不能完全解决他们的问题:一个是可以处理历史数据的可伸缩高延迟的批处理系统,另一个是无法重处理的低延迟流处理系统。通过将这两个系统进行融合,实际上可以构建可行的解决方案。

从这个意义上讲,尽管可能很痛苦,但我认为 Lambda 架构解决了一个通常被忽略的重要问题。但是我不认为这就是大数据的新规范或未来。这只是由于现有工具的局限性所造成的一个临时状态。我认为还会有更好的选择。

5. 代替方案

作为设计基础架构的人,我认为一个明显的问题是:为什么不能仅仅改进流处理系统来处理全部问题呢?为什么还需要和另外一个批处理系统配合运行?为什么在代码更改时不能进行实时处理同时能重处理呢?流处理系统已经有了并行度的概念,为什么不能通过增加并行度以及非常非常快地重播历史数据来处理重新处理问题呢?答案是我们可以做到这一点,并且我认为如果我们今天正在构建这种类型的系统,那么这实际上是一种合理的替代架构。

当我与其它人讨论这个问题时,他们有时会告诉我,对于高吞吐量的历史数据处理,流处理是不合适的。我认为这是一种错觉,主要是因为他们所使用的系统的局限性,伸缩性很差或无法保存历史数据等原因造成的。这样一来,他们就认为流处理系统本质上就是从流快照中计算出结果,并不保留所有的原始数​​据。但这没有理由证明这是对的,流处理中的底层抽象是数据流 DAG,它与传统数据仓库中的底层抽象完全相同。流处理只是此数据流模型的一般化形式,暴露中间结果的检查点以及可以向用户连续输出结果。

那么,如何直接从流处理作业中进行重处理呢?我首选的方法实际上非常简单:

  • 使用 Kafka 或其它类似系统保存我们要重复处理的完整日志,并且允许它有多个订阅者。比如你要重复处理30天的数据,你就让在 Kafka 中保留30天。
  • 当我们要进行重处理时,我们需要另外启动一个流处理作业实例,从头开始处理保留数据,并将输出数据输出到一个新的输出表。
  • 当第二个作业完成后,切换应用程序从这个新表中读取。
  • 停止老版本的作业,然后删除旧的输出表。

这种架构看起来像这样:

与 Lambda 架构不同,这种方法我们仅在代码更改时才进行重处理,也就是我们需要重新计算结果的时候。当然,进行重新计算的作业只是对相同代码的改进版本,在相同框架上运行,并采用相同的输入数据。自然地,我们希望提高重新处理作业的并行度,以快速完成。我们可以将其称为 Kappa 架构,尽管它的思想比较简单。

当然,我们可以进一步优化它。在许多情况下,我们可以合并两个输出表。但是,我认为在短时间内同时拥有两个输出表会更好一点。这可以使我们仅通过一个将应用程序重定向到旧表的按钮,立即恢复到旧逻辑。

请注意,这并不意味着我们的数据无法存入 HDFS;这只是意味着我们不在那里进行重新处理。Kafka 与 Hadoop 集成比较好,因此将任何 Kafka 主题镜像到 HDFS 都很容易。对于流处理作业的输出以及中间流,对于使用 Hadoop 中的 Hive 等工具进行分析非常有用。

我们已经文档记录了此方法的实现以及使用 Samza 的重新处理架构。

6. 对比

我知道将 Samza 用作流处理系统这种方法非常出色,因为我们在 LinkedIn 已经实践过。但是我不知道在 Storm 或其他流处理系统中会不会同样的出色。因为我对 Storm 并不很熟,无法全面了解实际情况,因此很高兴得知其他人已经这样做了。无论如何,我认为总体思路是一套完全独立的系统。

两种方法在效率和资源权衡上有一定程度的不同。Lambda 架构需要一直运行重处理和实时处理,而我提出的建议仅在需要重处理时才运行作业的一个副本。但是,我的建议需要在输出数据库中暂时占用2倍的存储空间,并且需要一个支持大容量写入的数据库来进行重新加载。在这两种情况下,重处理的额外负载可能会平均化。如果我们有很多这样的作业,我们不会同时一次全部重新处理,因此在具有几十个这样的作业的共享集群上,你可能会为在任何给定时间激活重新处理的少数作业提供额外几个百分点的容量预算。

Kappa 架构真正的优势根本不在于效率,而在于允许我们在一个处理框架之上开发、测试、调试以及操作系统。因此,在简单性很重要的情况下,请考虑使用这种方法替代 Lambda 架构。

Lambda架构:即可实时处理数据,也可以重处理数据。两套系统需要编写两套代码,操作复杂、维护复杂。
Kappa 架构:根本目的不是关注效率而是提高便利性,我们可以在一个处理框架之上开发、测试、调试以及操作系统。

欢迎关注我的公众号和博客:

原文:Questioning the Lambda Architecture

赏几毛白!