如何在社交networking中实现活动stream
我正在开发自己的社交networking,而且我还没有在networking上find实现用户行为stream的例子…例如,如何筛选每个用户的行为? 如何存储行动事件? 哪些数据模型和对象模型可以用于操作stream和操作本身?
总结 :对于大约100万活跃用户和1.5亿个存储活动,我保持简单:
- 使用关系数据库来存储独特的活动(每个活动logging1个/“发生的事情”)使logging尽可能紧凑。 结构,以便您可以通过活动标识或通过使用具有时间限制的一组朋友标识快速获取一批活动。
- 每当创build活动logging时,将活动标识发布到Redis,并将该标识添加到应该看到活动的朋友/订户的每个用户的“活动stream”列表中。
查询Redis以获取任何用户的活动stream,然后根据需要从数据库中获取相关数据。 如果用户需要及时浏览(如果你甚至提供这个),回到查询数据库的时间,
我使用一个普通的旧MySQL表处理大约一千五百万个活动。
它看起来像这样:
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
告诉我activity_type
的types, source_id
告诉我活动相关的logging。 所以如果活动types的意思是“添加最喜欢的”,那么我知道source_id指的是一个最喜欢的logging的ID。
parent_id
/ parent_type
对我的应用程序很有用 – 他们告诉我这个活动与什么有关。 如果一本书被collections了,那么parent_id / parent_type会告诉我这个活动与一个给定主键(id)的book(type)有关,
我索引(user_id, time)
和查询是user_id IN (...friends...) AND time > some-cutoff-point
。 放弃身份证,并select一个不同的聚集索引可能是一个好主意 – 我还没有尝试过。
非常基本的东西,但它工作,很简单,而且随着需求的变化很容易处理。 另外,如果你不使用MySQL,你可能会做更好的索引。
为了更快地访问最近的活动,我一直在尝试使用Redis 。 Redis将所有数据存储在内存中,因此您不能将所有活动都放在那里,但是您可以在网站上存储大部分常用的屏幕。 每个用户最近的100个或类似的东西。 在Redis中,它可能是这样工作的:
- 创build你的MySQL活动logging
- 对于创build活动的用户的每个朋友,将ID推送到Redis中的活动列表中。
- 修剪每个列表到最后的X个项目
Redis速度很快,并提供了一种通过一个连接pipe理命令的方法 – 所以将活动推送到1000个朋友需要几毫秒。
有关我所说的更详细的解释,请参阅Redis的Twitter示例: http : //redis.io/topics/twitter-clone
2011年2月更新我目前有5000万活跃的活动,我没有任何改变。 做类似这样的事情的一个好处是,它使用紧凑的小行。 我正计划进行一些涉及更多活动和更多查询的更改,我一定会使用Redis来保持速度。 我在其他领域使用Redis,对于某些types的问题确实很好。
2014年7月更新我们每月活跃用户数达到约700,000人。 在过去几年中,我一直在使用Redis(如项目符号列表中所述)来存储每个用户的最后1000个活动ID。 系统中通常有大约1亿个活动logging,它们仍然存储在MySQL中,并且仍然是相同的布局。 这些logging使我们能够以较less的Redis记忆逃脱,它们充当活动数据的logging,如果用户需要进一步寻找某些内容,我们会使用它们。
这不是一个聪明或特别有趣的解决scheme,但它已经很好地服务于我。
这是我使用mysql实现的一个活动stream。 有三个类:Activity,ActivityFeed,Subscriber。
活动表示活动条目,其表格如下所示:
id subject_id object_id type verb data time
Subject_id
是执行动作的对象的id, object_id
是接收动作的对象的id。 type
和verb
描述动作本身(例如,如果用户为文章添加评论,他们将分别为“评论”和“创build”),数据包含额外的数据,以避免连接(例如,它可以包含科目名称和姓氏,文章标题和url,评论主体等)。
每个Activity都属于一个或多个ActivityFeeds,并且它们通过如下所示的表格相关联:
feed_name activity_id
在我的应用程序中,每个用户都有一个feed,每个item都有一个feed(通常是博客文章),但是他们可以是任何你想要的。
订阅者通常是您网站的用户,但它也可以是对象模型中的任何对象(例如,文章可以订阅他的创build者的feed_action)。
每个Subscriber都属于一个或多个ActivityFeeds,并且像上面一样,它们通过这种链接表相关联:
feed_name subscriber_id reason
此处的reason
字段解释了订阅者订阅了订阅源的原因。 例如,如果用户为博客post添加书签,原因是“书签”。 这有助于我稍后过滤通知给用户的操作。
为了检索用户的活动,我做了三个表的简单连接。 join是快速的,因为我select几个活动感谢WHERE
条件,看起来像现在time > some hours
。 由于Activity表中的数据字段,我避免了其他联接。
对reason
领域的进一步解释。 例如,如果我想过滤电子邮件通知给用户的操作,并且用户为博客文章添加了书签(因此他订阅了“书签”原因的提要),我不希望用户收到发送有关该项目操作的电子邮件通知,而如果他评论该post(因此它以订阅原因“评论”订阅post),我希望当其他用户向同一post添加评论时通知他。 原因字段帮助我在这种歧视(我通过一个ActivityFilter类实现它),以及用户的通知首选项。
目前有一些知名人士正在开发的活动stream的格式。
基本上,每个活动都有一个演员(执行活动的人),一个动词(活动的动作),一个对象(演员在其上执行)和一个目标。
例如:Max已经发布了一个链接到Adam的墙上。
他们的JSON规范在编写时已达到1.0版本,显示了您可以应用的活动模式。
他们的格式已经被BBC,Gnip,Google Buzz Gowalla,IBM,MySpace,Opera,Socialcast,Superfeedr,TypePad,Windows Live,YIID等等采用。
我认为,关于如何在大型网站上通知系统工作的解释可以在堆栈溢出问题中find, 社交网站如何计算朋友更新? ,在杰里米·沃尔的答案中。 他build议使用Message Qeue ,他指出了两个实现它的开源软件:
- 的RabbitMQ
- Apache QPid
另请参阅问题什么是实施社交活动stream的最佳方式?
你绝对需要一个性能和分布式的消息队列。 但是它并没有结束,你将不得不决定要存储什么样的持久数据,以及什么是暂时的等等。
无论如何,如果你是在一个高性能和可扩展的系统之后,这真的是我的朋友的一个难题。 但是,当然有些慷慨的工程师分享了他们的经验。 LinkedIn最近使其消息队列系统Kafka开源。 在此之前,Facebook已经向开源社区提供了Scribe。 Kafka是用Scala编写的,起初需要一些时间才能运行,但是我用一些虚拟服务器进行了testing。 这真的很快。
http://blog.linkedin.com/2011/01/11/open-source-linkedin-kafka/
您可以通过API使用第三方服务,而不是自行开发。 我创build了一个名为Collabinate( http://www.collabinate.com )的graphics数据库后端和一些相当复杂的algorithm,以高度并发,高性能的方式处理大量数据。 尽pipeFacebook和Twitter没有足够的function,但是在大多数情况下,您需要将活动stream,社交馈送或微博function构build到应用程序中。