Дизайн бази даних Facebook?


133

Мені завжди було цікаво, як Facebook створив співвідношення друзів <-> користувачів.

Я вважаю, що таблиця користувачів приблизно така:

user_email PK
user_id PK
password 

Я вважаю таблицю з даними користувачів (стать, вік і т. Д., Пов’язані через електронну пошту користувача, яку я вважаю).

Як він з'єднує всіх друзів з цим користувачем?

Щось на зразок цього?

user_id
friend_id_1
friend_id_2
friend_id_3
friend_id_N 

Напевно, ні. Тому що кількість користувачів невідома і розшириться.


13
Існує сторінка Facebook Engineering, яка містить багато такого типу інформації, але не зовсім того, про що ви запитуєте. Ви можете запитати там і подивитися, чи зможете ви отримати відповідь. facebook.com/FacebookEngineering
John Meagher

1
Google graph database. Це точно не RDBMS.

Відповіді:


90

Зберігайте таблицю друзів, яка містить UserID, а потім UserID друга (ми будемо називати це FriendID). Обидва стовпці будуть зовнішніми ключами назад до таблиці користувачів.

Дещо корисний приклад:

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), оскільки вони вже представлені в іншому напрямку. Для прикладів, коли дружба чи інші стосунки явно не є двосторонніми, вам також потрібно мати ці рядки, щоб вказати на двосторонні стосунки.


8
подумайте, наскільки це неефективно - вам доведеться робити диз'юнктивний запит на стовпцях "багато на багато", в середньому подвоюючи час пошуку.
Єпископ Антоній

2
Особисто я не хотів би, щоб ці два поля складали складний первинний ключ. Унікальний ключ, абсолютно. Кластерний індекс на цьому унікальному ключі, безумовно. Але я також поставив би якусь некомпозитну ідентичність як ПК з некластеризованим індексом. Це дозволило б іншим таблицям, яким потрібен ФК «Ідентифікатор відносин з друзями», легко прив’язатись до цієї таблиці, а різні тригери можуть запускати каскадні події фринджування, відстоювання тощо.
Джессі К. Слікер

1
У ній сказано, що Facebook має близько 1 000 000 000 користувачів. Якщо середній користувач має 100 друзів, це означає, що таблиця міститиме 100'000'000'000 рядків. Розбиття MySQL?
veidelis

Забудьте про такий підхід. Якщо ви отримаєте серйозну кількість користувачів, це, безумовно, стане дуже повільним. Дивіться мою відповідь і спробуйте самостійно її порівняти. Я провів порівняльний аналіз із 10-тисячним користувачам та 2,5 мільйонами дружби, і результат був невтішним. Якщо ви запустили невелику спільноту, вона буде добре працювати, але є проблеми з ефективністю.
бурзум

7
Ви можете бути впевнені, що facebook не використовує для цього RDBMS, загальновідомо, що вони, щебетати та всі інші, для виконання таких запитів, використовують графічну базу даних з деяким смаком. є щонайменше 69 людей, які ніколи не працювали в будь-якому масштабі або не знають, як займатися математикою в масштабах.

51

Подивіться на таку схему баз даних, регенеровану Анатолієм Любарським :

Facebook Схема


7
Це діаграма класів, а не схема бази даних
Лимонний сік

2
То чи буде у кожного "Користувача" своя спеціалізована база даних? Як і вищезгаданий? Як би це працювало? Наприклад, коли користувач увійшов у ФБ, перевіряє, чи це дійсний User + Pass, а потім, якщо це дійсний facebook, перенаправить їх на туди базу даних, яка потім відображатиме все з вищевказаної бази даних
James111,

Цей магазин зберігає лише інформацію, що стосується користувача, я спеціально шукаю Пост та його аудиторію?
Waseem Ahmad Naeem

47

TL; DR:

Вони використовують архітектуру стека з кешованими графіками для всього, що знаходиться внизу MySQL внизу їх стеку.

Довга відповідь:

Я провів кілька досліджень з цього приводу, тому що мені було цікаво, як вони обробляють величезну кількість даних і швидко шукають їх. Я бачив, як люди скаржаться на замовлення сценаріїв соціальних мереж, які стають повільними, коли зростає база користувачів. Після того, як я здійснив порівняльний аналіз із лише 10-тисячними користувачами та 2,5 мільйонами друзів, навіть не намагаючись перейматися груповими дозволами та лайками та повідомленнями на стінах - швидко виявилося, що такий підхід є недоліком. Тому я витратив деякий час на пошук в Інтернеті, як зробити це краще, і натрапив на цю офіційну статтю у Facebook:

Я дуже рекомендую вам переглянути презентацію першого посилання вище, перш ніж продовжувати читати. Це, мабуть, найкраще пояснення того, як ФБ працює за кадром, який ви можете знайти.

Відео та стаття розповідають про декілька речей:

  • Вони використовують MySQL в самому дні їхнього стека
  • Над БД SQL є шар TAO, який містить щонайменше два рівні кешування і використовує графіки для опису з'єднань.
  • Я нічого не міг знайти, яке програмне забезпечення / БД вони фактично використовують для кешованих графіків

Давайте подивимось на це, дружні з'єднання вгорі зліва:

введіть тут опис зображення

Ну, це графік. :) Це не говорить вам про те, як побудувати його в 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
    )

Я дійсно рекомендую створити вам декілька зразкових даних, що містять щонайменше 10 тис. Записів користувачів, і кожен з них має принаймні 250 друзів, а потім запустити цей запит. На моїй машині (i7 4770k, SSD, 16 Гб оперативної пам’яті) результат склав ~ 0,18 секунди для цього запиту. Можливо, це можна оптимізувати, я не геній БД (пропозиції вітаються). Однак якщо ця масштабність лінійна, ви вже за 1,8 секунди для лише 100 тис. Користувачів, 18 секунд - для 1 млн користувачів.

Це все ще може звучати добре для ~ 100k користувачів, але врахуйте, що ви просто зібрали друзів друзів і не зробили жодного складнішого запиту, наприклад " показувати мені лише повідомлення від друзів друзів + робити дозвіл перевірити, чи мені це дозволено чи НЕ дозволено щоб побачити деякі з них + зробити підзапит, щоб перевірити, чи мені сподобався хтось із них ". Ви хочете дозволити БД перевіряти, чи сподобалась вам публікація вже чи ні, або вам доведеться це робити в коді. Також врахуйте, що це не єдиний запит, який ви запускаєте, і що у вас є більш ніж активний користувач одночасно на більш-менш популярному сайті.

Я думаю, що моя відповідь відповідає на питання, як Facebook дуже добре розробив стосунки своїх друзів, але мені шкода, що я не можу сказати, як це реалізувати так, щоб це швидко працювало. Реалізувати соціальну мережу досить просто, але переконатися, що вона працює добре, очевидно, немає - IMHO.

Я почав експериментувати з OrientDB, щоб робити графічні запити та відображати мої краї до базової бази даних SQL. Якщо я коли-небудь закінчу це, я напишу про це статтю.


так .. ви коли-небудь збиралися написати статтю?
FlowUI. SimpleUITesting.com

1
Ні, я досить зайнятий, окрім занять програмою, і не мав часу та настрою на це. Відповідь тут містить усе, що потрібно знати, якщо ви хочете реалізувати асоціації друзів-виконавців. Або кешуйте списки друзів на кожного користувача, або нанесіть на вашу реляційну БД частинами, або все це на графік, і запитайте в БД графіків. Для цього можна використовувати OrientDB або Neo4j. Я хотів би написати власне програмне забезпечення для соціальних мереж з відкритим кодом, але також є багато інших справ. Що б ви не робили: робіть орієнтири. :)
бурзум

Все ще ні. Але документація OrientDB пояснює з'єднання друзів, і все інше можна змоделювати, як тільки основи зрозуміли. orientdb.com/docs/2.1/Tutorial-Working-with-graphs.html Якщо ви хочете використовувати реляційну БД в якості основи , то вам просто потрібно додати код в ваш «після того, як зберегти» і «після» зворотних викликів на видалення , щоб оновити ваш графік БД (який ви б використовували для читання даних). Якщо у вас немає таких зворотних викликів, реалізуйте їх, але, мабуть, майже у всіх реалізаціях та структурах ORM є щось подібне. Насправді OrientDB також може зберігати документи.
бурзум

1
так .. ви коли-небудь збиралися написати статтю?
Коннор Герні

1
Все ще ні, але ми робимо щось подібне на роботі: ми пов'язуємо наші реляційні дані на індекс еластичного пошуку, як я писав у своєму коментарі раніше, просто питання отримання даних, які ви хочете зберегти в індексі чи графіку після певних дій (у нашому випадку зворотний виклик afterSave () / afterDelete ()), а потім оновлення індексу або графіка. Досить просто? :) До речі, те саме можна зробити і зі списками друзів, це не має значення, якщо ви зберігаєте їх у ES, графіку чи кеш-пам'яті на базі пам'яті (доки у вас достатньо оперативної пам’яті). Це насправді не важко, важка частина полягає в тому, щоб зробити весь масштаб, коли ростеш.
бурзум

32

Моя найкраща ставка, що вони створили структуру графіків . Вузли - це користувачі, а "дружба" - це краї.

Зберігайте одну таблицю користувачів, а іншу таблицю ребер. Потім ви можете зберігати дані про краї, наприклад, "день, коли вони стали друзями" та "затверджений статус" тощо.


40
У мене є відчуття, що вам доведеться пояснити це трохи більше для деяких людей тут.
TheTXI

4
Я думаю, що більш цікавим питанням було б, як зберегти таку величезну структуру (ми говоримо про 200 мільйонів вузлів і мільярди ребер) таким чином, щоб її можна було легко шукати та оновлювати.
Дірк Волмар

1
@divo: розумне використання індексів та розділів.
belgariontheking

20

Це, швидше за все, стосунки багато до багатьох:

Список друзів (стіл)

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

EDIT

Таблиця користувачів, ймовірно, не містить user_email як ПК, можливо, як унікальний ключ.

користувачів (таблиця)

user_id PK
user_email
password

4
Хоча це, безумовно, має найбільше сенс, я думаю, що вистава буде жахливою, враховуючи, скільки користувачів має Facebook та скільки друзів має кожен користувач Facebook.
Кевін Панг

17

Погляньте на ці статті, що описують, як побудовані 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

Ви побачите, що ці компанії мають справу зі сховищами даних, розділеними базами даних, кешування даних та іншими концепціями вищого рівня, ніж більшість із нас ніколи не займається щодня. Або принаймні, може, ми не знаємо, що робимо.

На перші дві статті є багато посилань, які мають дати вам більше розуміння.

ОНОВЛЕННЯ 20.10.2014

Мурат Демірбас написав резюме на тему

  • ТАО: Розподілений сховище даних Facebook для соціального графіка (ATC'13)
  • F4: тепла система зберігання BLOB у Facebook (OSDI'14)

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

HTH


9

Неможливо отримати дані з RDBMS для даних друзів користувачів для даних, які перетинають понад півмільярда за постійний час, тому Facebook реалізував це за допомогою хеш-бази даних (без SQL), і вони відкрилиобізна базу даних під назвою Кассандра.

Таким чином, кожен користувач має свій власний ключ та дані про друзів у черзі; щоб знати, як виглядає кассандра на це:

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


Дуже цікаво, дякую друже Коли вони перейшли на кассандру з sql? ти випадково знаєш?
Марін

1
Будьте в курсі: Постерові простори мертві ... тому посилання.
TechNyquist

6

Цей останній пост у червні 2013 року детально пояснює пояснення переходу від баз даних зв’язків до об'єктів з асоціаціями для деяких типів даних.

https://www.facebook.com/notes/facebook-engineering/tao-the-power-of-the-graph/10151525983993920

Більш довгий документ доступний на веб-сторінці https://www.usenix.org/conference/atc13/tao-facebook's-distributed-data-store-social-graph


5

Ви шукаєте іноземні ключі. В основному ви не можете мати масив у базі даних, якщо у нього немає власної таблиці.


Прикладна схема:

    Таблиця користувачів
        userID PK
        інші дані
    Таблиця друзів
        userID - FK для таблиці користувачів, що представляє користувача, у якого є друг.
        friendID - таблиця ФК для користувачів, що представляє ідентифікатор користувача друга

5
Чому голоси? Принаймні, нехай хтось знає, чому ти їх порушив.
Саша Чедигов

3
@freak: Чому? Вся концепція голосування на цьому сайті призначена для анонімного голосування. Чому ви вважаєте, що мальфіст має право на що-небудь?
ГЕОЧЕТ

4
Особливо, коли це правильна відповідь і перегукується з іншими відповідями (хоча я не копіював їх, коли я відповідав, там, де немає відповідей)
Malfist

4
@TheTXI: Я вважаю, що коментарі з низовими голосами - це ввічливість, особливо у відповідях, які очевидно їх не заслуговують, але я також погоджуюся, що коментарі не повинні бути наданими.
Роберт С.

2
Люди, які анонімно звертаються за неочевидними відповідями, - це ті, хто побоюється, що їхні мілководні міркування будуть викриті, якби вони залишили коментар, що пояснював голосування.
Виняк


1

Майте на увазі, що таблиці баз даних призначені для росту вертикально (більше рядків), а не горизонтально (більше стовпців)


24
НІКОЛИ НЕ ЗАБУВАЙ! Мій батько загинув через те, що стіл з надто вертикальним рівнем зростав для своїх стовпців. Я сумую за тобою тато.
белгарйонінг

1
хм, навіщо голоси? І коментар вище цього не має сенсу.
Ніл N

2
Ні, коментар не має сенсу. Здається, хтось намагався бути смішним, тому не заперечуйте.
Дірк Волмар

0

Що стосується продуктивності таблиці "багато на багато", якщо у вас є 2 32-бітні вкладиші, що пов'язують ідентифікатори користувачів, ваше основне сховище даних для 200 000 000 користувачів в середньому по 200 друзів за штуку трохи менше 300 Гб.

Очевидно, що вам знадобиться деякий розподіл та індексація, і ви не збираєтеся зберігати це в пам'яті для всіх користувачів.


0

Ймовірно, є таблиця, в якій зберігаються відносини знайомих <-> користувачів, скажімо, "frnd_list", що мають поля 'user_id', 'frnd_id'.

Щоразу, коли користувач додає іншого користувача як друга, створюються два нові ряди.

Наприклад, припустимо, що мій ідентифікатор 'deep9c', і я додаю користувача, який має ідентифікатор 'akash3b' як свого друга, тоді два нові рядки створюються в таблиці "frnd_list" зі значеннями ('deep9c', 'akash3b') і ('akash3b ',' deep9c ').

Тепер, показуючи список друзів певному користувачеві, звичайний sql зробив би це: "виберіть frnd_id з frnd_list where user_id =" де ідентифікований користувач, який увійшов (зберігається як атрибут сесії).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.