【问题标题】:MongoDB database schema designMongoDB数据库架构设计
【发布时间】:2012-06-06 17:13:03
【问题描述】:

我有一个拥有 50 万用户的网站(在 sql server 2008 上运行)。我现在想包括用户及其朋友的活动流。在 SQL Server 上测试了一些东西后,很明显 RDMS 不是这种功能的好选择。它很慢(即使我对数据进行了严重的非规范化)。因此,在查看了其他 NoSQL 解决方案之后,我认为我可以使用 MongoDB 来解决这个问题。我将关注基于 activitystrea.ms 的数据结构 json specifications for activity stream 所以我的问题是:MongoDB 中活动流的最佳模式设计是什么(有这么多用户,您几乎可以预测它的写入量会很大,因此我选择了 MongoDB——它具有出色的“写入”性能。我考虑了 3 种类型的结构,请告诉我这是否有意义或者我应该使用其他模式模式。

1 - 以这种模式存储所有朋友/关注者的每个活动:

{ _id:'activ123', 演员:{ 编号:person1 }, 动词:'跟随', 目的:{ 对象类型:'人', id:'person2' }, 更新:日期(), 消费者:[ person3, person4, person5, person6, ... 等等 ] }

2 - 第二种设计:集合名称-activity_stream_fanout

{ _id:'activ_fanout_123', 人名:person3, 活动:[ { _id:'activ123', 演员:{ 编号:person1 }, 动词:'跟随', 目的:{ 对象类型:'人', id:'person2' }, 更新:日期(), } ],[ //活动提要2 ] }

3 - 这种方法是将活动项目存储在一个集合中,将消费者存储在另一个集合中。在活动中,你可能有这样的文档:

{ _id:“123”, 演员:{人:“UserABC”}, 动词:“跟随”, 对象:{人:“someone_else”}, 更新日期:日期(...) }

然后,对于追随者,我会有以下“通知”文件:

{ activityId:“123”,消费者:“someguy”,updatedOn:日期(...)} {activityId:“123”,消费者:“otherguy”,updatedOn:日期(...)} {activityId:“123”,消费者:“thirdguy”,updatedOn:日期(...)}

非常感谢您的回答。

【问题讨论】:

    标签: mongodb android-activity stream


    【解决方案1】:

    我会采用以下结构:

    1. 对发生的所有操作使用一个集合,Actions

    2. 为谁关注谁使用另一个集合,Subscribers

    3. 对某个用户的新闻提要使用第三个集合Newsfeed,项目从Actions 集合中扇出。

    Newsfeed 集合将由一个异步处理新Actions 的工作进程填充。因此,新闻提要不会实时填充。我不同意 Geert-Jan 的观点,即实时性很重要。我相信大多数用户都不在乎大多数(不是全部)应用程序中的一分钟延迟(对于实时,我会选择完全不同的架构)。

    如果您有大量的consumers,扇出可能需要一段时间,确实如此。另一方面,将消费者直接放入对象中也不适用于非常大的关注者数量,并且会创建占用大量索引空间的过大对象。

    然而,最重要的是,扇出设计更灵活,并允许相关性评分、过滤等。我最近写了一篇关于 news feed schema design with MongoDB 的博客文章,我在其中解释了一些更详细地了解这种灵活性。

    说到灵活性,我会小心那个 activitystrea.ms 规范。作为不同提供商之间互操作的规范似乎很有意义,但只要您不打算聚合来自各种应用程序的活动,我就不会将所有详细信息存储在我的数据库中。

    【讨论】:

    • 很好的建议。对于实时,我不是指亚秒级,我只是指实时,因为速度足够快,以至于您不会从 OP 的场景 2 中“批处理”多个用户活动中获得很多收益。再说一次,我不熟悉“扇出”一词(OP的第二个选项似乎指的是,您也提到了),所以我可能没有完全理解 2. 的意图。 .. 顺便说一句:去阅读那篇博文,总是很高兴看到关于 MongoDB Schema 设计的架构文章
    • 很好读,我在你的博客上留下了一个你可能想阅读的相关问题的评论。谢谢
    • 各位,非常感谢您的建议。我将@mnemosyn 帖子标记为答案,因为它确实有意义。我会读你的博客,看看它会把我带到哪里。再次感谢您提供所有建议的日志。
    • @mnemosyn :这个设计让我害怕的是,扇出的“Newsfeed”集合会增长得非常快。假设我们只有 1000 个注册用户,每个用户后面跟着 10 个用户,每个用户每天执行 10 个操作。然后每 10 天“Newsfeed”集合将增长 1 000 000 条记录。请告诉我如何处理。
    • 伙计们,我好像错过了你们的 cmets :-( 删除旧帖子是有意义的 - 大多数新闻源不允许您返回很远。Facebook 对其时间线使用了大量缓存功能。您不能在 RAM 中保留所有用户的所有活动的详细日志。困难的部分是有效地删除旧的东西。另一种方法是为每个用户使用预先分配的空列表,再次保持最大大小每个用户的条目不变。但即使是 1M 条目,每个条目 80b 和两个服务器副本集,也就是 160M RAM 或每个用户每月大约 0.07 美分,以将最后 1000 个条目保留在 RAM 中。
    【解决方案2】:

    我认为您应该查看您的访问模式:您可能对这些数据执行最多的查询等。

    对我来说,需要最快的用例是能够将某个活动推送到每个“活动消费者”的“墙”(以 fb 而言)并在活动进入时立即执行.

    从这个角度来看(我没有考虑太多)我会选择 1,因为 2. 似乎在处理某个用户之前为某个用户批处理活动?因此,如果失败,则“立即”需要更新。此外,对于这个用例,我没有看到 3. 超过 1 的优势。

    对 1 的一些增强?问问自己,您是否真的需要为每个活动定义一组消费者的灵活性。真的有必要在这个细粒度的范围内指定这个吗?相反,提及“演员”的“朋友”还不够吗? (从长远来看,这将有很多空间,因为当消费者通常在数百个(?)范围内时,我认为消费者数组是每个活动的整个消息的大部分。

    在一些相关的说明上:根据您可能希望如何为这些活动流实现实时通知,可能值得看看 Pusher - http://pusher.com/ 和类似的解决方案。

    【讨论】:

      猜你喜欢
      • 2015-08-29
      • 2012-08-27
      • 2020-09-20
      • 1970-01-01
      • 2016-11-30
      • 2012-08-25
      • 2011-05-25
      • 1970-01-01
      相关资源
      最近更新 更多