我正在处理的应用程序有一个活动源,每个用户都可以看到他们朋友的活动(很像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等的东西.
非常感谢!
我倾向于只拥有主活动表.如果你这样做,我会考虑实施:
从数据库中获取数据时,可以创建多个活动表并执行UNION ALL.例如,每月滚动它们 - activity_2010_02等.只是按照你的例子 - 200K用户x 100个朋友x 3个活动= 6000万行.对于PostgreSQL来说,性能并不是一个值得关注的问题,但是你可能会认为这纯粹是为了方便,最终是为了轻松的未来扩展.
这样做的缺点是您正在查询可能永远不会处于活动状态的用户,并且随着您的朋友列表的增长,此查询会变得越来越慢.
您是否要显示整个活动源,可以追溯到时代的开始?您没有在原始问题中提供太多详细信息,但我猜测您将显示按时间戳排序的最后10/20/100项目.一些索引和LIMIT子句应足以提供即时响应(因为我刚刚在一个大约有2000万行的表上进行了测试).在繁忙的服务器上它可能会变慢,但这应该是硬件和缓存解决方案的解决方案,Postgres不会成为那里的瓶颈.
即使您确实提供了可以追溯到时间的活动,也可以对输出进行分页!LIMIT子句将为您节省开支.如果带有LIMIT的基本查询不够,或者如果您的用户有一长串不再活跃的朋友,您可以考虑先将查询限制为最后一天/周/月,然后提供朋友ids:
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页面并在每次视图之后将其再次保存在磁盘上,那么这种方法几乎没有价值.
希望这可以帮助.