Wow, to proste pytanie, na które można znaleźć wiele możliwych odpowiedzi. Bardziej wyraźna część pytania dotyczy tego, czy można bardziej skalować interfejs z bazą danych bezpośrednio, czy za pośrednictwem usługi internetowej. Ta odpowiedź jest prosta: bezpośrednio przeprowadź zapytanie do bazy danych. Przejście przez usługę internetową powoduje cały szereg opóźnień, które są całkowicie niepotrzebne dla kodu działającego za zaporą ogniową (ogólnie). Na przykład usługa sieci Web wymaga, aby jakiś komponent odebrał żądanie, przekształcił go z postaci szeregowej, wysłał zapytanie do bazy danych, serializował odpowiedź i zwrócił ją. Więc jeśli twój kod działa za zaporą ogniową, oszczędzaj sobie kłopotów i po prostu odpytaj bezpośrednio DB.
Skalowanie strony internetowej jest jednak znacznie wykraczające poza postawione na początku pytanie. Więc wybacz mi, jeśli wybiorę tutaj styczną, ale pomyślałem, że to może być przydatne, biorąc pod uwagę, że wspomniałeś w szczególności o Facebooku.
Polecam przeczytać o pracy i narzędziach stworzonych przez Brada Fitzpatricka (założyciela LiveJournal, a teraz Google). Kiedy współpracowałem z nim w Six Apart, oto kilka rzeczy, których się od niego nauczyłem, a także o architekturze LiveJournal, która uczyniła go tak skalowalnym.
Używaj wąskich tabel bazy danych zamiast szerokich . To, co było w tym fascynujące, to wiedza o motywach architektury, która tworzyła system, który był łatwy i szybkiulepszone. Jeśli używasz szerokich tabel lub tabel, dla których każde pole lub właściwość jest kolumną w tabeli, gdy przyjdzie czas na uaktualnienie schematu bazy danych, na przykład dodanie nowej kolumny, system będzie musiał zablokować tabelę podczas schematu zmiana została wprowadzona. Podczas pracy w skali oznaczałoby to prostą zmianę schematu bazy danych, która mogłaby doprowadzić do dużej awarii bazy danych. Co oczywiście jest do bani. Z drugiej strony wąska tabela po prostu przechowuje każdą indywidualną właściwość powiązaną z obiektem jako pojedynczy wiersz w bazie danych. Dlatego jeśli chcesz dodać nową kolumnę do bazy danych, wszystko, co musisz zrobić, to wstawić rekordy do tabeli, co jest operacją nieblokującą. Ok, to jest małe tło, zobaczmy, jak ten model faktycznie tłumaczy w działającym systemie, takim jak LiveJournal.
Załóżmy, że chcesz załadować 10 ostatnich pozycji dziennika na blogu danej osoby, i powiedzmy, że każda pozycja dziennika ma dziesięć właściwości. W klasycznym układzie szerokiej tabeli każda właściwość korelowałaby z kolumną w tabeli. Użytkownik zapyta następnie tabelę raz, aby pobrać wszystkie potrzebne dane. Kwerenda zwróciłaby 10 wierszy, a każdy wiersz zawierałby wszystkie potrzebne dane (np. WYBIERZ * Z pozycji ZAMÓW WEDŁUG LIMITU daty 10). Jednak w wąskim układzie tabel sytuacja wygląda nieco inaczej. W tym przykładzie faktycznie istnieją dwie tabele: pierwsza tabela (tabela A) przechowuje proste kryteria, według których chciałbyś wyszukiwać, np. Identyfikator wpisu, identyfikator autora, datę wpisu itp. Druga tabela (tabela B) następnie przechowuje wszystkie właściwości związane z wpisem. Ta druga tabela ma trzy kolumny: identyfikator_wpisu, klucz i wartość. Dla każdego wiersza w tabeli A będzie 10 wierszy w tabeli B (jeden wiersz dla każdej właściwości). Dlatego aby pobrać i wyświetlić ostatnie dziesięć wpisów, potrzebujesz 11 zapytań. Pierwsze zapytanie daje listę identyfikatorów pozycji, a następnie następne dziesięć zapytań pobiera właściwości związane z każdym z wpisów zwróconych w pierwszym zapytaniu.
„Holy Moly!” mówicie: „jak, u licha, może być bardziej skalowalne ?!” To całkowicie sprzeczne z intuicją, prawda? W pierwszym scenariuszu mieliśmy tylko jedno zapytanie do bazy danych, ale w drugim „bardziej skalowalnym” rozwiązaniu mamy 11 zapytań do bazy danych. To nie ma sensu. Odpowiedź na to pytanie opiera się całkowicie na następnym punkcie.
Użyj memcache swobodnie. Jeśli nie wiesz, Memcache jest rozproszonym, bezstanowym, opartym na sieci systemem buforowania o niskim opóźnieniu. Używają go Facebook, Google, Yahoo i niemal każda popularna i skalowalna strona internetowa na świecie. Został wynaleziony przez Brada Fitzpatricka częściowo, aby pomóc zrównoważyć narzut bazy danych związany z projektem bazy danych wąskiej tabeli. Spójrzmy na ten sam przykład, co omówiony w punkcie 1 powyżej, ale tym razem wprowadzimy memcache.
Zacznijmy, gdy użytkownik po raz pierwszy odwiedzi stronę i nic nie będzie w pamięci podręcznej. Zaczynasz od zapytania tabeli A, która zwraca identyfikatory 10 pozycji, które chcesz wyświetlić na stronie. Dla każdego z tych wpisów następnie przeszukujesz bazę danych, aby uzyskać właściwości związane z tym wpisem, a następnie użycie tych właściwości stanowi obiekt, z którym Twój kod może się połączyć (np. Obiekt). Następnie przechowujesz ten obiekt (lub szeregową postać tego obiektu) w memcache.
Za drugim razem, gdy ktoś ładuje tę samą stronę, zaczynasz w ten sam sposób: przeszukując tabelę A, aby wyświetlić listę identyfikatorów wpisów, które wyświetlisz. Do każdego wpisu najpierw przejdź do memcache i powiedz „czy masz wpis X w pamięci podręcznej?” Jeśli tak, to memcache zwraca obiekt wejściowy do Ciebie. Jeśli nie, musisz ponownie wykonać zapytanie do bazy danych, aby pobrać jej właściwości, utworzyć obiekt i schować go w pamięci podręcznej. Przez większość czasu, gdy ktoś odwiedza tę samą stronę, jest tylko jedno zapytanie do bazy danych, wszystkie inne dane są następnie pobierane bezpośrednio z pamięci podręcznej.
W praktyce większość LiveJournal zdarzyła się w ten sposób, że większość danych systemu, szczególnie te mniej zmienne, były buforowane w memcache, a dodatkowe zapytania do bazy danych potrzebne do obsługi schematu wąskiej tabeli zostały prawie całkowicie zrównowa one.
Ten projekt znacznie ułatwił rozwiązanie problemu związanego ze złożeniem listy postów powiązanych ze wszystkimi znajomymi w strumień lub „ścianą” .
Następnie rozważ podzielenie bazy danych na partycje. Model omówiony powyżej ujawnia jeszcze jeden problem, a mianowicie wąskie tabele będą zwykle bardzo duże / długie. Im więcej wierszy w tych tabelach, tym trudniejsze stają się inne zadania administracyjne. Aby to zrównoważyć, rozsądne może być zarządzanie rozmiarem tabel poprzez partycjonowanie tabel w taki sposób, aby klastry użytkowników były obsługiwane przez jedną bazę danych, a inny klaster użytkowników obsługiwany był przez oddzielną bazę danych. To rozkłada obciążenie bazy danych i utrzymuje wydajność zapytań.
Wreszcie potrzebujesz niesamowitych indeksów. Szybkość twoich zapytań będzie zależeć w dużej mierze od tego, jak dobrze indeksowane są tabele twojej bazy danych. Nie będę spędzał zbyt dużo czasu na omawianiu indeksu, poza tym, że mówię, że to bardzo przypomina system katalogów gigantycznych kart, aby usprawnić znajdowanie igieł w stogu siana. Jeśli używasz mysql, zalecam włączenie dziennika powolnych zapytań, aby monitorować zapytania, których wypełnienie zajmuje dużo czasu. Kiedy zapytanie pojawi się na twoim radarach (np. Ponieważ jest wolne), dowiedz się, jaki indeks musisz dodać do tabeli, aby go przyspieszyć.
„Dziękuję za całe to wspaniałe tło, ale cholera, to dużo kodu, który będę musiał napisać.”
Niekoniecznie. Napisano wiele bibliotek, które sprawiają, że interfejs z memcache jest naprawdę łatwy. Jeszcze inne biblioteki skodyfikowały cały proces opisany powyżej; Data :: ObjectDriver w Perlu jest właśnie taką biblioteką. Jeśli chodzi o inne języki, będziesz musiał przeprowadzić własne badania.
Mam nadzieję, że ta odpowiedź była pomocna. To, co stwierdziłem częściej niż nie, to to, że skalowalność systemu często sprowadza się coraz mniej do kodu, a coraz bardziej do solidnego przechowywania danych i strategii zarządzania / projektu technicznego.