147

我正在开发自己的社交网络,我还没有在网络上找到实现用户操作流的示例......例如,如何过滤每个用户的操作?如何存储动作事件?我可以为动作流和动作本身使用哪种数据模型和对象模型?

4

6 回答 6

256

摘要:对于大约 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 内存,它们作为活动数据的记录,如果用户需要进一步回溯以查找某些内容,我们会使用它们。

这不是一个聪明或特别有趣的解决方案,但它对我很有帮助。

于 2009-11-19T20:42:44.460 回答
21

这是我使用 mysql 实现的活动流。共有三个类:Activity、ActivityFeed、Subscriber。

Activity 表示一个活动条目,它的表格如下所示:

id
subject_id
object_id
type
verb
data
time

Subject_id是执行动作的对象object_id的id,接收动作的对象的id。typeverb描述操作本身(例如,如果用户向文章添加评论,他们将分别是“评论”和“创建”),数据包含额外的数据以避免连接(例如,它可以包含主题名称和姓氏,文章标题和网址,评论正文等)。

每个 Activity 都属于一个或多个 ActivityFeed,它们通过如下所示的表关联:

feed_name
activity_id

在我的应用程序中,每个用户都有一个提要,每个项目(通常是博客文章)都有一个提要,但它们可以是您想要的任何内容。

订阅者通常是您网站的用户,但它也可以是您的对象模型中的任何对象(例如,一篇文章可以订阅其创建者的 feed_action)。

每个订阅者都属于一个或多个 ActivityFeed,并且像上面一样,它们通过这种链接表相关联:

feed_name
subscriber_id
reason

此处的reason字段解释了订阅者订阅源的原因。例如,如果用户为博客文章添加书签,则原因是“书签”。这有助于我稍后过滤通知用户的操作。

为了检索订阅者的活动,我对三个表进行了简单的连接。加入速度很快,因为我选择了很少的活动,这要归功于WHERE现在看起来像这样的条件 - time > some hours。由于活动表中的数据字段,我避免了其他联接。

reason场上的进一步解释。例如,如果我想过滤发送给用户的电子邮件通知的操作,并且用户将博客文章添加为书签(因此他以“书签”的原因订阅了帖子提要),我不希望用户收到有关该项目操作的电子邮件通知,而如果他评论帖子(因此它以“评论”的原因订阅帖子提要)我希望在其他用户向同一帖子添加评论时通知他。原因字段有助于我进行这种区分(我通过 ActivityFilter 类实现它),以及用户的通知偏好。

于 2009-11-22T22:28:19.433 回答
16

一群知名人士正在开发一种当前的活动流格式。

http://activitystrea.ms/

基本上,每个活动都有一个参与者(执行该活动)、一个动词(该活动的动作)、一个对象(参与者在其上执行)和一个目标。

例如:Max 发布了指向 Adam's wall 的链接。

在撰写本文时,他们的 JSON 规范已达到 1.0 版,它显示了您可以应用的活动模式。

它们的格式已被 BBC、Gnip、Google Buzz Gowalla、IBM、MySpace、Opera、Socialcast、Superfeedr、TypePad、Windows Live、YIID 和许多其他公司采用。

于 2012-02-14T14:48:46.423 回答
13

我认为关于通知系统如何在大型网站上工作的解释可以在堆栈溢出问题中找到社交网络网站如何计算朋友更新?,在杰里米·沃尔的回答中。他建议使用Message Qeue,并指出了两个实现它的开源软件:

  1. 兔MQ
  2. Apache QPid

另请参阅问题实施社交活动流的最佳方式是什么?

于 2009-09-21T16:41:07.070 回答
1

您绝对需要一个高性能的分布式消息队列。但这并不止于此,您必须决定将哪些存储为持久数据以及哪些存储为瞬态数据等。

无论如何,如果您追求高性能和可扩展的系统,这确实是一项艰巨的任务。但是,当然,一些慷慨的工程师分享了他们在这方面的经验。LinkedIn 最近将其消息队列系统 Kafka 开源。在此之前,Facebook 已经向开源社区提供了 Scribe。Kafka 是用 Scala 编写的,起初它需要一些时间才能运行,但我用几个虚拟服务器进行了测试。它真的很快。

http://blog.linkedin.com/2011/01/11/open-source-linkedin-kafka/

http://incubator.apache.org/kafka/index.html

于 2012-04-05T00:47:22.177 回答
0

您可以查看通过 API 使用的第三方服务,而不是自己滚动。我开始了一个名为 Collabinate ( http://www.collabinate.com ) 的项目,它有一个图形数据库后端和一些相当复杂的算法,用于以高并发、高性能的方式处理大量数据。虽然它没有 Facebook 或 Twitter 那样的广泛功能,但对于大多数需要在应用程序中构建活动流、社交订阅源或微博功能的用例来说,它已经足够了。

于 2013-06-19T02:47:46.707 回答