假如你只有MongoDB的话,它就是没有后台存储的一个缓存。它将会产生不一致。不是最终的一致——而一直都是纯粹的、彻头彻尾的不一致。就这一点而言,你没有选择。即使毁灭式的也没有。你没有任何办法重新生成一致状态的数据。
当Diaspora项目决定将关系型数据存储于MongoDB的时候,我们将数据库与缓存合并起来。数据库与缓存是非常不一样的两种事物。对于持久化、瞬态、复制、引用、数据完整性和速度,它们有完全不一样的思想。 转变
一旦我们理解了我们一不小心给数据库选择了一个缓存,那么我们是怎样使用这个缓存的呢?
好吧,这是一个价值百万美元的问题。但是我们已经回答了价值十亿美元的问题。在这篇文章中,我已经谈到了我们是如何使用MongoDB的,相对应的是,它是如何设计其使用方法的。我已经谈过这一点了,就仿佛所有的信息都是显而易见的,只是Diaspora团队在做出选择之前没有做充足的研究。 但是这些东西一点也不显而易见。MongoDB文档告诉你它擅长什么,却没有强调它不擅长什么。这很好理解。所有项目都是这么做的。但是其结果是,这使我们花费了大约六个月,听到许多的用户埋怨,并且做了大量的调查,才由此断定我们使用MongoDB的方式不对。
没有什么别的办法,只有将数据从MongoDB中取出来,将它们迁移到一个关系型的存储设备,在此过程中要尽我们最大努力处理我们发现的不一致的数据。数据转变本身——由MongoDB导出,再导入到MySQL——非常简单明了。其中的技术细节,可以看看《你所有的基础配置2013》中的幻灯片 。 损害
我们有八个月的生产数据,这大约对应于MySQL中的120万行。我们耗费了四个双周来开发这个转换代码,当我们开始实际实施的时候,主站有大约两个小时的宕机时间。对于一个处于初期测试版的项目来说,这实在令人无法接受。我们应该缩短这个宕机时间的,但是却预估了八个小时的宕机时间,这样的话两个小时看起来似乎还很漂亮。 还不坏
尾声
还记得电视剧(TV show)的应用吗?它是MongoDB的完美用例。每个剧集都是一个文档,完全独立的文档。它不引用任何东西,没有副本,而且数据没有不一致的可能。
距离开发约过了三个月后,电视剧应用仍然在MongoDB基础上很好的运行着。后来的一个星期一,在每周计划会议上,有委托人告诉我们,有个投资人想要一项新的功能:当他们在某一集节目中看到某个演员的时候,他们想要可以点击该演员的名字,并看到这个人的整个电视职业生涯。他们想要该演员曾经出现过的所有不同剧集的一个时间排序的列表。 我们将每个剧集保存为MongoDB中的一个文档,其中包含了所有嵌套的信息,包括 整个演员班底。如果同样的演员出现于两个不同的戏,甚至是出现于同一个剧集,他们的信息在两个地方都有保存。除了比较他们的名字,我们没有办法识别出他们是否是同一个人。所以为了实现这个功能,我们必须搜索每个文档,找寻用户点击的演员,并删除重复记录。啊,对了。最起码,我们需要删除一次重复记录,然后再维护演员信息的一个外部索引,就像任何其它的缓存一样,它同样也具有失效问题。 你来看看这是怎么回事
客户期待的功能是如此微不足道。如果数据已经在关系存储,它会一直在哪里。由于这是我们第一次尝试说服项目经理,客户并不需要它MongoDB。失败后,我们提供了一些便宜的替代品,如链接到IMDB搜索演员的名字的产品。这个公司从广告赚钱,虽然如此,他们希望用户留在自己的网站上,而不是去上IMDB 。
此功能要求最终促使该项目的转换到PostgreSQL。当有更多的与客户交流后,我们意识到,客户企业看到把电视节目连接在一起很多价值。他们期望能够看到,正在看的节目的导演,他的其他节目。也希望能够看到,类似正在看的节目,其他本周发布的同一主题的节目。
这从根本上是一个沟通的问题,而不是技术问题。如果这些沟通已经提前发生了,如果我们花时间去真正了解客户端是怎么看到数据的和他们想要对数据做什么的话,我们可能会早些时候做这样一个沟通,那个时候有较少的数据,并且变更也较容易。 |