以较为可扩展的方式传送活动订阅内容

16
我正在开发的应用有一个活动源,每个用户都可以看到他们朋友的活动(类似于Facebook)。我正在寻找一种适度可扩展的方法,以便即时显示给定用户的活动流。我说“适度可扩展”是因为我想仅使用数据库(Postgresql)和可能的 memcached来完成此操作。例如,我希望这个解决方案可以扩展到每个拥有100个好友的200k个用户。
目前,有一个主活动表,存储给定活动的呈现html(Jim添加了一个朋友,George安装了一个应用程序等)。该主活动表保留源用户、html和时间戳。
然后,有一个单独的(“连接”)表,简单地保留指向应在其好友源中查看此活动的人以及对主活动表中对象的指针。
因此,如果我有100个朋友,并且我进行3项活动,则加入表将增长到300个项目。
显然,这张表会迅速增长。不过,它具有良好的特性,即获取要向用户显示的活动只需要进行单个(相对)廉价的查询。
另一种选择是仅保留主要活动表,并通过类似于以下内容的查询来查询它:
select * from activity where source_user in (1, 2, 44, 2423, ... my friend list)
这种方法的缺点是你查询了可能永远不会活跃的用户,随着朋友列表的增长,这个查询会变得越来越慢。
我看到双方的利弊,但我想知道一些SO的人是否可以帮助我权衡一下选择,并建议一种方式。我也愿意接受其他解决方案,尽管我想保持简单,不安装像CouchDB之类的东西。
非常感谢!
1个回答

12

我倾向于只有一个主活动表。如果你选择这样做,以下是我建议实现的内容:

  1. 您可以创建多个活动表,并在从数据库获取数据时使用UNION ALL。例如,每月滚动它们-activity_2010_02等。根据您的示例-200K用户x 100个朋友x 3个活动= 6000万行。对于PostgreSQL来说,在性能方面不是什么问题,但出于纯粹的方便和未来的扩展,您可能要考虑这一点。

  2. 这种方法的缺点是查询了可能永远不会活跃的用户,并且随着朋友列表的增长,这个查询可能变得越来越慢。

您是否将显示整个活动源,回溯到最初的时间?原始问题中提供的细节不多,但我猜测您将显示按时间戳排序的最后10/20/100个项目。几个索引和LIMIT子句应该足以提供即时响应(我刚刚在大约2000万行的表格上进行了测试)。在繁忙的服务器上可能会慢一些,但这是需要通过硬件和缓存解决方案解决的问题,Postgres不会成为瓶颈。

即使您提供回溯到时间之初的活动提要,也要进行分页! LIMIT子句将在此处为您节省。如果基本查询带有LIMIT不足以满足需求,或者如果您的用户有一长尾段的不再活跃的朋友,您可以考虑首先将查找限制为最近一天/一周/一个月,然后提供朋友id列表:

select * from activity 
  where ts <= 123456789 
    and source_user in (1, 2, 44, 2423, ... my friend list)
如果您拥有跨越几个月或几年的表,那么查找朋友ID的搜索将仅在第一个WHERE子句选择的行中执行。
这只是针对您现在考虑的两种解决方案之一。我还会考虑以下事项:
1. 重新考虑表的非规范化。存储预先生成的HTML输出是否真的是最佳方式?从性能角度来看,通过拥有一个活动的查找表并动态生成模板输出是否更好?预先生成的HTML可能在开始时看起来更好,但考虑磁盘存储、API、未来布局更改等问题,存储HTML可能并不那么有吸引力。查找表中可以包含您可能的活动 - 添加朋友、更改状态等,并且活动日志将参考其中的内容,以及如果涉及其他用户,则参考该用户的ID。
2. 进行预先生成HTML,但不要将其存储在数据库中。将这些内容保存为预生成页面。然而,这并不是万无一失的方案,很大程度上取决于站点的写入-读取比例。例如,在公共论坛上,一个典型的讨论线程可能有十多个留言,并且可能被查看数百次 - 这是缓存的好候选对象。而如果您的应用程序更加关注即时状态更新,并且您必须在每次查看之后重新生成HTML页面并将其再次保存到磁盘上,则此方法的价值很小。
希望这可以帮助到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接