总结:对于大约 100 万活跃用户和 1.5 亿存储活动,我保持简单:
- 使用关系数据库来存储唯一活动(每个活动 1 条记录/“发生的事情”) 使记录尽可能紧凑。结构,以便您可以通过活动 ID 或使用一组有时间限制的朋友 ID 快速抓取一批活动。
- 每当创建活动记录时,将活动 ID 发布到 Redis,将 ID 添加到应该看到该活动的每个朋友/订阅者的“活动流”列表中。
查询 Redis 以获取任何用户的活动流,然后根据需要从数据库中获取相关数据。如果用户需要及时浏览(如果你甚至提供这个),则回退到按时间查询数据库
我使用一个普通的旧 MySQL 表来处理大约 1500 万个活动。
看起来像这样:
id
user_id (int)
activity_type (tinyint)
source_id (int)
parent_id (int)
parent_type (tinyint)
time (datetime but a smaller type like int would be better)
activity_type 告诉我活动的类型,source_id 告诉我活动相关的记录。因此,如果活动类型表示“添加收藏”,那么我知道 source_id 是指收藏记录的 ID。
parent_id/parent_type 对我的应用很有用 - 它们告诉我活动与什么相关。如果收藏了一本书,则 parent_id/parent_type 会告诉我该活动与具有给定主键 (id) 的一本书 (类型) 相关
我在(user_id, time) 上建立索引并查询user_id IN (...friends...) AND time > some-cutoff-point 的活动。放弃 id 并选择不同的聚集索引可能是个好主意 - 我还没有尝试过。
相当基本的东西,但它很有效,很简单,并且随着您的需求变化很容易使用。此外,如果您不使用 MySQL,您可能会在索引方面做得更好。
为了更快地访问最新活动,我一直在尝试使用Redis。 Redis 将其所有数据存储在内存中,因此您不能将所有活动都存储在其中,但您可以存储足够多的内容以供您网站上的大多数常用屏幕使用。每个用户的最近 100 个或类似的东西。混合使用 Redis,它可能会像这样工作:
- 创建您的 MySQL 活动记录
- 对于创建活动的用户的每个朋友,将 ID 推送到他们在 Redis 中的活动列表中。
- 将每个列表修剪到最后 X 项
Redis 速度很快,并且提供了一种通过一个连接传递命令的方法 - 因此将活动推送给 1000 个朋友需要几毫秒。
有关我所说的内容的更详细说明,请参阅 Redis 的 Twitter 示例:http://redis.io/topics/twitter-clone
2011 年 2 月更新我目前有 5000 万个活跃活动,我没有改变任何东西。做与此类似的事情的一件好事是它使用紧凑的小行。我计划进行一些更改,这些更改将涉及更多活动和对这些活动的更多查询,我肯定会使用 Redis 来保持速度。我在其他领域使用 Redis,它确实适用于某些类型的问题。
2014 年 7 月更新我们每月有大约 70 万活跃用户。在过去的几年里,我一直在使用 Redis(如项目符号列表中所述)来存储每个用户的最后 1000 个活动 ID。系统中通常有大约 1 亿条活动记录,它们仍然存储在 MySQL 中,并且仍然是相同的布局。这些记录让我们摆脱了更少的 Redis 内存,它们作为活动数据的记录,如果用户需要进一步回溯以查找某些内容,我们会使用它们。
这不是一个聪明或特别有趣的解决方案,但它对我很有帮助。