0%

Kappa架构原文《质疑Lambda架构》解读

Kappa架构,是Jay Kreps在2014年提出的,其原文:《质疑Lambda架构》如下:

Nathan Marz写了一篇受欢迎的博客文章,描述了他称之为Lambda架构如何击败CAP定理)的想法。Lambda架构是一种在MapReduce和Storm或类似系统上构建流处理应用程序的方法。事实证明,这是一个出人意料的流行想法,有一个专门的网站即将初版的书。由于我一直在使用KafkaSamza在LinkedIn参与构建实时数据处理基础设施,经常被问及Lambda架构。我想描述我的想法和经历。

0.1 什么是Lambda架构,如何成为Lambda架构?

Lambda架构看起来像这样:

Lambda架构

Lambda架构的工作方法是捕获不可变的记录序列,同时输入批处理系统和流处理系统。需要分别实现批系统和流系统的计算逻辑,在查询时将批和流的计算结果组合成完整的结果。

Lambda架构有很多变体,我有意的简化一下。例如,你可以在Kafka、Storm和Hadoop的各种类似系统中交换数据,人们经常使用两个不同的数据库来存储输出表,一个优化为实时,另一个优化为批量更新。

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

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

我在LinkedIn参与建立了许多实时数据系统和管道。其中有些就是这种风格,但经过深思熟虑,这并不是我最喜欢的方法。我认为有必要描述一下这个架构的优点和缺点,并给出一个我更喜欢的选择。

0.2 Lambda架构的优点

数据不可变

Lambda架构强调保持输入数据不变。将数据转换建模为从原始输入开始的一系列物化步骤是有很多优点的。这也是大型MapReduce工作流易于处理的原因之一,因为它使您能够独立调试每个阶段。我认为这一思想可以很好地应用到流处理领域。我在这里写过一些关于捕获和转换不可变数据流的想法。

支持重新计算

这个体系结构突出了重新计算的问题。重新计算是流处理的关键挑战之一,但经常被忽略。通过“重新计算”,再次处理输入数据以修正结果。这是一个完全明显但经常被忽视的要求。代码逻辑不可避免的修改。所以,如果您有从输入流中派生输出数据的代码,则每当代码更改时,都需要重新计算输出以查看更改的效果。

代码逻辑修改

随着业务的发展,需要增加新的字段或删掉不需要的字段,或者修复发现的bug。代码逻辑不可避免的修改。构建实时系统的人往往不考虑这一点,所以根本无法快速发展。因为Lambda架构方便的解决了重新计算的问题,是比较大的有点。

流处理也可以精确并强壮

Lambda架构的设计,认为流式计算本质上是近似处理且不强壮,比批处理更容易丢失数据。事实并非如此,虽然现在的流处理框架不如MapReduce成熟,但没有理由不能像批处理系统那样提供如此强大的语义保证。

击败CAP定理

Lambda架构可以权衡不同的数据系统的混合起来以某种方式“击败了CAP定理”。长话短说,虽然流处理中肯定有延迟/可用性权衡,但Lambda架构是一个异步处理的架构,因此正在计算中的结果并不能马上与输入的数据保持一致,这并不能满足CAP定理

0.3 Lambda架构的缺点

Lambda架构的问题在于,维护两套在复杂的分布式系统的代码逻辑,并且无法解决。

编写Storm和Hadoop等分布式框架的程序是很复杂的,并且代码嵌入到运行框架,导致实现Lamdba架构具有极高的复杂性。

为什么不能改进流处理系统以处理在其目标域中设置的完整问题?一个提出的修复方法是具有抽象实时和批处理框架的语言或框架。您使用此更高级别的框架编写代码,然后将其“按住”到封面下的流处理或MapReduce。summingbird是一个这样做的框架。这绝对会使事情变得更好,但我认为它不解决问题。

为什么不能改进流处理系统来处理其目标域中的完整问题集?解决这个问题的一个方法是在实时和批框架的基础上抽象出语言或框架。使用高级框架编写代码,然后它“向下编译”到的流处理或MapReduce。Summingbird是一个执行此操作的框架。这肯定会让事情变得更好一点,但它并不能解决问题。

即使避免了两次编码,运行和调试两个系统的操作成本也很高。任何新的抽象层只适配了两个系统支持的功能。更糟糕的是,对于这个新框架,将会无法兼容Hadoop如此强大的丰富的工具和语言生态系统(Hive、Pig、Crunch、Cascading、Oozie等)。

打个比方,跨数据库的ORM实现真正透明是臭名昭著的困难。而这还只是在类似的系统上和相近的标准接口语言上进行抽象。如果要在几乎不稳定的分布式系统之上抽象化完全不同的编程范式的问题要困难得多。

0.4 我们的尝试

在LinkedIn上进行了几轮这样的尝试。构建了各种混合Hadoop架构,甚至是一个特定于域的API,允许代码在实时或Hadoop上“透明”的运行。这些方法奏效了,但没有一种方法非常愉快或富有成效。让代码在两个不同的系统中完美同步是非常非常困难的。旨在隐藏底层框架的API被证明是最泄露的抽象,最终还是需要深入的了解实时层和Hadoop。并且还附加了新的要求,当您调试问题或试图解释性能时,需要了解API将如何转换为这些底层系统

我的建议是:如果对延迟不敏感,请使用MapReduce等批处理框架;如果对延迟敏感,请使用流处理框架;但除非您绝对必须,否则不要同时尝试同时进行这两种处理。

那么,为什么Lambda架构令人兴奋呢?我认为原因是人们越来越需要构建复杂、低延迟的处理系统。他们拥有的两个不能完全解决他们的问题:可扩展高延迟的批处理系统可以处理历史数据和低延迟流处理系统无法重新计算。通过将这两样东西粘在一起,它们实际上可以构建一个工作解决方案。

从这个意义上说,尽管Lambda架构可能会很痛苦,但解决了一个被普遍忽视的重要问题。但我不认为这是大数据的新范式或未来。它只是受限于现成工具的临时状态。我也认为有更好的选择。

0.5 Kappa架构

作为设计基础架构的人,我认为最明显的问题是:为什么不能改进流处理系统以处理其目标域中设置的完整问题?你为什么需要粘在另一个系统上?为什么不能进行实时处理并在代码更改时支持重新计算?流处理系统已经存在并行性的概念; 为什么不仅仅通过增加并行性和重放历史数据来处理重新计算,非常快,非常快?答案是您可以执行此操作,如果您今天正在建立这种类型的系统,我认为这实际上是一个合理的替代架构。

当我与人们讨论这个问题时,他们有时会告诉我,流处理不适合历史数据的高吞吐量处理。但我认为这是一种直觉,主要基于他们使用的系统的局限性,这些系统要么规模差,要么无法保存历史数据。这让他们感到,流处理系统本质上是计算一些短暂流的结果,然后扔掉所有底层数据的东西。但这是没有理由应该如此。流处理的基本抽象是数据流DAG,它们与传统数据仓库(火山)中的基本抽象完全相同,也是MapReduce继任Tez的基本抽象。流处理只是该数据流模型的推广,它向最终用户公开中间结果和持续输出的Checkpoint。

那么,我们如何直接从我们的流处理工作中进行后处理呢?我更喜欢的方法实际上是愚蠢的简单:

  1. 使用Kafka或其他系统,允许您保留您想要重新处理的数据的完整日志,并允许多个订阅者。例如,如果您想重新处理长达30天的数据,请将您在Kafka中的保留时间设置为30天。
  2. 当您想进行后处理时,请启动流处理作业的第二个实例,该实例从保留数据的开头开始处理,但将此输出数据定向到新的输出表。
  3. 当第二个作业赶上时,切换应用程序以从新表读取。
  4. 停止旧版本的作业,并删除旧的输出表。

这个架构看起来像这样:

卡帕

与Lambda架构不同,在这种方法中,您只在代码更改时进行重新计算,并且实际上也需要重新计算结果。当然,重新计算的工作只是同一代码的改进版本,在同一框架上运行,使用相同的输入数据。当然,您会想在重新处理任务中增加并行性,以便它很快就能完成。

也许我们可以称之为Kappa架构,尽管这个想法可能太简单了,不值得使用希腊字母。

当然,可以进一步优化这一点。在许多情况下,您可以将两个输出表合并。然而,我认为两者在短期内都有一些好处。这允许您只需有一个按钮将应用程序重定向到旧表,即可立即恢复到旧逻辑。在特别重要的情况下(例如,您的广告定位标准),您可以使用自动A/B测试或回溯算法进行切换,以确保新代码的任何错误修复或代码改进都不会意外地与之前的版本相比降级。

请注意,这并不意味着您的数据无法转到HDFS;它只是意味着您不会在那里运行后处理。Kafka与Hadoop集成良好,因此将任何Kafka Topic落库到HDFS中都很容易。Hadoop中中保存流处理作业的输出和中间流是非常有用的,可以用于Hive等工具中的分析或其他离线数据处理流的输入。

我们记录了这种方法的实施,以及使用Samza的后处理架构的其他变体。

0.6 一些背景

Kafka维护如下有序日志:

Kafka_log

Kafka的Topic是这些日志的集合:

partitioned_log

消费这些数据的流处理消费者只会维护一个“offset”,这是它在每个分区上处理的上一次记录的日志条目号。因此,更改消费者返回和重新处理数据的位置就像用不同的偏移量重新启动作业一样简单。为同一数据添加第二个消费者只是另一个指向日志中不同位置的读者。

Kafka支持复制和容错,在廉价的硬件上运行,并每台机器存储许多TB的数据是很轻松的。因此,保留大量数据是一件非常自然和经济的事情,不会损害性能。LinkedIn在线存储了超过兆字节的Kafka存储空间,许多应用程序正好为此目的很好地利用了这种长期保留模式。

廉价的消费者和保留大量数据的能力使添加第二个“重新计算”的作业只是启动代码的第二个实例,但从日志中的不同位置开始。

这个设计不是偶然的。我们构建Kafka的目的是将其用作流处理的基础,我们完全想到了这种重新计算的模型。感兴趣的话,可以在这里找到更多关于Kafka的信息。

然而,从根本上说,没有什么能将这个想法与Kafka联系起来。您可以替换任何支持长期保留有序数据的系统(例如HDFS或某种数据库)。事实上,许多人熟悉名为事件采购CQRS的类似模式。当然,分布式数据库人员会告诉你,这只是对实例化视图维护的轻微重塑,正如他们很乐意提醒你的那样,他们很久以前就知道了*,索尼*。

0.7 Lambda架构与Kappa架构对比

我知道使用Samza作为流处理系统这种方法效果很好,因为LinkedIn是这样做的。但我不知道为什么它不应该在Storm或其他流处理系统中同样有效。我对Storm不够熟悉,无法了解实用性,所以如果其他人已经在这样做,我很乐意听到。无论如何,我认为一般想法是相当独立的。

这两种方法之间的效率和资源权衡有点令人扫地。Lambda架构需要一直运行后处理和实时处理,而我提议的只是需要在您需要重新处理时运行作业的第二份副本。然而,我的提案要求在输出数据库中暂时拥有2倍的存储空间,并要求一个支持重装大批量写入的数据库。在这两种情况下,重新处理的额外负载可能会平均。如果您有很多这样的工作,它们不会同时进行重新处理,因此在包含数十个此类工作的共享集群上,您可能会为在任何给定时间积极重新处理的少数工作额外预算容量的一小部分。

真正的优势根本不在于效率,而在于允许人们在单个处理框架上开发、测试、调试和操作他们的系统。因此,在简单性很重要的情况下,请将这种方法视为Lambda架构的替代方案。