一、概述:
在聊lambda之前,首先要聊聊大数据中的一个痛点:如何在海量数据里做即时查询?
其实最简单的解决方法就是直接对海量数据做计算做查询,但是效率可想而知,有些计算可能需要几个小时甚至几天来完成,那么在这个需求下,lambda架构就孕育而生了。
Lambda架构由Storm 的作者 [Nathan Marz] 提出, 此架构的设计是为了在处理大规模数据时,同时发挥流处理和批处理的优势。通过批处理提供全面、准确的数据,通过流处理提供低延迟的数据,从而达到平衡延迟、吞吐量和容错性的目的。为了满足下游的即席查询,批处理和流处理的结果会进行合并。
Marz认为,大数据系统应当具有以下的关键特性
- Robust and fault-tolerant(容错性和鲁棒性):对大规模分布式系统来说,机器是不可靠的,可能会当机,但是系统需要是健壮,行为正确的,即使是遇到机器错误。除了机器错误,人更可能会犯错误。在软件开发中难免会有一些Bug,系统必须对有Bug的程序写入的错误数据有足够的适应能力,所以比机器容错性更加重要的容错性是人为操作容错性。对于大规模的分布式系统来说,人和机器的错误每天都可能会发生,如何应对人和机器的错误,让系统能够从错误中快速恢复尤其重要。
- Low latencyreadsandupdates(低延时):很多应用对于读和写操作的延时要求非常高,要求对更新和查询的响应是低延时的。
- Scaable(横向扩容):当数据量/负载增大时,可扩展性的系统通过增加更多的机器资源来维持性能。也就是常说的系统需要线性可扩展,通常采用scaleout(通过增加机器的个数)而不是scaleup(通过增强机器的性能)。
- General(通用性):系统需要能够适应广泛的应用,包括金融领域、社交网络、电子商务数据分析等。
- Extensible(可扩展):需要增加新功能、新特性时,可扩展的系统能以最小的开发代价来增加新功能。
- Allows ad hoc queries(方便查询):数据中蕴含有价值,需要能够方便,快速的查询出所需要的数据。
- Minimal maintenance(易于维护):系统要想做到易于维护,其关键是控制其复杂性,越是复杂的系统越容易出错、越难维护。
- Debuggable(易调试):当出问题时,系统需要有足够的信息来调试错误,找到问题的根源。其关键是能够追根溯源到每个数据生成点。
对于数据系统,可以简化为:数据系统 = 数据 + 查询
lambda架构中对数据存储采用的方式是:数据不可变,存储所有数据。
通过采用不可变方式存储的数据,可以有以下好处
- 简单,采用不可变的数据模型,存储数据时只需要简单的往主数据集后追加数据即可。相比于采用可变的数据模型,为了Update操作,数据通常需要被索引,从而能快速找到要更新的数据去做更新操作。
- 应对人为和机器的错误。前述中提到人和机器每天都可能会出错,如何应对人和机器的错误,让系统能够从错误中快速恢复极其重要。不口变性(Immutability)和重新计算(Recomputation)则是应对人为和机器错误的常用方法。采用可变数据模型,引发错误的数据有可能被覆盖而丢失。相比于采用不可变的数据模型,因为所有的数据都在,引发错误的数据也在。
修复的方法就可以简单的是遍历数据集上存诸的所有的数据,丢弃错误的数据,重新计算得到Views。重新计算的关键点在于利用数据的时间特性决定的全局次序,依次顺序重新执行。必然能得到正确的结果。
——引用自 微信公众号 大数据肌肉猿
对于数据系统中的查询,有一类成为Monoid特性的函数应用非常广泛,简单来说有些类似于加法的结合律 ( a + b ) + c = a + ( b + c ),比如多个数的平均值Avg函数,多个平均值没法直接通过结合来得到最终的值,可以通过拆成分母除以分子,分母和分子都是证书的加法,从而来达到目的,这个特性在分布式计算中极其重要,我们可以使用这个特性,将计算分解到多个节点并行计算,再结合各自的部分运算结果得到最终结果,同时也意味着部分运算结果可以储存下来被别的运算共享利用,从而减少重复运算工作量。
二、lambda架构
正如我们文章开头提出的问题,海量数据的即时计算即使查询的痛点,我们可以使用lambda架构来解决。
lambda架构分为三层
- Batch Layer:批处理层,对离线的历史数据进行预计算,为了下游能够快速查询想要的结果。由于批处理基于完整的历史数据集,因此准确性可以得到保证。批处理层可以用 Hadoop、Spark 和 Flink 等框架计算
- Speed Layer:加速处理层,处理实时的增量数据,这一层重点在于低延迟。加速层的数据不如批处理层那样完整和准确,但是可以填补批处理高延迟导致的数据空白。加速层可以用 Storm、Spark streaming 和 Flink 等框架计算
- Serving Layer:合并层,计算历史数据和实时数据都有了, 合并层的工作自然就是将两者数据合并,输出到数据库或者其他介质,供下游分析。
这里涉及到上文中提到的加法结合律数据合并问题,只需要简单的合并Batch View和Realtime View。否则,需要把查询函数转换为多个满足Monoid性质的查询函数的运算,单独对每个满足Monoid性质的查询函数进行Batch View和Realtime View中的结果数据集合并,然后再计算得到最终的结果数据集。也可以根据业务自身特性,运用业务自身的规则来对Batch View和Realtime View中的结果数据集合并。
Speed Layer中处理的数据也不断写入Batch Layer,当Batch Layer中重新计算的数据集包含Speed Layer处理的数据集后,当前的Realtime View就可以丢弃,这也就意味着Speed Layer处理中引入的错误,在Batch Layer重新计算时都可以得到修正。这点也可以看成是CAP理论中的最终一致性(Eventual Consistency)的体现。
上面分别讨论了Lambda架构的三层:Batch Layer,Speed Layer和Serving Layer。下图给出了Lambda架构的一个完整视图和流程。数据流进入系统后,同时发往Batch Layer和Speed Layer处理。Batch Layer以不可变模型离线存储所有数据集,通过在全体数据集上不断重新计算构建查询所对应的Batch Views。Speed Layer处理增量的实时数据流,不断更新查询所对应的Realtime Views。Serving Layer响应用户的查询请求,合并Batch View和Realtime View中的结果数据集到最终的数据集。
三、实践
我们创建一个示例应用来演示Lambda架构,这个实力的主要目的是统计从某时刻到现在此时此刻的#标签
Batch Layer
为了简单起见,假设我们的主数据集包含自时间开始以来的所有标签数据,此外我们做了一个预计算的批处理View,其中包含自项目运行时间开始依赖的#标签统计信息
apache - 6
spark - 15
flink - 14
beam - 2
lambda - 5
ranger - 7
kerberos - 9
hbase - 3
Speed Layer
当程序运行中,我们的程序接收到了新的标签信息,如下
#lambda#ranger#spark#apache
这是我们的Speed Layer层会对新数据做实时统计,并生成Realtime View,如下
lambda - 1
ranger - 1
spark - 1
apache - 1
Serving Layer
当终端用户查询结果时,我们只需要将Batch View和Realtime View合并即可
apache - 7
spark - 16
flink - 14
beam - 2
lambda - 6
ranger - 8
kerberos - 9
hbase - 3
四、lambda优缺点
lambda不只有优点,也还是存在一些缺点,我们在做架构选型时,也要考虑当前现有的场景、硬件条件来做选择。
优点:
- 职责边界清晰。Speed Layer处理数据为最近的增量数据流,Batch Layer处理的是全体数据集。Speed Layer为了效率,接收到新数据时不断更新Realtime View,而Batch Layer根据全体离线数据集直接得到Batch View。Speed Layer是一种增量计算,而非重新计算(recomputation)。
- 容错性。Speed Layer中处理的数据也不断写入Batch Layer,当Batch Layer中重新计算的数据集包含Speed Layer处理的数据集后,当前的Realtime View就可以丢弃,这意味着Speed Layer处理中引入的错误,在Batch Layer重新计算时都可以得到修正。这点也可以看成是CAP理论中的最终一致性(Eventual Consistency)的体现。
- 复杂性隔离。Batch Layer处理的是离线数据,可以很好的掌控。Speed Layer采用增量算法处理实时数据,复杂性比Batch Layer要高很多。通过分开Batch Layer和Speed Layer,把复杂性隔离到Speed Layer,可以很好的提高整个系统的鲁棒性和可靠性。
缺点:
- 实时与批量计算结果不一致引起的数据口径问题:因为批量和实时计算走的是两个计算程序,算出的结果往往不同,经常看到一个数字当天看是一个数据,第二天看昨天的数据反而发生了变化。
- 批量计算在计算窗口内无法完成:在IOT时代,数据量级越来越大,经常发现夜间只有4、5个小时的时间窗口,已经无法完成白天20多个小时累计的数据,保证早上上班前准时出数据已成为每个大数据团队头疼的问题。
- 开发和维护的复杂性问题:Lambda 架构需要在两个不同的 API(application programming interface,应用程序编程接口)中对同样的业务逻辑进行两次编程:一次为批量计算的ETL系统,一次为流式计算的Streaming系统。针对同一个业务问题产生了两个代码库,各有不同的漏洞。这种系统实际上非常难维护
- 服务器存储大:数据仓库的典型设计,会产生大量的中间结果表,造成数据急速膨胀,加大服务器存储压力。