构建一个类似Facebook的个性化新闻源:SQL,MongoDB?

时间:2011-12-13 15:36:53

标签: sql mongodb facebook optimization database

我正在构建类似Facebook的新闻源。这意味着它是从许多SQL表构建的,每个数据类型都有一个特定的布局。但是它的负载变得非常沉重,我希望能让它变得更加复杂......

这就是我现在所做的事情:

用户模型:

  def updates(more_options = {})
        (games_around({},more_options) + friends_statuses({},more_options).sort! { |a,b| b.updated_at <=> a.updated_at }.slice(0,35) + friends_stats({:limit  => 10},more_options) + friends_badges({:limit  => 3},more_options)).sort! { |a,b| b.updated_at <=> a.updated_at }
  end

徽章数据示例:

  def friends_badges(options = {:limit  => 3}, more_options = {})
    rewards = []
      rewards = Reward.find(:all, options.merge!(:conditions  => ["rewards.user_id IN (?)",self.players_around({},more_options).collect{|p| p.id}], :joins  => [:user, :badge], :order  => "rewards.created_at DESC"))            
    rewards.flatten
  end

新闻源视图:

<% for update in @current_user.updates %>
        <% if update.class.name == "Status" %>
            <% @status = update %>
            <%= render :partial  => "users/statuses/status_line", :locals  => {:status  => update} %>
        <% elsif update.class.name == "Game" %>
            <%= render :partial => "games/game_newsfeed_line", :locals  => {:game  => update} %>
        <% elsif update.class.name == "Stat" %>
            <%= render :partial => "stats/stat_newsfeed_line", :locals  => {:stat  => update} %>
        <% elsif update.class.name == "Reward" %>
            <%= render :partial => "badges/badge_newsfeed_line", :locals  => {:reward  => update} %>
        <% end %>
    <% end %>

我想到的选项:

  • 构建“Feed”表并使用后台作业为每个用户预处理大部分更新。最有可能是一小时的cron。我会为每次更新存储整个HTML代码。
  • 保留初始结构,但分别缓存每个更新(现在我没有缓存)
  • 切换到MongoDB以更快地访问数据库

我不得不说,我不是真正的专家,Rails的第一步很容易,但现在每页加载超过150个SQL请求,我觉得它失控,需要专家的观点... < / p>

你会做什么?

感谢您的宝贵帮助,

Screenshots

1 个答案:

答案 0 :(得分:2)

你的代码并没有告诉我很多;我认为如果你能用普通的JSON / SQL布局你的数据结构会很有帮助。

无论如何,我将每个用户的流序列化为MongoDB。我不会出于各种原因将HTML存储在数据库中(至少不是在软件的那个级别);相反,您应该将相关数据保存在(可能是多态的)集合中。获取新闻源很容易,索引很简单,等等。视图结构基本上不会改变。如果您以后想要更改HTML,那也很容易。

缺点是这将复制大量数据。如果人们可以拥有大量粉丝,这可能会成为一个问题。使用用户ID数组而不是单个用户ID可能有所帮助(如果所有关注者的信息相同),但它也是有限的。

对于非常大的关联问题,只有缓存。我理解它的方式,facebook和twitter的神奇之处在于它们不会经常访问数据库并在RAM中保留大量数据。如果您正在关联数十亿个项目,那么即使在RAM中也是如此。

更新应该连续写入,而不是每小时写一次。假设您有大量流量,每小时更新需要30分钟。现在,最坏的情况是90分钟。延迟。如果您及时处理更改,则可以将其缩短到5分钟。

你必须在某些时候抛出假设,使用缓存和一些启发式方法。一些例子:

  • 推文越近,流量就会越多。它被转发的可能性更高,并且更常见。把它放在RAM中。
  • 您1991年的Facebook时间线概述页面可能不会每天更改,因此这是长期输出缓存的候选者。
  • 目前的Facebook活动可能会经历很多写作。输出缓存在这里没有多大帮助。同样,该对象应保存在RAM中。