Facebook 数据库设计?

我一直想知道 Facebook 是如何设计好友关系的。

我想用户表是这样的:

user_email PK
user_id PK
password

我用用户的数据(性别,年龄等通过用户的电子邮件连接,我假设表)。

它如何将所有的朋友连接到这个用户?

像这样吗?

user_id
friend_id_1
friend_id_2
friend_id_3
friend_id_N

可能不会,因为用户的数量是未知的,而且还会增加。

204685 次浏览

这很可能是一种多对多的关系:

FriendList (表)

user_id -> users.user_id
friend_id -> users.user_id
friendVisibilityLevel

剪辑

User 表可能没有 user _ email 作为 PK,而 有可能作为唯一键。

用户(表)

user_id PK
user_email
password

保留一个朋友表,其中包含朋友的 UserID 和 UserID (我们称之为 FriendID)。这两列都是回到 Users 表的外键。

一个有用的例子:

Table Name: User
Columns:
UserID PK
EmailAddress
Password
Gender
DOB
Location


TableName: Friends
Columns:
UserID PK FK
FriendID PK FK
(This table features a composite primary key made up of the two foreign
keys, both pointing back to the user table. One ID will point to the
logged in user, the other ID will point to the individual friend
of that user)

示例用法:

Table User
--------------
UserID EmailAddress Password Gender DOB      Location
------------------------------------------------------
1      bob@bob.com  bobbie   M      1/1/2009 New York City
2      jon@jon.com  jonathan M      2/2/2008 Los Angeles
3      joe@joe.com  joseph   M      1/2/2007 Pittsburgh


Table Friends
---------------
UserID FriendID
----------------
1      2
1      3
2      3

这将表明鲍勃与乔和乔都是朋友,乔也是乔的朋友。在这个例子中,我们假设友谊总是两种方式,所以您不需要表中的一行,比如(2,1)或(3,2) ,因为它们已经在另一个方向上表示了。对于友谊或其他关系不是明确的双向关系的示例,您还需要使用这些行来指示双向关系。

我最好的猜测是他们创建了一个 图形结构图形结构。节点是用户,“友谊”是边缘。

保持一个用户表,保持另一个表的边缘。然后你可以保留关于边缘的数据,比如“他们成为朋友的那天”和“认可状态”等等。

您正在寻找外键。基本上,数据库中不能有数组,除非它有自己的表。


示例模式:

Users Table
userID PK
other data
Friends Table
userID   -- FK to users's table representing the user that has a friend.
friendID -- FK to Users' table representing the user id of the friend

看看这些描述如何构建 LinkedIn 和 Digg 的文章:

还有“大数据: 来自 Facebook 数据团队的观点”可能会有所帮助:

Http://developer.yahoo.net/blogs/theater/archives/2008/01/nextyahoonet_big_data_viewpoints_from_the_fac.html

此外,还有一篇文章讨论了非关系数据库以及一些公司如何使用它们:

Http://www.readwriteweb.com/archives/is_the_relational_database_doomed.php

您将看到,这些公司正在处理数据仓库、分区数据库、数据缓存和其他更高层次的概念,这些概念是我们大多数人在日常生活中从未涉及过的。或者至少,我们不知道我们知道。

在前两篇文章中有很多链接,它们应该会给你更多的见解。

更新日期: 2014年10月20日

Murat Demirbas 写了一篇关于

  • TAO: Facebook 的社交图表分散式档案系统(ATC’13)
  • F4: Facebook 的暖 BLOB 存储系统(OSDI’14)

Http://muratbuffalo.blogspot.com/2014/10/facebooks-software-architecture.html

高温

关于多对多表的性能,如果有2个32位 int 链接用户 ID,那么对于平均每个200个好友的200,000个用户,基本数据存储量将低于300GB。

显然,您需要一些分区和索引,并且您不会为所有用户将其保留在内存中。

看一下下面的数据库模式 由 Anatoly Lubarsky 逆向工程:

Facebook Schema

从 RDBMS 中检索用户好友数据的数据是不可能的,因为这些数据在一个固定的时间跨越了5亿 所以 Facebook 使用了一个散列数据库(没有 SQL)来实现这一点,他们开放了一个名为 Cassandra 的数据库。

因此,每个用户都有自己的密钥,好友的详细信息在一个队列中; 要知道 Cassandra 是如何工作的,看看这个:

Http://prasath.posterous.com/cassandra-55

它是一种图形数据库: Http://components.neo4j.org/neo4j-examples/1.2-snapshot/social-network.html

它与关系数据库无关。

谷歌图形数据库。

可能存在一个表,它存储好友 <-> 用户关系,比如“ frnd _ list”,其中有字段‘ user _ id’、‘ frnd _ id’。

每当一个用户将另一个用户添加为好友时,就会创建两个新行。

例如,假设我的 id 是“ deep 9c”,并且我添加了一个 id 为“ akash3b”的用户作为我的朋友,然后在表“ frnd _ list”中创建两个新行,它们的值分别是(‘ deep 9c’,‘ akash3b’)和(‘ akash3b’,‘ deep 9c’)。

现在,当向特定用户显示好友列表时,一个简单的 sql 将执行以下操作: “ select frnd _ id from frnd _ list where user _ id =” 其中是登录用户的 id (存储为会话属性)。

译者:

他们使用一个包含缓存图的堆栈架构来处理堆栈底部 MySQL 以上的所有内容。

答案很长:

我自己对此做了一些研究,因为我很好奇他们是如何处理海量数据并快速搜索的。我见过人们抱怨自定义的社交网络脚本在用户基数增长时变慢。在我对自己与 只要一万用户和 250万的朋友连接进行了一些基准测试之后——甚至没有试图关心组权限、喜欢和墙上的帖子——很快就发现这种方法是有缺陷的。因此,我花了一些时间在网上搜索如何做得更好,并偶然发现了这篇 Facebook 官方文章:

真的建议您在继续阅读之前先观看上面第一个链接的演示。这可能是你能找到的关于 FB 如何在幕后工作的最好的解释。

视频和文章告诉你一些事情:

  • 他们在栈的 底部处使用 MySQL
  • 上面的 SQL DB 有一个 TAO 层,它至少包含两个缓存级别,并且使用图形来描述连接。
  • 我找不到任何关于他们实际使用什么软件/数据库缓存图表

让我们看看这个,朋友关系在左上角:

enter image description here

这是个图表。:)它没有告诉你 怎么做在 SQL 中构建它,有几种方法可以做到这一点,但是 这个网站有很多不同的方法。注意:考虑到关系数据库的本质: 它被认为是存储规范化数据,而不是图形结构。所以它的性能不如专门的图形数据库。

还要考虑到您必须执行比仅仅朋友的朋友更复杂的查询,例如,当您希望过滤您和朋友的朋友喜欢的给定坐标周围的所有位置时。图形是这里的完美解决方案。

我不能告诉您如何构建它,以便它能够很好地执行,但是它显然需要一些试验和错误以及基准测试。

以下是我对 只是令人失望测试结果: 朋友的朋友:

数据库模式:

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个朋友连接,然后运行此查询。在我的机器(i74770k,SSD,16gb RAM)上,该查询的结果是 0.18秒。也许它可以被优化,我不是一个 DB 天才(建议是受欢迎的)。但是,对于10万用户来说,如果的线性缩放时间已经是1.8秒,对于100万用户来说是18秒。

对于大约10万用户来说,这听起来还可以,但是考虑到你只是获取了朋友的朋友,并没有做任何更复杂的查询,比如“ 只显示来自朋友的朋友的帖子 + 做权限检查,如果我被允许或不允许看到他们中的一些 + 做一个子查询,以检查是否我喜欢他们中的任何一个”。你想让数据库做的检查,如果你喜欢一个职位已经或没有或你将不得不做的代码。还要考虑到这不是您运行的唯一查询,并且您在一个或多或少受欢迎的站点上同时拥有多于活动用户。

我认为我的回答回答了 Facebook 是如何设计好他们的朋友关系的问题,但是我很抱歉我不能告诉你如何实现它,它将工作得很快。实现一个社交网络是容易的,但是确保它表现良好显然不是——恕我直言。

我已经开始尝试使用 OrientDB 进行图形查询,并将我的边映射到底层的 SQL DB。如果我能完成它,我会写一篇关于它的文章。

我怎样才能创建一个表现良好的社交网站?

更新2021-04-10 : 我可能永远不会写这篇文章;)但是这里有一些你可以尝试扩展它的要点:

  • 使用不同的读写存储库
  • 基于更快的非关系数据库系统构建特定的读取存储库,不要害怕反规范化数据。写入规范化数据库,但从特殊视图读取。
  • 使用最终的一致性
  • 看看 CQRS
  • 对于基于社交网络图表的读取存储库可能也是一个好主意。
  • 将 Redis 用作存储整个序列化数据集的读存储库

如果你以一种聪明的方式将上面列表中的要点组合起来,你就可以构建一个性能良好的 非常系统。这个清单不是一个“待办事项”清单,你仍然需要去理解,去思考,去适应它!https://microservices.io/是一个很好的网站,它涵盖了我之前提到的一些主题。

我所做的是存储由聚合生成的事件,并使用项目和处理程序向上面提到的不同 DBs 写入内容。这样做的好处是,我可以在任何时候根据需要重新构建我的数据。