我正在处理的应用程序有一个活动源,每个用户都可以看到他们朋友的活动(很像Facebook)。我正在寻找一种适度可扩展的方式来动态显示给定用户的活动流。我说“适度”因为我只想用数据库(Postgresql)和可能 memcached来做这件事。例如,我希望这个解决方案可以扩展到200k用户,每个用户有100个朋友。
目前,有一个主活动表存储了给定活动的渲染html(Jim添加了一个朋友,George安装了一个应用程序等)。此主活动表保留源用户,html和时间戳。
然后,有一个单独的('join')表,它只是指向应该在朋友提要中看到此活动的人的指针,以及指向主活动表中对象的指针。
所以,如果我有100个朋友,并且我做3个活动,那么连接表将增加到300个项目。
显然,这张表会很快增长。但它具有不错的属性,即向用户显示的获取活动只需要一个(相对)便宜的查询。
另一种选择是保留主活动表并通过以下方式查询:
select * from activity where source_user in (1, 2, 44, 2423, ... my friend list)
这样做的缺点是您要查询可能永远不会处于活动状态的用户,并且随着您的朋友列表的增长,此查询会变得越来越慢。
我看到双方的优点和缺点,但我想知道是否有些SO人可以帮助我权衡选项并提出一种方式或其他方式。我也对其他解决方案持开放态度,但我想保持简单,不要像CouchDB那样安装等。
非常感谢!
答案 0 :(得分:12)
我倾向于拥有主活动表。如果你这样做,我会考虑实施这个:
您可以在从数据库中提取数据时创建多个活动表并执行UNION ALL。例如,每月滚动它们 - activity_2010_02等。只是按照你的例子 - 200K用户x 100个朋友x 3个活动= 6000万行。对于PostgreSQL来说,性能并不是一个值得关注的问题,但是你现在可能认为这只是为了方便,最终是为了毫不费力的未来扩展。
这样做的缺点是您要查询可能永远不会处于活动状态的用户,并且随着您的朋友列表的增长,此查询会变得越来越慢。
您是否要显示整个活动Feed,这可以追溯到时代的开始?您没有在原始问题中提供太多详细信息,但我猜测您将显示按时间戳排序的最后10/20/100项目。一些索引和LIMIT子句应足以提供即时响应(因为我刚刚在一个大约有2000万行的表上进行了测试)。在繁忙的服务器上它可能会变慢,但这应该是硬件和缓存解决方案的解决方案,Postgres不会成为那里的瓶颈。
即使您确实提供了回溯到时间的活动供稿, paginate 输出! LIMIT子句将为您节省开支。如果带有LIMIT的基本查询不够,或者如果您的用户有一长串不再活跃的朋友,您可以考虑将查找限制为最后一天/周/月首先和然后提供朋友ID列表:
select * from activity
where ts <= 123456789
and source_user in (1, 2, 44, 2423, ... my friend list)
如果您有一个跨越数月或数年的表,则只会在第一个WHERE子句选择的行中搜索friends id。
这就是我现在正在考虑的两种解决方案之间的选择。我还会看一下这样的事情:
重新考虑你的表的非规范化。存储预生成的HTML输出真的是最好的方法吗?通过查找活动查找表并动态生成模板化输出,您会在性能方面做得更好吗?预先生成的HTML在开始时看起来似乎更好,但考虑诸如磁盘存储,API,未来布局更改和存储HTML之类的东西可能并不那么吸引人。查找表可以包含您可能的活动 - 添加朋友,更改状态等,如果其他用户参与活动,活动日志将引用该信息以及朋友的ID。
执行预生成HTML,但不将其存储在数据库中。将内容保存在磁盘上作为预生成的页面。然而,这不是一个灵丹妙药,在很大程度上取决于您网站上的写入读取比率。即公共论坛上的典型讨论主题可能有十几条消息,但可以被观看数百次 - 一个很好的缓存候选者。然而,如果您的应用程序更多地针对即时状态更新而且您必须重新生成HTML页面并在每次观看后再次将其保存在磁盘上,那么这种方法几乎没有价值。
希望这有帮助。