Conception de base de données Facebook?

133

Je me suis toujours demandé comment Facebook avait conçu la relation utilisateur ami <->.

Je pense que la table des utilisateurs ressemble à ceci:

user_email PK
user_id PK
password 

Je figure le tableau avec les données de l'utilisateur (sexe, âge, etc. connecté via l'email de l'utilisateur, je suppose).

Comment connecte-t-il tous les amis à cet utilisateur?

Quelque chose comme ça?

user_id
friend_id_1
friend_id_2
friend_id_3
friend_id_N 

Probablement pas. Parce que le nombre d'utilisateurs est inconnu et va augmenter.

Marin
la source
13
Il existe une page d'ingénierie Facebook qui contient beaucoup de ce type d'informations, mais pas tout à fait ce que vous demandez. Vous voudrez peut-être y poser la question et voir si vous pouvez obtenir une réponse. facebook.com/FacebookEngineering
John Meagher
1
Google graph database. Ce n'est certainement pas un SGBDR.

Réponses:

90

Gardez une table d'amis qui contient le UserID puis le UserID de l'ami (nous l'appellerons FriendID). Les deux colonnes seraient des clés étrangères de la table Users.

Exemple un peu utile:

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)

Exemple d'utilisation:

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

Cela montrera que Bob est ami avec Jon et Joe et que Jon est également ami avec Joe. Dans cet exemple, nous supposerons que l'amitié est toujours de deux manières, vous n'aurez donc pas besoin d'une ligne dans le tableau comme (2,1) ou (3,2) car elles sont déjà représentées dans l'autre sens. Pour les exemples où l'amitié ou d'autres relations ne sont pas explicitement bidirectionnelles, vous devez également avoir ces lignes pour indiquer la relation bidirectionnelle.

TheTXI
la source
8
pensez à combien cela est inefficace - vous devez faire une requête disjonctive sur les colonnes du plusieurs-à-plusieurs, doublant en moyenne le temps de recherche.
Anthony Bishopric
2
Personnellement, je ne voudrais pas que ces deux champs créent une clé primaire composite. Une clé unique, absolument. L'index clusterisé sur cette clé unique, définitivement. Mais je mettrais également une sorte d'identité non composite en tant que PK avec un index non clusterisé. Cela permettrait à d'autres tables qui ont besoin d'un FK «ID de relation d'ami» de se lier facilement à cette table et divers déclencheurs pourraient déclencher des événements en cascade d'amitié, de défiance, etc.
Jesse C. Slicer
1
On dit que Facebook compte environ 1'000'000'000 utilisateurs. Si l'utilisateur moyen a 100 amis, cela signifie que la table contiendra 100'000'000'000 lignes. Partitionnement MySQL?
veidelis le
Oubliez cette approche. Si vous obtenez un nombre important d'utilisateurs, cela deviendra certainement très lent. Consultez ma réponse et essayez de la comparer vous-même. J'ai fait des analyses comparatives avec 10 000 utilisateurs et 2,5 millions de connexions d'amitié et le résultat a été décevant. Si vous dirigez une petite communauté, cela fonctionnera bien, mais il y a des problèmes de performances à prendre en compte.
burzum
7
vous pouvez être sûr que facebook n'utilise pas de SGBDR pour cela, il est de notoriété publique qu'eux, Twitter et tous ceux qui ont besoin d'exécuter des requêtes comme celle-ci utilisent une base de données de graphes d'une certaine saveur. il y a au moins 69 personnes qui n'ont jamais travaillé à aucune échelle ou qui ne savent pas faire des mathématiques à grande échelle.
51

Jetez un œil au schéma de base de données suivant, conçu par Anatoly Lubarsky :

Schéma Facebook

Brad Larson
la source
7
Ceci est un diagramme de classes, pas un schéma de base de données
Lemon Juice
2
Est-ce que chaque «utilisateur» aurait sa propre base de données dédiée? Comme celui ci-dessus? Comment cela fonctionnerait-il? Par exemple, lorsque l'utilisateur se connecte à FB vérifie s'il s'agit d'un User + Pass valide, puis s'il est valide, Facebook les redirigera vers la base de données qui affiche ensuite tout ce qui provient de la base de données ci-dessus
James111
Ce magasin ne contient que les informations relatives à l'utilisateur, je recherche spécifiquement la publication et son public?
Waseem Ahmad Naeem
47

TL; DR:

Ils utilisent une architecture de pile avec des graphiques en cache pour tout ce qui se trouve au-dessus du bas de MySQL de leur pile.

Longue réponse:

J'ai fait des recherches à ce sujet moi-même parce que j'étais curieux de savoir comment ils gèrent leur énorme quantité de données et les recherchent rapidement. J'ai vu des gens se plaindre de la lenteur des scripts de réseaux sociaux personnalisés lorsque la base d'utilisateurs augmente. Après avoir moi-même effectué des analyses comparatives avec seulement 10 000 utilisateurs et 2,5 millions de connexions d' amis - sans même essayer de me soucier des autorisations de groupe, des likes et des publications sur le mur - il s'est rapidement avéré que cette approche était imparfaite. J'ai donc passé du temps à chercher sur le Web comment le faire mieux et je suis tombé sur cet article officiel de Facebook:

Je vous recommande vraiment de regarder la présentation du premier lien ci-dessus avant de continuer la lecture. C'est probablement la meilleure explication du fonctionnement de FB dans les coulisses que vous puissiez trouver.

La vidéo et l'article vous disent plusieurs choses:

  • Ils utilisent MySQL tout en bas de leur pile
  • Au - dessus de la base de données SQL se trouve la couche TAO qui contient au moins deux niveaux de mise en cache et utilise des graphiques pour décrire les connexions.
  • Je n'ai rien trouvé sur le logiciel / la base de données qu'ils utilisent réellement pour leurs graphiques en cache

Jetons un coup d'œil à ceci, les connexions d'amis sont en haut à gauche:

entrez la description de l'image ici

Eh bien, c'est un graphique. :) Il ne vous dit pas comment le construire en SQL, il y a plusieurs façons de le faire mais ce site a un bon nombre d'approches différentes. Attention: Considérez qu'une base de données relationnelle est ce qu'elle est: on pense qu'elle stocke des données normalisées, pas une structure graphique. Il ne fonctionnera donc pas aussi bien qu'une base de données de graphes spécialisée.

Considérez également que vous devez faire des requêtes plus complexes que de simples amis d'amis, par exemple lorsque vous souhaitez filtrer tous les emplacements autour d'une coordonnée donnée que vous et vos amis d'amis aimez. Un graphique est la solution parfaite ici.

Je ne peux pas vous dire comment le construire pour qu'il fonctionne bien, mais cela nécessite clairement des essais et des erreurs et une analyse comparative.

Voici mon test décevant pour trouver juste des amis d'amis:

Schéma de base de données:

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;

Requête des amis d'amis:

(
        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
    )

Je vous recommande vraiment de créer des exemples de données avec au moins 10k enregistrements d'utilisateurs et chacun d'entre eux ayant au moins 250 connexions d'amis, puis d'exécuter cette requête. Sur ma machine (i7 4770k, SSD, 16 Go de RAM), le résultat était d' environ 0,18 seconde pour cette requête. Peut-être qu'il peut être optimisé, je ne suis pas un génie de la DB (les suggestions sont les bienvenues). Cependant, si cela évolue de manière linéaire, vous êtes déjà à 1,8 seconde pour seulement 100 000 utilisateurs, 18 secondes pour 1 million d'utilisateurs.

Cela peut sembler correct pour ~ 100 000 utilisateurs, mais considérez que vous venez de récupérer des amis d'amis et que vous n'avez pas fait de requête plus complexe comme " affichez-moi uniquement les messages d'amis d'amis d'amis + vérifiez les autorisations si je suis autorisé ou non pour voir certains d'entre eux + faire une sous-requête pour vérifier si je les ai aimés ". Vous voulez laisser la base de données vérifier si vous avez déjà aimé un message ou non ou si vous devrez le faire dans le code. Considérez également que ce n'est pas la seule requête que vous exécutez et que vous avez plus d'utilisateurs actifs en même temps sur un site plus ou moins populaire.

Je pense que ma réponse répond à la question de savoir comment Facebook a très bien conçu sa relation entre amis, mais je suis désolé de ne pas pouvoir vous dire comment la mettre en œuvre de manière à ce qu'elle fonctionne rapidement. La mise en œuvre d'un réseau social est facile mais s'assurer qu'il fonctionne bien n'est clairement pas - à mon humble avis.

J'ai commencé à expérimenter avec OrientDB pour faire les requêtes de graphes et mapper mes bords à la base de données SQL sous-jacente. Si jamais je le fais, j'écrirai un article à ce sujet.

Burzum
la source
alors ... avez-vous déjà eu l'occasion d'écrire l'article?
FlowUI. SimpleUITesting.com
1
Non, je suis assez occupé en plus de faire de la programmation et je n'ai pas eu le temps ni l'humeur de le faire. La réponse ici contient tout ce que vous devez savoir si vous souhaitez implémenter des associations d'amis performantes. Mettez en cache les listes d'amis par utilisateur ou mappez votre base de données relationnelle en parties ou le tout à un graphique et interrogez la base de données du graphique. Vous pouvez utiliser OrientDB ou Neo4j pour cela. J'adorerais écrire mon propre logiciel de réseautage social open source, mais il y a aussi une tonne d'autres choses à faire. Quoi que vous fassiez: faites des benchmarks. :)
burzum
Toujours pas. Mais la documentation OrientDB explique les connexions des amis et tout le reste peut être modélisé une fois que les bases sont comprises. orientdb.com/docs/2.1/Tutorial-Working-with-graphs.html Si vous souhaitez utiliser une base de données relationnelle comme base, il vous suffit d'ajouter du code dans vos rappels "après sauvegarde" et "après suppression" pour mettre à jour votre graphe DB (que vous utiliseriez pour lire des données). Si vous n'avez pas de tels rappels, implémentez-les, mais je suppose que presque tous les types d'implémentations et de frameworks ORM ont quelque chose comme ça. En fait, OrientDB peut également stocker des documents.
burzum
1
alors ... avez-vous déjà eu l'occasion d'écrire l'article?
Connor Gurney
1
Toujours non, mais nous faisons quelque chose de similaire au travail: nous mappons nos données relationnelles à un index Elastic Search, comme je l'ai écrit dans mon commentaire auparavant, il s'agit simplement d'obtenir les données que vous souhaitez stocker dans l'index ou le graphique après une certaine action (callback afterSave () / afterDelete () dans notre cas) puis mise à jour de l'index ou du graphique. Assez simple? :) La même chose pourrait être faite avec les listes d'amis en passant, peu importe si vous les stockez dans ES, un graphique ou un cache basé sur la mémoire (tant que vous avez assez de RAM). Ce n'est vraiment pas difficile, le plus dur est de faire évoluer le tout en grandissant.
burzum
32

Mon meilleur pari est qu'ils ont créé une structure graphique . Les nœuds sont des utilisateurs et les «amitiés» sont des bords.

Gardez une table des utilisateurs, gardez une autre table des arêtes. Ensuite, vous pouvez conserver des données sur les bords, comme "le jour où ils sont devenus amis" et "le statut approuvé", etc.

belgariontheking
la source
40
J'ai le sentiment que vous allez devoir expliquer cela un peu plus pour certaines personnes ici.
TheTXI
4
Je pense qu'une question plus intéressante serait de savoir comment maintenir une structure aussi énorme (nous parlons de 200 millions de nœuds et de milliards d'arêtes) de manière à pouvoir facilement la rechercher et la mettre à jour.
Dirk Vollmar
1
@divo: utilisation intelligente des index et des partitions.
belgariontheking
20

Il s'agit probablement d'une relation plusieurs à plusieurs:

FriendList (tableau)

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

ÉDITER

La table user n'a probablement pas user_email comme PK, peut - être comme clé unique.

utilisateurs (tableau)

user_id PK
user_email
password
Nathan Koop
la source
4
Bien que cela ait certainement le plus de sens, je pense que les performances seraient horribles compte tenu du nombre d'utilisateurs de Facebook et du nombre d'amis de chaque utilisateur de Facebook.
Kevin Pang
17

Jetez un œil à ces articles décrivant comment LinkedIn et Digg sont construits:

Il y a aussi "Big Data: Points de vue de l'équipe Facebook Data" qui pourrait être utile:

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

En outre, il y a cet article qui parle des bases de données non relationnelles et de la façon dont elles sont utilisées par certaines entreprises:

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

Vous verrez que ces entreprises traitent des entrepôts de données, des bases de données partitionnées, de la mise en cache des données et d'autres concepts de plus haut niveau que la plupart d'entre nous ne traitent jamais quotidiennement. Ou du moins, peut-être que nous ne savons pas ce que nous savons.

Il y a beaucoup de liens sur les deux premiers articles qui devraient vous donner un aperçu supplémentaire.

MISE À JOUR 20/10/2014

Murat Demirbas a rédigé un résumé sur

  • TAO: magasin de données distribué de Facebook pour le graphe social (ATC'13)
  • F4: le système de stockage BLOB chaleureux de Facebook (OSDI'14)

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

HTH

Adrian J. Moreno
la source
9

Il n'est pas possible de récupérer les données du SGBDR pour les données des amis utilisateurs pour les données qui traversent plus d'un demi-milliard à un moment constant, Facebook l'a donc implémenté en utilisant une base de données de hachage (pas de SQL) et ils ont ouvert la base de données appelée Cassandra.

Ainsi, chaque utilisateur a sa propre clé et les détails des amis dans une file d'attente; pour savoir comment fonctionne cassandra regardez ceci:

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

user362541
la source
Très intéressant, merci mon ami. Quand sont-ils passés à Cassandra de SQL? Est-ce que vous savez?
Marin
1
Attention: Posters Spaces est mort ... donc le lien.
TechNyquist
5

Vous recherchez des clés étrangères. Fondamentalement, vous ne pouvez pas avoir de tableau dans une base de données à moins qu'il n'ait sa propre table.


Exemple de schéma:

    Table des utilisateurs
        ID utilisateur PK
        autre informations
    Table des amis
        userID - FK à la table des utilisateurs représentant l'utilisateur qui a un ami.
        friendID - FK to Users 'table représentant l'ID utilisateur de l'ami
Malfist
la source
5
Pourquoi les votes négatifs? Au moins, faites savoir à quelqu'un pourquoi vous l'avez rejeté.
Sasha Chedygov
3
@freak: Pourquoi? Tout le concept du vote sur ce site consiste à voter pour être anonyme. Pourquoi pensez-vous que Malfist a droit à quelque chose?
GEOCHET
4
Surtout quand c'est une réponse valide et que les autres réponses font écho (bien que je n'en ai pas copié, quand j'ai répondu, il n'y avait pas de réponses)
Malfist
4
@TheTXI: Je pense que les commentaires sur les votes négatifs sont une courtoisie, en particulier sur les réponses qui ne les méritent manifestement pas, mais je suis également d'accord que les commentaires ne devraient pas être obligatoires.
Robert S.
2
Les personnes qui votent de façon anonyme sur des réponses non évidentes sont celles qui craignent que leur raisonnement superficiel ne soit exposé si elles laissaient un commentaire expliquant un vote défavorable.
Vinayak
1

Gardez à l'esprit que les tables de base de données sont conçues pour croître verticalement (plus de lignes), pas horizontalement (plus de colonnes)

Neil N
la source
24
N'OUBLIE JAMAIS! Mon père est mort à cause d'une table de base de données qui avait poussé trop verticalement pour ses colonnes. Tu vas me manquer papa.
belgariontheking
1
hmm, pourquoi le vote défavorable? Et le commentaire ci-dessus n'a pas de sens.
Neil N
2
Non, le commentaire n'a pas de sens. On dirait que quelqu'un a essayé d'être drôle, alors ne vous inquiétez pas.
Dirk Vollmar
0

En ce qui concerne les performances d'une table plusieurs-à-plusieurs, si vous avez 2 entiers 32 bits reliant les identifiants utilisateur, votre stockage de données de base pour 200 000 000 d'utilisateurs comptant en moyenne 200 amis chacun est un peu moins de 300 Go.

De toute évidence, vous auriez besoin d'un partitionnement et d'une indexation et vous n'allez pas garder cela en mémoire pour tous les utilisateurs.

Cade Roux
la source
0

Il y a probablement une table, qui stocke la relation utilisateur friend <->, par exemple "frnd_list", ayant les champs 'user_id', 'frnd_id'.

Chaque fois qu'un utilisateur ajoute un autre utilisateur comme ami, deux nouvelles lignes sont créées.

Par exemple, supposons que mon identifiant soit 'deep9c' et que j'ajoute un utilisateur ayant l'identifiant 'akash3b' comme ami, puis deux nouvelles lignes sont créées dans la table "frnd_list" avec les valeurs ('deep9c', 'akash3b') et ('akash3b ',' deep9c ').

Maintenant, lors de l'affichage de la liste d'amis à un utilisateur particulier, un simple sql ferait cela: "sélectionnez frnd_id de frnd_list où user_id =" où est l'id de l'utilisateur connecté (stocké comme attribut de session).

deep9c
la source