Desain basis data Facebook?

133

Saya selalu bertanya-tanya bagaimana Facebook merancang hubungan pengguna teman <->.

Saya pikir tabel pengguna adalah sesuatu seperti ini:

user_email PK
user_id PK
password 

Saya pikir tabel dengan data pengguna (jenis kelamin, usia dll terhubung melalui email pengguna saya akan menganggap).

Bagaimana cara menghubungkan semua teman ke pengguna ini?

Sesuatu seperti ini?

user_id
friend_id_1
friend_id_2
friend_id_3
friend_id_N 

Mungkin tidak. Karena jumlah pengguna tidak diketahui dan akan bertambah.

Marin
sumber
13
Ada halaman Teknik Facebook yang memiliki banyak jenis informasi ini, tetapi tidak cukup dengan apa yang Anda minta. Anda mungkin ingin bertanya di sana dan melihat apakah Anda bisa mendapatkan jawaban. facebook.com/FacebookEngineering
John Meagher
1
Google graph database. Itu pasti bukan RDBMS.

Jawaban:

90

Simpan tabel teman yang memegang UserID dan kemudian UserID dari teman (kami akan menyebutnya FriendID). Kedua kolom akan menjadi kunci asing kembali ke tabel Pengguna.

Contoh yang cukup berguna:

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)

Contoh penggunaan:

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

Ini akan menunjukkan bahwa Bob berteman dengan Jon dan Joe dan bahwa Jon juga berteman dengan Joe. Dalam contoh ini kita akan menganggap bahwa pertemanan selalu dua arah, jadi Anda tidak perlu baris dalam tabel seperti (2,1) atau (3,2) karena pertemanan itu sudah terwakili di arah yang lain. Untuk contoh di mana persahabatan atau hubungan lainnya tidak secara eksplisit dua arah, Anda juga perlu memiliki baris-baris tersebut untuk menunjukkan hubungan dua arah.

TheTXI
sumber
8
pikirkan betapa tidak efisiennya hal ini - Anda harus melakukan kueri terputus-putus pada kolom banyak-ke-banyak, menggandakan waktu pencarian rata-rata.
Anthony Bishopric
2
Secara pribadi, saya tidak ingin kedua bidang membuat kunci primer komposit. Kunci unik, tentu saja. Indeks berkerumun pada kunci unik itu, pasti. Tapi saya juga menempatkan semacam identitas non-komposit sebagai PK dengan indeks nonclustered. Itu akan memungkinkan tabel lain yang memerlukan "ID hubungan pertemanan" FK untuk dengan mudah mengikat ke tabel ini dan berbagai pemicu dapat memicu terjadinya berbagai acara pertemanan, pertemanan, dll.
Jesse C. Slicer
1
Dikatakan bahwa Facebook memiliki sekitar 1'000'000'000 pengguna. Jika rata-rata pengguna memiliki 100 teman, itu artinya tabel tersebut akan berisi 100'000'000'000 baris. Partisi MySQL?
veidelis
Lupakan pendekatan ini. Jika Anda mendapatkan jumlah pengguna yang serius itu pasti akan menjadi sangat lambat. Lihat jawaban saya dan coba tolok ukur sendiri. Saya telah melakukan pembandingan dengan 10 ribu pengguna dan 2,5 juta koneksi pertemanan dan hasilnya mengecewakan. Jika Anda menjalankan komunitas kecil, itu akan berfungsi dengan baik tetapi ada masalah kinerja yang perlu dipertimbangkan.
burzum
7
Anda dapat yakin bahwa facebook tidak menggunakan RDBMS untuk ini, sudah menjadi rahasia umum bahwa mereka, twitter, dan semua orang yang perlu menjalankan query seperti ini menggunakan basis data grafik dengan beberapa rasa. setidaknya ada 69 orang yang tidak pernah bekerja pada skala apa pun atau tidak tahu bagaimana melakukan matematika pada skala.
51

Lihatlah skema database berikut, direkayasa balik oleh Anatoly Lubarsky :

Skema Facebook

Brad Larson
sumber
7
Ini adalah diagram kelas, bukan skema basis data
Lemon Juice
2
Jadi, apakah setiap "Pengguna" memiliki basis data khusus? Seperti yang di atas? Bagaimana cara kerjanya? Misalnya, ketika pengguna log on FB memeriksa untuk melihat apakah itu User + Pass yang valid dan kemudian apakah itu facebook yang sah akan mengarahkan mereka ke database yang ada di sana yang kemudian menampilkan semuanya dari database di atas
James111
Toko ini hanya informasi yang terkait dengan pengguna, saya secara khusus mencari Post dan audiensnya?
Waseem Ahmad Naeem
47

TL; DR:

Mereka menggunakan arsitektur tumpukan dengan grafik yang di-cache untuk semua yang ada di atas bagian bawah tumpukan MySQL mereka.

Jawaban panjang:

Saya melakukan riset sendiri karena saya ingin tahu bagaimana mereka menangani data dalam jumlah besar dan mencarinya dengan cepat. Saya telah melihat orang-orang mengeluh tentang skrip jejaring sosial yang dibuat khusus menjadi lambat ketika basis pengguna bertambah. Setelah saya melakukan benchmark sendiri dengan hanya 10k pengguna dan 2,5 juta koneksi teman - bahkan tidak mencoba untuk peduli tentang izin grup dan suka dan posting dinding - dengan cepat ternyata pendekatan ini cacat. Jadi saya telah menghabiskan waktu mencari di web tentang cara melakukannya dengan lebih baik dan menemukan artikel resmi Facebook ini:

Saya sangat merekomendasikan Anda untuk menonton presentasi tautan pertama di atas sebelum melanjutkan membaca. Itu mungkin penjelasan terbaik tentang cara kerja FB di balik layar yang dapat Anda temukan.

Video dan artikel memberi tahu Anda beberapa hal:

  • Mereka menggunakan MySQL di bagian paling bawah tumpukan mereka
  • Di atas SQL DB ada lapisan TAO yang berisi setidaknya dua level caching dan menggunakan grafik untuk menggambarkan koneksi.
  • Saya tidak dapat menemukan apa pun pada perangkat lunak / DB apa yang sebenarnya mereka gunakan untuk grafik cache mereka

Mari kita lihat ini, koneksi teman di kiri atas:

masukkan deskripsi gambar di sini

Ini adalah grafik. :) Ini tidak memberi tahu Anda bagaimana membangunnya dalam SQL, ada beberapa cara untuk melakukannya tetapi situs ini memiliki sejumlah pendekatan yang berbeda. Perhatian: Pertimbangkan bahwa DB relasional adalah apa adanya: Diperkirakan untuk menyimpan data yang dinormalisasi, bukan struktur grafik. Jadi itu tidak akan berfungsi sebaik basis data grafik khusus.

Juga pertimbangkan bahwa Anda harus melakukan kueri yang lebih kompleks daripada sekadar teman teman, misalnya ketika Anda ingin memfilter semua lokasi di sekitar koordinat yang Anda dan teman teman Anda sukai. Grafik adalah solusi sempurna di sini.

Saya tidak bisa memberi tahu Anda cara membuatnya sehingga kinerjanya baik tetapi jelas membutuhkan beberapa percobaan dan kesalahan serta pembandingan.

Inilah tes mengecewakan saya untuk adil temuan teman teman:

Skema DB:

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;

Pertanyaan Teman dari Friends:

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

Saya benar-benar menyarankan Anda untuk membuat Anda beberapa data sampel dengan setidaknya 10k catatan pengguna dan masing-masing dari mereka memiliki setidaknya 250 koneksi teman dan kemudian jalankan kueri ini. Di mesin saya (i7 4770k, SSD, 16gb RAM) hasilnya adalah ~ 0,18 detik untuk permintaan itu. Mungkin itu bisa dioptimalkan, saya bukan jenius DB (saran dipersilahkan). Namun, jika skala ini linier, Anda sudah berada di 1,8 detik hanya untuk 100 ribu pengguna, 18 detik untuk 1 juta pengguna.

Ini mungkin masih terdengar OK untuk ~ 100k pengguna tetapi pertimbangkan bahwa Anda baru saja menjemput teman teman dan tidak melakukan kueri yang lebih rumit seperti " tampilkan saya hanya posting dari teman teman + lakukan pemeriksaan izin jika saya diizinkan atau TIDAK diizinkan untuk melihat beberapa dari mereka + melakukan sub kueri untuk memeriksa apakah saya menyukai salah satu dari mereka ". Anda ingin membiarkan DB melakukan pemeriksaan apakah Anda sudah menyukai pos atau tidak atau Anda harus melakukannya dalam kode. Juga pertimbangkan bahwa ini bukan satu-satunya kueri yang Anda jalankan dan bahwa Anda memiliki lebih dari pengguna aktif pada saat yang sama di situs yang kurang lebih populer.

Saya pikir jawaban saya menjawab pertanyaan bagaimana Facebook merancang hubungan teman-teman mereka dengan sangat baik, tetapi saya minta maaf karena saya tidak bisa memberi tahu Anda bagaimana menerapkannya dengan cara yang akan bekerja cepat. Menerapkan jaringan sosial itu mudah tetapi memastikan kinerjanya baik jelas tidak - IMHO.

Saya sudah mulai bereksperimen dengan OrientDB untuk melakukan query grafik dan memetakan tepi saya ke SQL DB yang mendasarinya. Jika saya menyelesaikannya, saya akan menulis artikel tentang itu.

burzum
sumber
jadi .. apakah Anda pernah sempat menulis artikel?
FlowUI. SimpleUITesting.com
1
Tidak, saya cukup sibuk selain melakukan pemrograman dan belum punya waktu dan suasana hati untuk melakukannya. Jawabannya di sini berisi semua yang perlu Anda ketahui jika Anda ingin menerapkan asosiasi teman yang berprestasi. Baik cache daftar teman per pengguna atau petakan DB relasional Anda di bagian atau semuanya ke grafik dan permintaan grafik DB. Anda dapat menggunakan OrientDB atau Neo4j untuk itu. Saya ingin menulis perangkat lunak jejaring sosial open source saya sendiri tetapi ada banyak hal lain yang harus dilakukan juga. Apa pun yang Anda lakukan: Lakukan benchmark. :)
burzum
Masih tidak. Tetapi dokumentasi OrientDB menjelaskan koneksi teman dan yang lainnya dapat dimodelkan begitu dasar-dasarnya dipahami. orientdb.com/docs/2.1/Tutorial-Working-with-graphs.html Jika Anda ingin menggunakan DB relasional sebagai dasar maka Anda hanya perlu menambahkan beberapa kode dalam panggilan balik "after save" dan "after delete" Anda untuk memperbarui grafik DB (yang akan Anda gunakan untuk membaca data). Jika Anda tidak memiliki callback seperti mengimplementasikannya tapi saya kira hampir semua jenis implementasi ORM dan kerangka kerja memiliki sesuatu seperti itu. Sebenarnya OrientDB dapat menyimpan dokumen juga.
burzum
1
jadi .. apakah Anda pernah sempat menulis artikel?
Connor Gurney
1
Masih tidak ada tetapi kami melakukan sesuatu yang serupa di tempat kerja: Kami memetakan data relasional kami ke indeks Pencarian Elastis, seperti yang saya tulis dalam komentar saya sebelumnya, itu hanya masalah mendapatkan data yang ingin Anda simpan dalam indeks atau grafik setelah tindakan tertentu (panggilan balik afterSave () / afterDelete () dalam kasus kami) dan kemudian memperbarui indeks atau grafik. Cukup mudah? :) Hal yang sama dapat dilakukan dengan daftar teman, tidak masalah jika Anda menyimpannya dalam ES, grafik atau cache berbasis memori (selama Anda memiliki cukup RAM). Ini benar-benar tidak sulit, bagian yang sulit adalah membuat skala semuanya ketika Anda tumbuh.
burzum
32

Taruhan terbaik saya adalah mereka membuat struktur grafik . Node adalah pengguna dan "persahabatan" adalah ujung.

Simpan satu tabel pengguna, simpan tabel tepi lainnya. Kemudian Anda dapat menyimpan data tentang tepinya, seperti "hari mereka menjadi teman" dan "status yang disetujui," dll.

belgariontheking
sumber
40
Saya punya perasaan Anda harus menjelaskan itu sedikit lebih untuk beberapa orang di sini.
TheTXI
4
Saya pikir pertanyaan yang lebih menarik adalah bagaimana bertahan struktur yang sangat besar (kita berbicara tentang 200 juta node dan milyaran tepi) dengan cara yang dapat dengan mudah dicari dan diperbarui.
Dirk Vollmar
1
@divo: penggunaan indeks dan partisi secara cerdas.
belgariontheking
20

Kemungkinan besar hubungan banyak ke banyak:

Daftar Teman (tabel)

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

EDIT

Tabel pengguna mungkin tidak memiliki user_email sebagai PK, mungkin sebagai kunci unik.

pengguna (tabel)

user_id PK
user_email
password
Nathan Koop
sumber
4
Meskipun ini tentu yang paling masuk akal, saya pikir kinerjanya akan mengerikan mengingat berapa banyak pengguna yang dimiliki Facebook dan berapa banyak teman yang dimiliki setiap pengguna Facebook.
Kevin Pang
17

Lihatlah artikel-artikel ini yang menjelaskan bagaimana LinkedIn dan Digg dibangun:

Ada juga "Data Besar: Sudut Pandang dari Tim Data Facebook" yang mungkin membantu:

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

Juga, ada artikel ini yang membahas tentang database non-relasional dan bagaimana mereka digunakan oleh beberapa perusahaan:

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

Anda akan melihat bahwa perusahaan-perusahaan ini berurusan dengan gudang data, basis data yang dipartisi, penyimpanan data dan konsep tingkat tinggi lainnya daripada kebanyakan dari kita tidak pernah berurusan dengan setiap hari. Atau setidaknya, mungkin kita tidak tahu bahwa kita tahu.

Ada banyak tautan pada dua artikel pertama yang seharusnya memberi Anda lebih banyak wawasan.

UPDATE 10/20/2014

Murat Demirbas menulis ringkasan tentang

  • TAO: Menyimpan data terdistribusi Facebook untuk grafik sosial (ATC'13)
  • F4: Sistem penyimpanan BLOB hangat Facebook (OSDI'14)

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

HTH

Adrian J. Moreno
sumber
9

Tidak mungkin untuk mengambil data dari RDBMS untuk data teman-teman pengguna untuk data yang melintasi lebih dari setengah miliar pada waktu yang konstan sehingga Facebook menerapkan ini menggunakan database hash (tidak ada SQL) dan mereka membuka database yang disebut Cassandra.

Jadi setiap pengguna memiliki kunci sendiri dan rincian teman dalam antrian; untuk mengetahui cara kerja cassandra lihat ini:

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

pengguna362541
sumber
Sangat menarik, terima kasih temanku. Kapan mereka beralih ke cassandra dari sql? apakah kamu tahu
Marin
1
Waspada: Ruang Posterous sudah mati ... jadi tautannya.
TechNyquist
5

Anda sedang mencari kunci asing. Pada dasarnya Anda tidak dapat memiliki array dalam database kecuali memiliki tabel sendiri.


Contoh skema:

    Tabel Pengguna
        userID PK
        data yang lain
    Meja Teman
        userID - FK ke tabel pengguna yang mewakili pengguna yang memiliki teman.
        friendID - FK ke tabel Users yang mewakili id ​​pengguna dari teman tersebut
Malfist
sumber
5
Mengapa downvotes? Setidaknya beri tahu seseorang mengapa Anda menurunkannya.
Sasha Chedygov
3
@freak: Kenapa? Seluruh konsep pemungutan suara di situs ini adalah untuk pemungutan suara menjadi anonim. Mengapa Anda merasa malfist berhak atas apa saja?
GEOCHET
4
Terutama ketika itu adalah jawaban yang valid dan digemakan oleh jawaban lain (walaupun saya tidak menyalinnya, ketika saya menjawab, tidak ada jawaban)
Malfist
4
@TheTXI: Saya pikir komentar tentang downvotes adalah sopan santun, terutama pada jawaban yang jelas tidak layak untuk mereka, tetapi saya juga setuju bahwa komentar tidak boleh diamanatkan.
Robert S.
2
Orang yang downvote secara anonim pada jawaban yang tidak jelas adalah mereka yang takut bahwa alasan dangkal mereka akan terungkap jika mereka meninggalkan komentar yang menjelaskan downvote.
Vinayak
1

Perlu diingat bahwa tabel database dirancang untuk tumbuh secara vertikal (lebih banyak baris), bukan horizontal (lebih banyak kolom)

Neil N
sumber
24
TIDAK PERNAH LUPA! Ayah saya meninggal karena meja db yang tumbuh terlalu jauh secara vertikal untuk kolomnya. Aku akan merindukanmu, Ayah.
belgariontheking
1
hmm, mengapa downvote? Dan komentar di atas yang satu ini tidak masuk akal.
Neil N
2
Tidak, komentar itu tidak masuk akal. Sepertinya seseorang mencoba menjadi lucu, jadi jangan pedulikan.
Dirk Vollmar
0

Mengenai kinerja tabel banyak-ke-banyak, jika Anda memiliki 2 int 32-bit yang menghubungkan ID pengguna, penyimpanan data dasar Anda untuk 200.000.000 pengguna dengan rata-rata 200 teman masing-masing hanya di bawah 300GB.

Jelas, Anda akan membutuhkan beberapa partisi dan pengindeksan dan Anda tidak akan menyimpannya di memori untuk semua pengguna.

Cade Roux
sumber
0

Mungkin ada tabel, yang menyimpan hubungan pengguna teman <->, katakan "frnd_list", yang memiliki bidang 'user_id', 'frnd_id'.

Setiap kali pengguna menambahkan pengguna lain sebagai teman, dua baris baru dibuat.

Misalnya, id saya adalah 'deep9c' dan saya menambahkan pengguna yang memiliki id 'akash3b' sebagai teman saya, maka dua baris baru dibuat di tabel "frnd_list" dengan nilai ('deep9c', 'akash3b') dan ('akash3b' ',' deep9c ').

Sekarang ketika menampilkan daftar teman ke pengguna tertentu, sql sederhana akan melakukan itu: "pilih frnd_id dari frnd_list di mana user_id =" di mana id dari pengguna yang masuk (disimpan sebagai atribut sesi).

deep9c
sumber