1.3.4 Lambda架构
对于有状态的流处理,当数据越来越多时,必须用分布式的集群架构来获取更高的吞吐量。但是分布式架构会带来另一个问题:怎样保证数据处理的顺序是正确的呢?
对于批处理来说,这并不是一个问题,因为所有数据都已收集完毕,可以根据需要选择、排列数据而得到想要的结果。但是如果我们采用“来一个处理一个”的流处理,就可能出现“乱序”现象:本来先发生的事件,因为分布处理滞后了。那么应该怎么解决这个问题呢?
以Storm为代表的第一代分布式开源流处理器主要专注于具有毫秒级延迟的事件处理,特点就是快;而对于准确性和结果的一致性是不提供内置支持的,因为结果有可能取决于事件到达的时间和顺序。另外,第一代流处理器通过检查点来保证容错性,但是在故障恢复的时候,即使事件不会丢失,也有可能被重复处理,因此,无法保证exactly-once。
与批处理器相比,可以说第一代流处理器牺牲了结果的准确性,用来换取更低的延迟。而批处理器恰好相反,牺牲了实时性,换取了结果的准确性。
我们自然想到,如果可以让二者相结合,不就可以同时提供低延迟和准确的结果了吗。正是基于这样的思想,Lambda架构被设计出来,如图1-10所示,可以认为这是第二代流处理架构,但事实上它只是第一代流处理器和批处理器的简单合并。
图1-10 Lambda架构示意图
Lambda架构的主体是传统批处理架构的增强。它的批处理层(Batch Layer)就是由传统的批处理器和存储空间组成的;而实时层(Speed Layer)则由低延迟的流处理器组成。数据到达之后,两层处理双管齐下,一边由流处理器进行实时处理,一边写入批处理器存储空间,等待批处理器进行批量计算。流处理器快速计算出一个近似结果,并将它们写入流处理表中;而批处理器会定期处理存储空间中的数据,将准确的结果写入批处理表中,并从流处理表中删除不准确的结果。最终,应用程序会合并流处理表和批处理表中的结果,并展示出来。
Lambda架构现在已经不再是最先进的了,但仍应用在许多地方。它的优点非常明显,就是兼具了批处理器和第一代流处理器的优点,同时保证了低延迟和结果的准确性。而它的缺点同样非常明显:首先,Lambda架构本身就很难建立和维护;其次,它需要我们对一个应用程序做出两套语义上等效的逻辑实现,因为批处理和流处理是两套完全独立的系统,它们的API也完全不同,为了实现一个应用,付出双倍的工作量,这对程序员显然不够友好。