在实时层,可以使用Riak或者Cassandra这种读写数据库,而且实时层依赖那些数据库中对状态更新的增量算法。
让Hadoop模拟实时计算的工具是Storm。我写Storm的目的是让Hadoop可以健壮、可扩展地处理大量的实时数据。Storm在数据流上运行无限的计算,并且对这些数据处理提供了强有力的保障。
让我们回到刚才那个根据某个URL查询某个页面在某个时间段内页面访问量的例子,通过这个例子我将展示实时层是如何工作的。
批处理系统还是跟之前一样:一个基于Hadoop和ElephantDB的批处理工作流,在几个小时之前的数据上预计算查询函数。剩下就是让实时系统去处理最近几小时数据了。
我们将最近几小时的数据状态存入Cassandra中,用Storm去处理页面访问量数据流并并行更新到数据库中,针对每一个页面访问量,在[URL, hour]所代表的key下,有一个计数器,这个计数器在Cassandra中实现。这就是所有的事情,Storm让事情变得非常简单。
图4 批处理/实时架构示例
批处理层+实时层、CAP定理和人为错误容忍性
貌似又回到一开始提出的问题上去了,访问实时数据需要使用NoSQL数据库和增量算法。这就说明回到了版本化数据、矢量时钟和读取修复这些复杂问题中来。但这是有本质区别的。由于实时层只处理最近几小时的数据,所有实时层的计算都会被最终批处理层重新计算。所以如果犯了什么错误或者实时层出了问题,最终都会被批处理层更正过来,所有复杂的问题都是暂时的。
这并不意味着不需要关心实时层的读取修复和最终一致性,你仍然需要实时层尽可能的一致。但当犯了一个错误时,不会永久性地破坏数据。这便移除了许多你所需要面对的复杂问题。
在批处理层仅需要考虑数据和数据上的查询函数,批处理层因此很好掌控。在实时层,需要使用增量算法和复杂的NoSQL数据库。把所有的复杂问题独立到实时层中,对系统的鲁棒性、可靠性做出了重大贡献。
同样的,实时层并没有影响系统的人为错误容忍性,这个数据不可变和只追加的批处理系统,仍然是整个系统的核心,所以所有的都可以像上面说的一样被纠正过来。
我有一个类似的系统:Hadoop和ElephantDB组成批处理系统,Storm和Cassandra组成实时系统。由于缺乏监控,某天当我起床的时候发现Cassandra运行满负荷了,使得所有的数据请求都超时。这使得Storm计算失败,一些数据又重新回到了等待队列中,这个数据就一次次重复请求。
如果我没有批处理层,那么我就需要扩展和恢复Cassandra,这个很不容易。更糟的是,因为请求不断的重复,无法得到正确的数据。
幸运的是,所有的复杂问题都被隔离到实时层中去了,我清空了所有的后台请求队列,把它们打到了批处理层上,同时重启了Cassandra集群,过了几个小时之后所有数据都恢复正常了。没有错误数据,请求中也没有不准确的地方。