TL;DR:
他们使用带有缓存图的堆栈架构,用于存储堆栈底部 MySQL 之上的所有内容。
长答案:
我自己对此进行了一些研究,因为我很好奇他们如何处理大量数据并快速搜索。我看到人们抱怨当用户群增长时定制的社交网络脚本变得很慢。在我用只有 10k 个用户和 250 万朋友 连接对自己进行了一些基准测试之后 - 甚至没有试图打扰群组权限、喜欢和墙帖 - 很快结果证明这方法有缺陷。所以我花了一些时间在网上搜索如何做得更好,并看到了这篇官方 Facebook 文章:
我真的建议您在继续阅读之前观看上面第一个链接的演示。这可能是您能找到的关于 FB 如何在幕后工作的最佳解释。
视频和文章告诉你一些事情:
- 他们在堆栈的最底部使用 MySQL
-
在 SQL DB 之上有一个 TAO 层,它包含至少两个级别的缓存,并使用图表来描述连接。
- 我找不到任何关于他们实际用于缓存图表的软件/数据库
我们来看看这个,好友关系在左上角:
嗯,这是一个图表。 :) 它没有告诉您如何 在 SQL 中构建它,有几种方法可以做到,但 this site 有很多不同的方法。 注意: 考虑一下关系数据库就是这样:它被认为是存储规范化数据,而不是图形结构。所以它的性能不如专门的图形数据库。
还要考虑到您必须执行比朋友的朋友更复杂的查询,例如,当您想要过滤您和朋友的朋友喜欢的给定坐标周围的所有位置时。图表是这里的完美解决方案。
我无法告诉您如何构建它以使其运行良好,但显然需要一些试验和错误以及基准测试。
这是我对只是发现朋友的朋友的令人失望的测试:
数据库架构:
CREATE TABLE IF NOT EXISTS `friends` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`friend_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
好友好友查询:
(
select friend_id
from friends
where user_id = 1
) union (
select distinct ff.friend_id
from
friends f
join friends ff on ff.user_id = f.friend_id
where f.user_id = 1
)
我真的建议您创建一些示例数据,其中包含至少 10k 个用户记录,并且每个记录至少有 250 个朋友连接,然后运行此查询。在我的机器(i7 4770k、SSD、16gb RAM)上,该查询的结果是 ~0.18 秒。也许可以优化,我不是数据库天才(欢迎提出建议)。但是,如果这是线性比例,对于 10 万用户,您已经是 1.8 秒,对于 100 万用户是 18 秒。
这对于大约 10 万用户来说可能听起来还不错,但考虑到您只是获取朋友的朋友并且没有执行任何更复杂的查询,例如“只显示我朋友的朋友的帖子 + 如果我做权限检查允许或不允许查看其中一些 + 执行子查询以检查我是否喜欢其中任何一个”。您想让数据库检查您是否已经喜欢某个帖子,或者您必须在代码中进行。还要考虑到这不是您运行的唯一查询,并且您在或多或少受欢迎的网站上同时拥有多个活跃用户。
我认为我的回答回答了 Facebook 如何很好地设计他们的朋友关系的问题,但很抱歉,我无法告诉您如何以一种可以快速运行的方式实施它。实施社交网络很容易,但确保其表现良好显然不是 - 恕我直言。
我已经开始尝试使用 OrientDB 来进行图形查询并将我的边映射到底层 SQL DB。如果我完成它,我会写一篇关于它的文章。
如何创建一个性能良好的社交网站?
2021 年 4 月 10 日更新:我可能永远不会写这篇文章;)但这里有一些要点,你可以尝试如何扩展它:
- 使用不同的读写存储库
- 基于为此目的而制造的更快的非关系数据库系统构建特定的读取存储库,不要害怕非规范化数据。写入规范化数据库,但从专用视图读取。
- 使用最终一致性
- 看看 CQRS
- 对于社交网络,基于图的读取存储库可能也是个好主意。
- 将 Redis 用作存储整个序列化数据集的读取存储库
如果您巧妙地结合以上列表中的要点,您可以构建一个非常性能良好的系统。该列表不是“待办事项”列表,您仍然需要理解、思考和熟练使用它! https://microservices.io/ 是一个不错的网站,涵盖了我之前提到的一些主题。
我所做的是存储由聚合生成的事件,并使用项目和处理程序写入上述不同的数据库。很酷的一点是,我可以随时根据需要重新构建我的数据。