Facebook veritabanı tasarımı?


133

Facebook'un arkadaş <-> kullanıcı ilişkisini nasıl tasarladığını hep merak etmişimdir.

Kullanıcı tablosunun şöyle bir şey olduğunu anladım:

user_email PK
user_id PK
password 

Tabloyu kullanıcı verilerinin (cinsiyet, yaş vb. Kullanıcı e-postası yoluyla bağlı olduğunu varsayıyorum) buluyorum.

Tüm arkadaşları bu kullanıcıya nasıl bağlar?

Bunun gibi bir şey mi?

user_id
friend_id_1
friend_id_2
friend_id_3
friend_id_N 

Muhtemelen değil. Çünkü kullanıcı sayısı bilinmiyor ve artacak.


13
Bu türden pek çok bilgiye sahip olan, ancak tam olarak istediğiniz şeyi olmayan bir Facebook Mühendislik sayfası var. Orada sorup bir cevap alıp alamayacağınıza bakmak isteyebilirsiniz. facebook.com/FacebookEngineering
John Meagher

1
Google graph database. Kesinlikle bir RDBMS değil .

Yanıtlar:


90

Kullanıcı Kimliğini ve ardından arkadaşın Kullanıcı Kimliğini tutan bir arkadaş tablosu tutun (biz buna FriendID adını vereceğiz). Her iki sütun da Kullanıcılar tablosunun yabancı anahtarları olacaktır.

Biraz faydalı örnek:

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)

Örnek Kullanım:

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

Bu, Bob'un hem Jon hem de Joe ile arkadaş olduğunu ve Jon'un da Joe ile arkadaş olduğunu gösterecektir. Bu örnekte arkadaşlığın her zaman iki yol olduğunu varsayacağız, bu nedenle tabloda (2,1) veya (3,2) gibi bir satıra ihtiyacınız olmayacak çünkü bunlar zaten diğer yönde temsil ediliyor. Arkadaşlığın veya diğer ilişkilerin açıkça iki yönlü olmadığı örnekler için, iki yönlü ilişkiyi belirtmek için bu satırlara da sahip olmanız gerekir.


8
bunun ne kadar verimsiz olduğunu bir düşünün - çoktan çoğa sütunlarında ayırıcı bir sorgu yapmanız ve arama süresini ortalama iki katına çıkarmanız gerekir.
Anthony Bishopric

2
Şahsen, bu iki alanın bileşik bir birincil anahtar yapmasını istemem. Kesinlikle benzersiz bir anahtar. Kesinlikle, bu benzersiz anahtardaki kümelenmiş dizin. Ama aynı zamanda kümelenmemiş indeksi olan PK olarak bir çeşit bileşik olmayan kimlik koydum. Bu, bir "arkadaş ilişkisi kimliği" FK'sine ihtiyaç duyan diğer tabloların bu tabloya kolayca bağlanmasına izin verir ve çeşitli tetikleyiciler, arkadaşlık, arkadaşlık bozma, vb. Olayları kademeli olarak tetikleyebilir.
Jesse C. Slicer

1
Facebook'un yaklaşık 1'000'000'000 kullanıcısı olduğu söyleniyor. Ortalama bir kullanıcının 100 arkadaşı varsa, bu masa 100'000'000'000 satır içereceği anlamına gelir. MySQL bölümleme?
veidelis

Bu yaklaşımı unutun. Ciddi miktarda kullanıcı alırsanız, kesinlikle çok yavaşlayacaktır. Cevabımı görün ve kendiniz kıyaslamayı deneyin. 10.000 kullanıcı ve 2.5 milyon arkadaşlık bağlantısı ile bazı kıyaslamalar yaptım ve sonuç hayal kırıklığı yarattı. Küçük bir topluluğu yönetirseniz, iyi çalışır ancak dikkate alınması gereken performans sorunları vardır.
burzum

7
facebook'un bunun için bir RDBMS kullanmadığından emin olabilirsiniz, onlar, twitter ve bunun gibi sorguları çalıştırması gereken diğer herkesin bir çeşit grafik veritabanı kullandığı genel bir bilgidir. hiç herhangi bir ölçekte çalışmamış ya da büyük ölçekte matematik yapmayı bilmeyen en az 69 kişi var.

51

Anatoly Lubarsky tarafından tersine mühendislik uygulanan aşağıdaki veritabanı şemasına bir göz atın :

Facebook Şeması


7
Bu bir sınıf diyagramı, bir veritabanı şeması değil
Lemon Juice

2
Öyleyse her "Kullanıcının" kendine özel bir veritabanı olur mu? Yukarıdaki gibi mi? Nasıl çalışır? Örneğin, kullanıcı FB'de oturum açtığında, bunun geçerli bir Kullanıcı + Geçiş olup olmadığını kontrol eder ve sonra geçerliyse, Facebook onları daha sonra yukarıdaki veritabanından her şeyi görüntüleyen veritabanına yönlendirir
James111

Bu Mağaza yalnızca kullanıcıyla ilgili bilgileri, özellikle Gönderiyi ve hedef kitlesini mi arıyorsunuz?
Waseem Ahmad Naeem

47

TL; DR:

Yığının altındaki MySQL'in üstündeki her şey için önbelleğe alınmış grafiklere sahip bir yığın mimarisi kullanırlar.

Uzun cevap:

Bu konuda kendim biraz araştırma yaptım çünkü büyük miktarda veriyi nasıl işlediklerini ve hızlı bir şekilde nasıl aradıklarını merak ediyordum. Kullanıcı tabanı büyüdükçe özel hazırlanmış sosyal ağ betiklerinin yavaşladığından şikayet eden insanlar gördüm. Sadece 10.000 kullanıcı ve 2,5 milyon arkadaş bağlantısıyla kendimi bir miktar kıyaslama yaptıktan sonra - grup izinleri, beğenileri ve duvar gönderileri hakkında endişelenmeye bile çalışmadan - bu yaklaşımın kusurlu olduğu hemen ortaya çıktı. Bu yüzden, nasıl daha iyi yapılacağına dair internette biraz araştırma yaptım ve şu resmi Facebook makalesine rastladım:

Ben gerçekten önce okumaya devam yukarıdaki ilk bağlantının sunumunu izlemek için tavsiye ederiz. FB'nin bulabileceğiniz perde arkasında nasıl çalıştığına dair muhtemelen en iyi açıklama budur.

Video ve makale size birkaç şey anlatıyor:

  • Yığının en altında MySQL kullanıyorlar
  • Yukarıda DB SQL önbelleğe alma en az iki düzeylerini içerir ve bağlantıları tanımlamak için grafikler kullanan Tao tabakası vardır.
  • Önbelleğe alınmış grafikleri için gerçekte hangi yazılımı / DB'yi kullandıkları hakkında hiçbir şey bulamadım

Şuna bir bakalım, arkadaş bağlantıları sol üstte:

görüntü açıklamasını buraya girin

Bu bir grafik. :) Size SQL'de nasıl inşa edileceğini anlatmıyor , bunu yapmanın birkaç yolu var ama bu site pek çok farklı yaklaşıma sahip. Dikkat: İlişkisel bir DB'nin ne olduğunu düşünün: Bir grafik yapısı değil, normalleştirilmiş verileri depoladığı düşünülmektedir. Bu nedenle, özel bir grafik veritabanı kadar iyi performans göstermez.

Ayrıca, arkadaşlarınızın arkadaşlarından daha karmaşık sorgular yapmanız gerektiğini de göz önünde bulundurun, örneğin, belirli bir koordinat çevresindeki tüm konumları sizin ve arkadaşlarınızın beğendiği tüm konumları filtrelemek istediğinizde. Burada bir grafik mükemmel çözümdür.

İyi performans göstermesi için nasıl inşa edileceğini size söyleyemem ama açıkça biraz deneme yanılma ve kıyaslama gerektiriyor.

İşte sadece arkadaşların arkadaşları için hayal kırıklığı yaratan testim :

DB Şeması:

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;

Friends of Friends Sorgusu:

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

En az 10 bin kullanıcı kaydı olan ve her birinin en az 250 arkadaş bağlantısı olan bazı örnek veriler oluşturmanızı ve ardından bu sorguyu çalıştırmanızı gerçekten tavsiye ederim. Makinemde (i7 4770k, SSD, 16gb RAM) sonuç bu sorgu için ~ 0.18 saniyeydi . Belki optimize edilebilir, ben bir DB dehası değilim (önerilere açığız). Ancak, eğer bu ölçekler doğrusal sadece 100k kullanıcıları, 1.000.000 kullanıcıları için 18 saniye boyunca 1.8 saniyeye zaten.

Bu, ~ 100.000 kullanıcı için yine de kulağa hoş geliyor olabilir, ancak arkadaşlarının arkadaşlarını yeni getirdiğini ve " bana yalnızca arkadaşların arkadaşlarından gelen gönderileri göster + izin ver izin ver, izin verilmediğini kontrol et bazılarını görmek için + alt sorgu yaparak bunlardan herhangi birini beğenip beğenmediğimi kontrol edin ". Bir gönderiyi beğenip beğenmediğinizi DB'nin kontrolü yapmasına izin vermek istersiniz, yoksa kod içinde yapmanız gerekir. Ayrıca bunun çalıştırdığınız tek sorgu olmadığını ve aynı anda az ya da çok popüler bir sitede birden fazla aktif kullanıcınız olduğunu unutmayın.

Cevabımın Facebook'un arkadaş ilişkilerini nasıl tasarladığı sorusuna cevap verdiğini düşünüyorum ancak bunu hızlı çalışacak şekilde nasıl uygulayacağınızı size söyleyemediğim için üzgünüm. Bir sosyal ağ uygulamak kolaydır, ancak iyi performans gösterdiğinden emin olmak kesinlikle değildir - IMHO.

Grafik sorgularını yapmak ve kenarlarımı temeldeki SQL DB ile eşleştirmek için OrientDB ile deneyler yapmaya başladım. Eğer bitirirsem, bunun hakkında bir makale yazacağım.


öyleyse .. hiç makaleyi yazmaya başladınız mı?
FlowUI. SimpleUITesting.com

1
Hayır, programlama yapmanın yanı sıra oldukça meşgulüm ve bunu yapacak zamanım ve ruh halim olmadı. Buradaki cevap, performanslı arkadaş dernekleri uygulamak istiyorsanız bilmeniz gereken her şeyi içerir. Ya kullanıcı başına arkadaş listelerini önbelleğe alın ya da ilişkisel DB'nizi parçalar halinde veya her şeyi bir grafiğe eşleyin ve grafik DB'sini sorgulayın. Bunun için OrientDB veya Neo4j kullanabilirsiniz. Kendi açık kaynaklı sosyal ağ yazılımımı yazmayı çok isterdim, ancak yapacak çok şey var. Ne yaparsanız yapın: Kıyaslama yapın. :)
burzum

Hala hayır. Ancak OrientDB dokümantasyonu, arkadaş bağlantılarını açıklar ve diğer her şey, temel bilgiler anlaşıldıktan sonra modellenebilir. orientdb.com/docs/2.1/Tutorial-Working-with-graphs.html Temel olarak ilişkisel bir DB kullanmak istiyorsanız, "kaydettikten sonra" ve "sildikten sonra" geri aramalarınızı güncellemek için yalnızca bir kod eklemeniz gerekir. grafik DB (verileri okumak için kullanacağınız). Bu tür geri aramalarınız yoksa bunları uygular, ancak neredeyse tüm ORM uygulamalarının ve çerçevelerinin böyle bir şeyi olduğunu tahmin ediyorum. Aslında OrientDB belgeleri de saklayabilir.
burzum

1
öyleyse .. hiç makaleyi yazmaya başladınız mı?
Connor Gurney

1
Yine de hayır ama işte benzer bir şey yapıyoruz: İlişkisel verilerimizi daha önce yorumumda yazdığım gibi Esnek Arama diziniyle eşliyoruz, bu sadece belirli bir eylemden sonra dizinde veya grafikte saklamak istediğiniz verileri elde etme meselesi (bizim durumumuzda afterSave () / afterDelete () geri arama) ve ardından dizini veya grafiği güncelleyin. Gayet basit? :) Bu arada, arkadaş listeleri için de aynısı yapılabilir, bunları ES'de, bir grafikte veya bellek tabanlı bir önbellekte (yeterli RAM'e sahip olduğunuz sürece) saklamanız çok da önemli değil. Gerçekten zor değil, zor olan, büyüdüğünüzde her şeyi ölçeklendirmek.
burzum

32

En iyi iddiam, bir grafik yapısı oluşturmalarıdır . Düğümler kullanıcı ve "arkadaşlıklar" uç noktalardır.

Bir kullanıcı tablosu tutun, başka bir kenar tablosu tutun. Ardından, "arkadaş oldukları gün" ve "onaylanma durumu" gibi uçlarla ilgili verileri saklayabilirsiniz.


40
Sanırım buradaki bazı insanlara bunu biraz daha açıklaman gerekecek.
TheTXI

4
Bence daha ilginç bir soru, bu kadar büyük bir yapının (200 milyon düğüm ve milyarlarca uçtan bahsediyoruz) kolayca aranabilecek ve güncellenebilecek şekilde nasıl sürdürüleceği olacaktır.
Dirk Vollmar

1
@divo: dizinlerin ve bölümlerin akıllıca kullanımı.
belgariontheking

20

Büyük olasılıkla çoktan çoğa bir ilişki:

Arkadaş Listesi (tablo)

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

DÜZENLE

Kullanıcı tablosunda muhtemelen bir PK olarak user_email yok, muhtemelen benzersiz bir anahtar olarak.

kullanıcılar (tablo)

user_id PK
user_email
password

4
Bu kesinlikle en mantıklı olanı olsa da, Facebook'un kaç kullanıcısı ve her Facebook kullanıcısının kaç arkadaşı olduğu göz önüne alındığında performansın korkunç olacağını düşünüyorum.
Kevin Pang

17

LinkedIn ve Digg'in nasıl inşa edildiğini açıklayan şu makalelere bir göz atın:

Ayrıca yararlı olabilecek "Büyük Veri: Facebook Veri Ekibinden Bakış Açıları" da var:

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

Ayrıca, ilişkisel olmayan veritabanlarından ve bazı şirketler tarafından nasıl kullanıldıklarından bahseden bir makale var:

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

Bu şirketlerin veri ambarları, bölümlenmiş veritabanları, veri önbelleğe alma ve çoğumuzun günlük olarak asla uğraşmadığımız diğer yüksek seviyeli kavramlarla uğraştığını göreceksiniz. Ya da en azından, bildiğimizi bilmiyoruz.

İlk iki makalede, size daha fazla fikir vermesi gereken birçok bağlantı var.

GÜNCELLEME 10/20/2014

Murat Demirbaş hakkında bir özet yazdı

  • TAO: Facebook'un sosyal grafik için dağıtılmış veri deposu (ATC'13)
  • F4: Facebook'un sıcak BLOB depolama sistemi (OSDI'14)

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

HTH


9

Sabit bir zamanda yarım milyarı aşan veriler için RDBMS'den kullanıcı arkadaşları için veri almak mümkün değildir, bu nedenle Facebook bunu bir karma veritabanı (SQL yok) kullanarak gerçekleştirdi ve Cassandra adlı veritabanını açık kaynaklı hale getirdi.

Böylece her kullanıcının kendi anahtarı ve bir kuyruktaki arkadaş ayrıntıları vardır; Cassandra'nın nasıl çalıştığını öğrenmek için şuna bakın:

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


Çok ilginç, teşekkürler dostum. Sql'den Cassandra'ya ne zaman geçtiler? Ne oldugunu biliyor musun?
Marin

1
Dikkat edin: Posterous Spaces öldü ... yani bağlantı.
TechNyquist


5

Yabancı anahtarlar arıyorsunuz. Temel olarak, kendi tablosu olmadığı sürece bir veritabanında bir diziye sahip olamazsınız.


Örnek şema:

    Kullanıcılar Tablosu
        kullanıcı kimliği PK
        diğer veri
    Arkadaşlar Masası
        userID - Bir arkadaşı olan kullanıcıyı temsil eden kullanıcıların tablosuna FK.
        friendID - Arkadaşın kullanıcı kimliğini temsil eden Kullanıcı tablosuna FK

5
Neden olumsuz oylar? En azından birisine neden reddettiğinizi bildirin.
Sasha Chedygov

3
@freak: Neden? Bu sitedeki oylama kavramının tamamı, oy vermenin anonim olması içindir. Neden malfistin herhangi bir şeye hakkı olduğunu düşünüyorsunuz?
GEOCHET

4
Özellikle geçerli bir cevap olduğunda ve diğer cevaplar tarafından yankılandığında (onlardan kopyalamamama rağmen, cevapladığımda cevapların olmadığı yerde)
Malfist

4
@TheTXI: Olumsuz oylarla ilgili yorumların bir nezaket olduğunu düşünüyorum, özellikle onları hak etmediği açık olan yanıtlar için, ancak yorumların zorunlu kılınmaması gerektiğini de kabul ediyorum.
Robert S.

2
Açık olmayan cevaplara isimsiz olarak olumsuz oy veren kişiler, olumsuz oyu açıklayan bir yorum bırakırlarsa sığ akıl yürütmelerinin açığa çıkacağından korkanlardır.
Vinayak


1

Veritabanı tablolarının yatay olarak değil (daha fazla sütun) dikey olarak (daha fazla satır) büyüyecek şekilde tasarlandığını unutmayın.


24
ASLA UNUTMA! Babam, sütunları için dikey olarak çok fazla büyüyen bir db tablosu nedeniyle öldü. Seni özleyeceğim baba
belgariontheking

1
hmm, neden olumsuz oy? Ve bunun üzerindeki yorum mantıklı değil.
Neil N

2
Hayır, yorum mantıklı değil. Birisi komik olmaya çalışıyor gibi görünüyor, bu yüzden aldırmayın.
Dirk Vollmar

0

Çoktan çoğa bir tablonun performansıyla ilgili olarak, kullanıcı kimliklerini birbirine bağlayan 2 32-bit girişiniz varsa, her biri ortalama 200 arkadaş olan 200.000.000 kullanıcı için temel veri depolama alanınız 300 GB'ın biraz altındadır.

Açıkçası, biraz bölümlemeye ve indekslemeye ihtiyacınız olacak ve bunu tüm kullanıcılar için hafızada tutmayacaksınız.


0

Muhtemelen, arkadaş <-> kullanıcı ilişkisini saklayan, "frnd_list" diyen, 'user_id', 'frnd_id' alanlarına sahip bir tablo vardır.

Bir kullanıcı başka bir kullanıcıyı arkadaş olarak eklediğinde, iki yeni satır oluşturulur.

Örneğin, kimliğimin 'deep9c' olduğunu ve arkadaşım olarak 'akash3b' kimliğine sahip bir kullanıcı eklediğimi ve ardından "frnd_list" tablosunda ('deep9c', 'akash3b') ve ('akash3b) değerleriyle iki yeni satır oluşturulduğunu varsayalım. ', 'deep9c').

Şimdi, arkadaş listesini belirli bir kullanıcıya gösterirken, basit bir sql bunu yapacaktır: "frnd_list'ten frnd_id seçin, burada user_id =" oturum açmış kullanıcının kimliği nerede (bir oturum özelliği olarak saklanır).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.