Facebook或Twitter是如何实现他们的订阅系统的

时间:2015-05-20 04:38:25

标签: mysql social-networking

我正在开发一个类似移动应用程序项目的SNS,用户可以上传其内容,并可以在其主页上查看订阅主题或朋友的更新。

我将用户内容存储在mysql中,并通过简单地查询用户订阅的用户和用户来查询用户特定的主页数据,然后使用' where userid IN(.... )或主题IN(....)'子句。

我怀疑当内容表堆积或用户订阅大量用户或主题时,这会变得非常慢。我们新发布的应用程序已经开始每周有数千名新用户,并且随着时间的推移越来越多。可扩展性现在必须成为我们关注的问题。

所以我想知道Facebook或Twitter如何用他们惊人的用户数来处理这个订阅问题。他们是否为每个用户处理一个列表?我试图搜索,但我得到的只是如何与Facebook或Twitter进行交互,而不是他们如何实际实现此功能。

我注意到在使用Facebook时,您只会在Feed中看到更新而非历史记录。这意味着订阅新用户不会通过使用我当前的方法将多余的内容转储到您的Feed中。

Facebook如何设计数据库以及如何向订阅用户发送新内容?

我的后端目前是PHP + MySQL,我不介意介绍Redis或JMS等其他后端技术以及其应有的方式。

1 个答案:

答案 0 :(得分:2)

听起来你们还处于相当早期阶段。有多种方法可以解决这个问题,这取决于您认为近期会遇到的DAU阶段,您需要花多少钱在硬件上,花在构建它上面的时间等等。 / p>

您可以尝试一个临时表,对新引入的项目进行排队,其元数据包含哪些内容(哪个主题,朋友user_id列表等)。然后使用像RabbitMQ / GearMan这样的队列消费者系统来管理这个不断增长的列表的消费,并找出谁应该处理它。在Scala或像Maven / Tomcat这样的J2EE系统中构建队列使用者程序,这可以持续存在。如果你真的想坚持使用PHP,可以构建一个PHP REST API,它可以存在于php5-fpm的内存中,由FastCGI进程管理器管理,并通过像nginx这样的代理调用,由curl调用以适当的时间间隔从执行的cron执行脚本。

[编辑] - 最好不要将数据库用于排队系统,使用像Redis这样的缓存服务器,它在很多方面都优于数据库,并且可以持久存储到磁盘(查找RDB和AOF)。如果作业突然失败,它不是非常容错的,你可能会丢失一份工作记录。很可能你不会关心这些崩溃边缘情况。还查找php-resque!

为了准备让SNS高效出门,我假设你已经对表格进行了规范化。我想象一个“user_topic”表,主题映射到订阅它们的用户。创建另一个表“notification_metadata”,描述用户更喜欢接收通知的位置(短信/推送/电子邮件/应用内通知),以及推送到这些渠道所需的元数据(APNS / GCM的移动客户端批准密钥,电子邮件地址,用户) AUTH-令牌)。对notification_metadata中的两个字段使用JSON blob,因此每个用户都有一行。这样可以节省数据库上的I / O命中。

使用user_id作为“notification_meta”的主键,将user_id + topic_id用作“user_topic”的PK。不要为其中任何一个添加自动增量“id”字段,在这个用例中占用空间(占用空间,CPU,索引内存等)。如果两个字段都在PK中,则user_topic上的查询将全部来自内存,并且在JOIN期间唯一的磁盘命中是“notification_meta”。

因此,如果用户订阅了2个主题,则“user_topic”中将有两个条目,并且每个用户在“notification_meta”中始终只有一行

还有更多的扩展方法,例如为每个新主题动态创建一个新表,基于user_id分割到不同的MySQL实例,分区等。有N种扩展方式,特别是在MySQL中。祝你好运!