--- layout: post title: lambda 架构问题的阅读笔记 category: 技术 tags: BigData keywords: description: --- {:toc} 原文: Storm的作者Nathan Marz提出了 lambda 架构,该架构是在 MapReduce 上和 Storm 上构建流式处理的应用。lambda 架构是捕获不可变的数据序列并将其并行的发送给批处理系统和流式处理系统。但是你需要分别在批处理系统和流式处理系统中实现一次数据处理逻辑。而在查询的时候需要将两个系统计算的结果合并在一起,以完成查询返回给请求端。 对于两种处理系统,你可以灵活替换实现系统,比如使用 kafka+storm 实现流出处理,使用 hadoop 实现批式处理,输出结果通常在分开的两个数据库中,一个是为了流式而优化,另一个是为了批式更新而优化。 但是对于Jay Kreps【原文作者】因为一直在从事实时数据管道的建设,虽然其中有一些风格就是 lambda 架构,但是他更喜欢一个新的替换的方案。 ## Lambda 架构图 ![Lambda 架构](//raw.githubusercontent.com/George5814/blog-pic/master/image/arch/lambda-arch.png) ## 为什么会提出lambda 架构呢 因为那些试图构建流式处理系统的人并没有过多的考虑数据重计算的问题,最终造成系统没有便利的方法来处理数据重计算。 lambda 架构强调保持输入的原始数据不可变并且**显示的将数据重新计算的问题**给展现了出来。通过 lambda 架构可以比较好的解决了流式数据和历史数据的计算问题。 ## 为什么数据会可能重新计算呢? 因为随着时间的推移,代码可能会改变。改变的原因可能是你想在输出结果中新加一个字段,或者是因为代码有 bug 需要修复。不管是什么原因,要使得历史数据得到新的预期结果,就需要将数据重新计算。 ## Jay Kreps对 lambda 架构的反驳 因为 lambda 架构提出其中一个观点认为流式系统是近似的,不准确的,准确度不如批式处理。 Jay Kreps对此观点不敢苟同,他认为现存的流式处理的框架不如 MapReduce成熟,但不代表流式系统不能如批式系统那样提供强大的语义保证。而且 lambda 架构提出的标题是"beats the CAP theorem",即干掉 CAP 理论,但是实际上尽管在流处理上对延时和可用性间存在权衡,但因为这是一种异步处理架构。所以异步计算的结果也不能立即保持与输入的数据一致,因此 CAP 理论仍然没有被打破。 ## lambda 架构存在的问题是什么? lambda 架构需要维护在两个复杂的分布式系统中输出相同结果的代码,就像看起来那么痛苦,而且Jay Kreps也不认为该问题是可以解决的。 因为 storm 和 Hadoop 分布式框架非常的复杂,因此不可避免的代码会针对其运行的框架进行设计。 ## 为什么 Lambda 会这样令人兴奋呢? Jay Kreps建议如果对延时性不敏感就仅使用如 MapReduce 这样的批处理系统。如果延迟敏感则使用流式处理框架,除非特别必须才同时使用这两种系统。 但是需求总是千奇百怪的,人们需要构建复杂的,低延时的处理系统,(而且在天朝 PM 都想要大而全的功能下,这样需求更盛)。 他们拥有的两件事情并不能解决他们的问题:一个可以处理历史数据的可扩展高延迟批处理系统和一个无法重新处理结果的低延迟流处理系统。但通过将两个东西连接在一起,实际上构成了一个可行的方案,也就是 lambda 架构。但尽管lambda 架构让人很痛苦,但确实也解决了重新计算这样通常让人忽略的问题。 但是Jay Kreps只认为 lambda 架构只是临时解决方案,它不是新的编程范例也不是大数据的未来方向。 ## Jay Kreps的经验 因为在 linkedin 内部已经进行过多次的讨论和尝试。发现保持两个不同系统中编写的代码完全同步非常非常困难。用于隐藏底层框架的API 被证明是最 Low 的抽象,因为这样设计会需要深入的 Hadoop 知识和对实时层的深入了解,而且当你在调试或者因为性能问题排查原因时,还加上需要深入了解抽象层是怎么转换到底层的处理框架的。 也许简单的才是最有效的。 ## Jay Kreps的灵魂拷问 1. **为什么不能改进流式处理系统来处理它的目标域内的完整问题呢?** 2. **为什么需要粘在另一个系统上?** 3. **为什么不能同时进行实时处理并在代码更改时处理重新处理?** 4. **为什么不通过增加并行性和重播历史非常非常快地处理重新计算的问题?** ## Jay Kreps 的观点是什么? Jay Kreps在思考为什么不能改进流式处理系统来处理它的目标域中完整的问题集呢。 因此出现了两种思路 1. 使用一种语言或者框架来抽象实时和批处理框架,可以用更高层的框架 api 写代码,然后该框架会编译后选择使用实时处理或者批处理。 这种方式肯定使得事情变得更好些,但是不能解决问题。 即使这样可以避免编写两次代码,但是运行和调试两个系统的负担也会非常高,而且新的抽象只能提供两个系统特性的并集(**但现在 Beam 不是在做这样的事情吗**)。而且这样做与跨数据库 透明的 ORM一样的臭名昭著。 在原有系统之上提供相似的接口和界面化语言,在几乎不稳定的分布式系统上构建统一的抽象层比构建完全不同的编程范式要难得多。 2. 增强流式系统的能力,以解决其目标域内的完整问题。流处理的基本抽象是数据流DAG,它与传统数据仓库中的底层抽象完全相同,也是MapReduce后继Tez的基本抽象。流处理只是这种数据流模型的一种推广,它将中间结果的检查点和持续输出暴露给最终用户。 ## Jay Kreps提出的在流式处理系统中进行重新计算的逻辑 1. 使用 kafka 或其他系统保留全部想要重新计算的 log 数据,比如保留 30 天内的数据。 2. 当想要重新计算时,开启一个新的流式处理 job 的实例从头开始计算,并将计算结果输出到一个新的 table 中。 3. 当第二个实例处理的数据追赶上前一个时,将应用切换到读新表。 4. 停用老版本的 JOB,并删除老的表数据 该方式只在代码更改时需要重新计算。当然重新计算只是统一代码的改进版本,运行在相同的框架上,消费同样的输入数据。当然也可以提高 job 的并行度,以便快速完成。 而该架构被称为 **Kappa架构** ![Lambda 架构](//raw.githubusercontent.com/George5814/blog-pic/master/image/arch/kappa-arch.png) 而且新旧两张表也可以同时存在,这样就可以通过将应用切换到旧表来恢复旧的逻辑。在特别重要的情况下,也可以使用AB 测试或 bandit 算法来确保无论是修复bug还是代码改进都不会意外降级。 同样的,数据还是可以存储在 HDFS 上的,但是数据的重新计算不会再在 HDFS 做了。 而对于 Kappa 系统,Linkedin 内部使用的Samza就正在使用。 ## 比较 两种方法之间的效率和资源权衡在某种程度上有所不同 1. Lambda架构需要始终运行重新处理和实时处理 2. Kappa 架构只需要在需要重新处理时运行第二份作业,但是,Kappa 架构要求在输出数据库中暂时拥有2倍的存储空间,并且需要一个支持高容量写入的数据库来重新加载。 在这两种情况下,再加工的额外负荷可能会平均。如果你有很多这样的工作,他们不会一次全部重新处理,所以在一个有几十个这样的工作的共享集群上,你可能会为在任何给定时间激活重新处理的少数Job提供额外的几个百分点的容量预算。 ||lambda 架构|kappa 架构| |--|--|--| |数据处理能力|可处理超大规模的历史数据 |历史数据处理能力有限| |机器开销|批处理和实时计算需一直运行,机器开销大|必要时进行全量计算,机器开销相对较小| |存储开销|只需要保存一份查询结果,存储开销较小|需要存储新老实例结果,存储开销相对较大。但如果是多 Job 共用的集群,则只需要预留出一小部分的存储即可| |开发、测试难易程度|实现两套代码,开发、测试难度较大|只需面对一个框架,开发、测试难度相对较小| |运维成本|维护两套系统,运维成本大|只需维护一个框架,运维成本小| 对比表格参考自: ### Kappa 的优势 Kappa 的真正优势不是关于效率,而是关于允许人们在单个处理框架之上开发,测试,调试和操作他们的系统。因此,在简单性很重要的情况下,请将Kappa 架构视为Lambda架构的替代方案。