当然,现在讲的只不过是想法而已,而且每次从原始数据计算查询基本上不可能。但我们从中可以学到一些在实际解决方案中的关键点。
数据系统因为不可变数据和不断增长的数据集变得简单了。基本的写入操作就是写入一条新的不可变数据。数据系统通过重新从原始数据计算查询规避了CAP定理带来的复杂度。数据系统利用增量算法使得查询的返回延迟降低到一个可以接受的程度。
让我们开始探索这个数据系统应该如何设计。请注意从这里开始我们所描述都是针对系统优化、数据库、索引、EFL、批量计算、流处理——这些技术都是对查询函数的优化,让查询返回时间降低到一个可以接受的程度。这很简单,但也是数据系统所面对的现实。数据库通常是数据管理的核心,但它们是更大蓝图中的一部分。
批量计算
“如何让任意一个函数可以在任意一个数据集上快速执行完成”这个问题太过于复杂,所以我们先放宽了一下这个问题依赖条件。首先假设,可以允许数据滞后几小时。放宽这个条件之后,我们可以得到一个简单、优雅、通用的数据系统构建解决方案。之后,我们会通过扩展这个解决方案使得它可以不用放宽条件来解决问题。
由于查询是所有数据的一个函数,让查询变快的最简单的方法就是预先计算好这些查询。只要这里有新的数据,你就重新计算这些查询。这是可能的,因为我们放宽了条件使得我们的数据可以滞后几个小时。图1展示了这个工作流程。
图1 预计算工作流程
为了实现这个,你的系统需要:
能很容易存储大的、不断增长的数据集;能在数据集上可扩展地计算查询函数。
这样的系统是存在的,即Hadoop。它是一个成熟的、经历了无数团队实战检验过的系统,同时拥有一个巨大的工具生态系统。它虽不完美,但是这里用来做批量处理的最好的一个工具。
许多人也许会告诉你,Hadoop只适用于那些“非结构化”的数据,这是完全错误的看法。Hadoop处理“结构化”的数据也很不错,通过使用像Thrift或者Protocol Buffers这样的工具,你可以使用丰富的数据结构存储你的数据。
Hadoop由分布式文件系统HDFS和批处理框架MapReduce两部分构成。HDFS可以通过文件存储大量数据,MapReduce可以在这样数据上进行可扩展计算。这个系统完全符合我们的要求。
我们将数据以文件形式存储到HDFS中去。文件可以包括一个数据记录序列。新增数据时,我们只需要在包括所有数据的文件夹中新增一个包含这条新记录的文件即可。像这样在HDFS存储数据满足了“能够很容易存储大的、不断增长的数据集”这个要求。
预计算数据集上的查询也很直观,MapReduce是一个足够复杂的框架,使得几乎所有的函数都可以按照多个MapReduce任务这种方式实现。像Cascalog、Cascading和Pig这样的工具使实现这些函数变得十分简单。
最后,为了可以快速访问这些预计算查询结果,你需要对查询结果进行索引,这里有许多数据库可以完成这个工作。ElephantDB和Voldemort read-only可以通过从Hadoop中导出key/value数据来加快查询速度。这些数据库支持批量写和随机读,同时不支持随机写。随机写使得数据库变得复杂,所以通过不支持随机写,这些数据库设计得特别简洁,也就几千行代码而已。简洁使得这些数据库鲁棒性变得非常好。