我正在开发自己的社交网络,但在Web上的实现示例中却找不到用户操作流…例如,如何为每个用户过滤操作?如何存储动作事件?可以将哪些数据模型和对象模型用于操作流及其自身的操作?
我正在开发自己的社交网络,但在Web上的实现示例中却找不到用户操作流…例如,如何为每个用户过滤操作?如何存储动作事件?可以将哪些数据模型和对象模型用于操作流及其自身的操作?
Answers:
摘要:对于大约100万活跃用户和1.5亿存储的活动,我将其简单化:
查询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时,它可能像这样工作:
Redis速度很快,并且提供了一种通过一个连接流水线命令的方法-因此将活动推送给1000个朋友需要花费毫秒的时间。
有关我在说什么的更详细说明,请参阅Redis的Twitter示例:http : //redis.io/topics/twitter-clone
2011年2月更新我目前有5000万活跃活动,但我没有做任何更改。做类似的事情的一件好事是它使用紧凑的小行。我正在计划进行一些更改,这些更改将涉及更多的活动和对这些活动的更多查询,并且我肯定会使用Redis来保持速度。我在其他领域使用Redis,它对于某些类型的问题确实非常有效。
2014年7月更新我们每月有大约70万活跃用户。在过去的几年中,我一直在使用Redis(如项目符号列表中所述)存储每个用户的最后1000个活动ID。系统中通常有大约1亿个活动记录,它们仍然存储在MySQL中,并且布局相同。这些记录使我们可以用更少的Redis内存来逃脱它们,它们充当活动数据的记录,如果用户需要及时返回页面以查找某些内容,则可以使用它们。
这不是一个聪明或特别有趣的解决方案,但它对我很有帮助。
JOIN
在各种activity_type
表上执行?这些会增加性能吗?
activity_type
以获取您需要的其他数据。
这是我使用mysql实现的活动流。共有三类:活动,ActivityFeed,订户。
活动代表活动条目,其表如下所示:
id
subject_id
object_id
type
verb
data
time
Subject_id
是执行操作object_id
的对象的ID,即接收操作的对象的ID。type
并verb
描述操作本身(例如,如果用户在文章中添加评论,则分别为“评论”和“创建”),数据包含其他数据以避免连接(例如,可以包含主题名称)和姓氏,文章标题和网址,评论正文等)。
每个活动都属于一个或多个ActivityFeed,它们之间的关系如下表所示:
feed_name
activity_id
在我的应用程序中,我为每个用户提供一个提要,为每个项目提供一个提要(通常是博客文章),但是它们可以随心所欲。
订阅者通常是您网站的用户,但也可以是您对象模型中的任何对象(例如,文章可以订阅其创建者的feed_action)。
每个订户都属于一个或多个ActivityFeed,并且如上所述,它们由这种链接表关联:
feed_name
subscriber_id
reason
reason
此处的字段说明了订阅者为何订阅源。例如,如果用户为博客帖子添加了书签,则原因是“书签”。这有助于我稍后过滤用于通知用户的操作。
为了检索订户的活动,我对三个表进行了简单的连接。加入的速度很快,因为由于现在的WHERE
状况- 我很少选择活动time > some hours
。由于活动表中的数据字段,我避免了其他联接。
reason
现场进一步解释。例如,如果我要过滤发送给用户的电子邮件通知的操作,并且该用户将该博客帖子添加为书签(因此他以“书签”为原因订阅该帖子供稿),那么我不希望该用户收到电子邮件通知有关该项目的操作,而如果他评论该帖子(因此它以“评论”的原因订阅了该帖子供稿),我希望他在其他用户向同一帖子添加评论时得到通知。原因字段可帮助我进行这种区分(我通过ActivityFilter类实现了它)以及用户的通知首选项。
一群知名人士正在开发一种当前的活动流格式。
基本上,每个活动都有一个演员(执行该活动的演员),一个动词(该活动的动作),一个对象(演员在其上执行活动的对象)和一个目标。
例如:麦克斯(Max)发布了到亚当(Adam)的墙的链接。
在撰写本文时,他们的JSON规范已达到1.0版,其中显示了您可以应用的活动模式。
它们的格式已被BBC,Gnip,Google Buzz Gowalla,IBM,MySpace,Opera,Socialcast,Superfeedr,TypePad,Windows Live,YIID等采用。
我认为可以在堆栈溢出问题中找到有关通知系统如何在大型网站上工作的解释,该问题是社交网站如何计算好友更新?,在Jeremy Wall的回答中。他建议使用Message Qeue,并指出了实现它的两个开源软件:
另请参阅问题 实施社交活动流的最佳方式是什么?
您绝对需要高性能和分布式消息队列。但这还不止于此,您必须决定将什么存储为持久性数据以及将什么存储为瞬态数据等。
无论如何,如果您追求高性能和可扩展的系统,对我的朋友来说,这确实是一项艰巨的任务。但是,当然,一些慷慨的工程师已经分享了他们的经验。LinkedIn最近将其消息队列系统Kafka开源。在此之前,Facebook已经向开源社区提供了Scribe。Kafka是用Scala编写的,起初它需要一些时间才能运行,但是我已经测试了几个虚拟服务器。真的很快。
http://blog.linkedin.com/2011/01/11/open-source-linkedin-kafka/
您可以使用API来使用第三方服务,而不必自己动手做。我创建了一个名为Collabinate(http://www.collabinate.com)的网站,该网站具有图形数据库后端和一些相当复杂的算法,可以以高并发,高性能的方式处理大量数据。尽管它没有Facebook或Twitter那样的功能广度,但对于大多数需要在应用程序中构建活动流,社交源或微博功能的用例而言,它已经足够了。