8.3 设计数据库模式
本书中多次重复的内容是了解我们的数据及其用途的重要性。 现在,在这个实践练习中,我们比以往任何时候都要更加细致地设计我们的模式,并考虑到每一个细节。 在上一节中,我们定义了要从Web服务器访问日志中提取的数据集。 下一步是列出与数据库客户端相关的需求。 如前所述,一个进程将负责从日志文件中捕获信息并将其写入MongoDB,另一个进程将读取已保存在数据库中的信息。 一个关注点是在MongoDB中写入文档过程中的性能表现,因为确保信息几近实时生成非常重要。 既然我们没有先期对每秒数据量的估计,我们将会持乐观态度。 让我们设想一下,从Web服务器到MongoDB实例将一直都有大量的数据交互。 考虑到这一要求,我们会担心随着时间的推移会增加的数据量。 更多的事件意味着会插入更多的文档。 这些是我们的系统运行良好的主要要求。 初看起来,我们可以想象,这完全是关于定义文档格式并将其保存到集合中。 但以这种方式思考就是忽略了众所周知的MongoDB架构灵活性。 因此,我们将分析吞吐量问题,以确定信息的持续存储位置和方式。
8.3.1 捕获事件请求
Web服务器吞吐量分析可能是最简单的任务。 简单地说,事件数量的度量将给我们一个代表Web服务器吞吐量的数字。 因此,如果对于每个生成的事件执行写入文档来描述此操作的时间,是否意味着我们可以轻松获得吞吐量? 正是如此! 因此,我们可以分析吞吐量的最简单方式是表现为一个MongoDB文档。
在文档集合中执行count方法时,我们将获得Web服务器的吞吐量值。 假设我们有一个名为events的集合,为了找出吞吐量,我们必须在mongod shell中执行以下命令:
这个命令返回直到目前在我们的web服务器上生成的事件总数。但是,这是我们想要的数字吗? 不是。在一定的时间内没有把事件总数放在一起是没有意义的。 不知道什么时候开始记录这些事件或者甚至是最后一个事件的产生时,它有可能是直到目前为止由Web服务器处理的10000条事件中的任意用法吗? 如果我们想要在给定的时间段内对事件进行计数,最简单的方法是包含一个代表事件创建日期的字段。 这个文件的一个例子如下所示:
因此,我们可以通过执行查询来检查给定时间段内Web服务器中的请求总数。 执行此查询的最简单方法是使用聚合框架。 在mongod shell上执行以下命令将返回每分钟请求的总数:
:
聚合管道有其限制。 如果命令结果返回超过BSON文档大小的单个文档,则会产生错误。 自MongoDB 2.6发行版以来,聚合命令返回一个游标,因此它可以返回任意大小的结果集。您可以在MongoDB参考手册中找到关于聚合管道限制的更多信息: http://docs.mongodb.org/manual/core/aggregation-pipeline-limits/.
在命令管道中,我们定义$group阶段以按日、月、年、小时和分钟对文档进行分组。 我们使用$sum运算符对所有数据进行计数。例如,从这个聚合命令的执行中,我们将有类似这些文件:
在这个输出中,可以知道在特定时间段内Web服务器接收到多少请求。 发生这种情况的原因是$group运算符的行为,该操作将文档与查询匹配,然后基于一个或多个字段收集文档组。 我们将$date_created字段的每个部分(例如月,日,年,小时和分钟)用到聚合管道的分组阶段。 如果您想知道哪些资源在吞吐量较高的Web服务器中最常访问,则这些选项都不符合此请求。 但是,这个问题的快速解决方案很容易获得。 乍一看,最快的方法是解构事件并创建更复杂的文档,如下例所示:
通过使用这种文档设计,可以在聚合框架的帮助下了解每分钟的资源吞吐量:
在前面的管道中,第一步是按资源分组并统计一整天内资源请求发生的次数。 下一步是使用运算符$project,并与运算符$divide一起使用,来计算给定资源的点击次数,并除以1440分钟计算每分钟的平均值,即每天的总分钟数 或24小时。 最后,我们按降序排列结果,以查看哪些资源具有更高的吞吐量。 为了保持清楚,我们将逐步执行管道并解释每个步骤的结果。 在执行第一阶段时,我们如下执行:
此执行按字段资源对事件收集文档进行分组,并使用值为1时$sum运算符,计算字段匹配的出现次数。 返回的结果如下所示
在管道的第二阶段,我们使用运算符$project,这将给出每分钟命中数或点击数:
以下是这个阶段的结果:
最后阶段是按降序对吞吐量进行排序:
生成的输出如下所示:
看起来我们成功地为我们的文档获得了一个好的设计。现在我们可以提取所需的分析和其他分析,我们将会看到更多,因此我们现在可以停下来。 错误! 我们将审查我们的要求,将它们与我们设计的模型进行比较,并尝试确定它是否是最佳解决方案。 我们的愿望是了解所有Web服务器资源的每分钟吞吐量的度量。 在我们设计的模型中,每个事件在我们的Web服务器中创建一个文档,并且通过使用聚合框架,我们可以计算我们需要分析信息。 这个解决方案有什么问题没? 如果你认为这是收集文件的数量,你是对的。 每个事件一个文档可以根据Web服务器流量生成大量集合。 显然,我们可以采用使用分片的策略,并通过多个主机分发这些集合。 但首先,我们将看到如何利用MongoDB中的模式灵活性来减少集合大小并优化查询。
这一节就到这,下一节,继续数据库库模式设计之“单文档解决方案”,请持续关注。
领取专属 10元无门槛券
私享最新 技术干货