Autor: Gdańsk 01.06.2010 Michał Giergielewicz MongoDB w zastosowaniu w serwisach społecznościowych Poniższe sprawozdanie ma na celu przekazanie informacji na temat systemu bazodanowego MongoDB, i tego, jaką daję przewagę nad tradycyjną bazą danych wykorzystywaną w internetowych serwisach społecznościowych czyli MySQL. Sprawozdanie zawiera: 1. Przedstawienie wymagań dotyczących baz danych w tradycyjnym podejściu do portali internetowych czyli tzw. WEB1.0 2. Przedstawienie wymagań dotyczących baz danych w podejściu społecznościowym czyli WEB2.0 3. Przybliżenie cech systemów nierelacyjnych na podstawie MongoDB 4. Prezentacja możliwych zastosowań MongoDB 5. Omówienie zalet MongoDB na przykładzie wybranych funkcjonalności społecznościowych 6. Podsumowanie wyników wydajnościowych przeprowadzonych w środowisku produkcyjnym serwisów Gratka Technologie Celem sprawozdania jest przekazanie podstawowej wiedzy na temat nierelacyjnych baz danych, uświadomienie konieczności rozwoju środowisk bazodanowych w internetowych portalach społecznościowych, tak aby sprostać zmieniającym się wymaganiom i zaprezentowanie nowego podejścia do sposobu przechowywania i prezentowania informacji w portalach internetowych. Wymagania wobec baz danych w portalach internetowych w podejściu tradycyjnym. MySQL jest najpopularniejszym obecnie systemem baz danych wykorzystywanym w środowiskach portali internetowych. Jest to relacyjna baza danych spełniająca wymogi wydajnościowe i pojemnościowe nawet dla dużych serwisów. W czasach tzw. WEB1.0 czyli wtedy, gdy użytkownicy witryn internetowych byli biernymi oglądaczami prezentowanych treści, a jedyną formą interakcji była funkcjonalność forum internetowego, baza MySQL była więcej niż wystarczającym narzędziem. Jeśli założymy, że nawet duży portal internetowy o charakterze kontentowym 1 (wp.pl, 1 Portal kontentowy (ang. Content treść, zawartość), to portal o charakterze informacyjnym, który publikuje artykuły, wiadomości i zawartość multimedialną mającą na celu informowanie użytkowników. 1
onet.pl itp) posiada nie więcej niż kilkuset redaktorów tworzących treść serwisu, to przekłada się to na nie więcej niż kilka-kilkanaście tysięcy zapisów do bazy MySQL na dobę. Przy tym założeniu baza MySQL jest idealnym narzędziem ponieważ jej siła najbardziej się uwidacznia przy dużej dysproporcji między poziomem zapisu a odczytu (dokładnie mało zapisów, dużo odczytów). Nawet bardzo duża pula odczytów w takim serwisie może zostać skutecznie rozłożona na slave'y 2 w replikacji MySQL. Jeśli uruchomimy replikację na jednej maszynie typu master, to bez najmniejszego problemu obsłuży ona cały ruch zapisujący dane od redaktorów i prześle go na dowolną praktycznie ilość slave'ów, a duża pula odczytów rozłoży się poprzez loadbalancing na kilka slave'ów. W takim systemie jest możliwe obsłużenie naprawdę bardzo dużego ruchu przy rozsądnych nakładach sprzętowych. Wymagania wobec baz danych w portalach internetowych w podejściu społecznościowym Tak zwane WEB2.0 całkowicie odmieniło rzeczywistość 'sprzętową' w portalach internetowych. Wokół witryn zaczęły tworzyć się społeczności przyciągane możliwościami aktywnego tworzenia treści serwisu, wymiany myśli, poglądów, współpracy i integracji ludzi. W Web2.0 przeważa tzw. User Generated Content, co przekłada się oczywiście na kwestie przechowywania i serwowania informacji z poziomu baz danych. W serwisach społecznościowych nie ma kilkuset redaktorów tylko kilka tysięcy lub nawet kilka milionów! Facebook czy naszaklasa to sztandarowe przykłady bardzo dużych portali społecznościowych i na ich podstawie można przeanalizować jakim wymaganiom musi sprostać baza danych. Ogromny wzrost zapisów i modyfikacji w bazie danych spowodowany jest tym, że każdy dotychczasowy bierny odbiorca treści, stał się aktywnym twórcą. Taki wzrost zapisów jest czymś do czego MySQL po prostu nie został stworzony, zapis do bazy, zwłaszcza modyfikacja rekordu powoduje zablokowanie całej tabeli, co powoduje opóźnienia w odczytach i rosnące kolejki 'selectów' czekających na odblokowanie tabeli. Jeśli zapisów jest dużo, blokady powodują ogromny wzrost obciążenia i w rezultacie zawieszenie procesu MySQLd. Oczywiście w MySQL są techniki i narzędzia które mogą w pewnym stopniu ograniczyć ten problem lecz w praktyce bardzo szybko dochodzi do wysycenia systemu i jedynym rozwiązaniem jest ucieczka w sprzęt czyli rozbudowa farmy serwerów MySQL. Oczywiście takie rozwiązanie jest bardzo kosztowne i w praktyce nieopłacalne. Na szczęście istnieje inne rozwiązanie. 2 Slave (ang. niewolnik, to w znaczeniu podległy) część systemu bazodanowego (najczęściej osobna maszyna) udostępniająca dane tylko do odczytu. Jeden system bazodanowy może utrzymywać kilka takich systemów rozkładając w ten sposób obciążenie zapytaniami pobierającymi dane na kilka fizycznych maszyn. 2
Przybliżenie cech systemów nierelacyjnych na bazie MongoDB MongoDB to tak zwana nierelacyjna baza danych pracująca w modelu 'Document Oriented'. Idea stojąca za Mongo jest następująca: Systemy relacyjne takie jak MySQL, Oracle czy Mssql są bardzo rozbudowane, mają ogromne możliwości lecz często okupione jest to niższą wydajnością i skomplikowaną obsługą. Z drugiej strony systemy typu 'key-value' takie jak Mamcache, Redis, czy Voldemort są wyjątkowo proste w budowie i oferują stosunkowo niewiele funkcji (w uogólnieniu to tablice hashowe, czasem rozbudowane o proste mechanizmy wyszukiwania czy agregacji i bardziej rozbudowane funkcje wydajnościowe takie jak klastrowanie, możliwość pracy w systemach rozproszonych z wysoką odpornością na awarie) lecz ich zaletą jest ogromna wręcz prędkość działania i niezawodność. MongoDB spina te dwa podejścia starając się przejąć to co najlepsze z systemów relacyjnych czyli funkcje wyszukiwania, sortowania, agregacji a z systemów key-value szybkość działania i dużą odporność na awarie. W efekcie MongoDB zapewnia doskonałe lekarstwo na problemy które przyniosło Web2.0. Posiada możliwość definiowania kolekcji (tabel) i dokumentów (krotek), lecz ponieważ jest bazą typu schemeless 3 nie ma potrzeby definiowania struktury tych obiektów, więc każdy z nich może zawierać inne pola np. jeśli weźmiemy pod uwagę kolekcję użytkowników, to jeden dokument może zawierać pola 'imie', 'nazwisko', 'email' a drugi 'imie', 'login', 'status' oba dokumenty mogą leżeć we wspólnej kolekcji. W każdym przypadku pola niezdefiniowane są niejawnie definiowane jako puste. Jedynym wymogiem jest istnienie unikalnego klucza głównego dla każdego dokumentu wewnątrz jednej kolekcji o co zresztą dba samo Mongo. Takie podejście jest intuicyjne i proste w implementacji a dodatkowo oszczędza miejsce (nie ma potrzeby rezerwacji miejsca na pola które mają puste wartości, i łatwo wprowadzać zmiany do danych przechowywanych w kolekcji nie ma potrzeby redefiniowania struktury jak w wypadku baz relacyjnych) Kolekcje można przeszukiwać pod kątem istnienia dokumentów spełniających określone kryteria (np. Pole płeć ma wartość k lub imie zaczyna się na Mich ), w tej chwili nie ma jeszcze możliwości przeszukiwania pełnotekstowego ale istnieją znane obejścia tego problemu a developerzy Mongo pracują nad natywną obsługą tej funkcji. Otrzymane wyniki można dowolnie sortować, ograniczać i agregować. Mongo pozwala też na zakładanie indeksów, które działają analogicznie do tych w MySQL. Dodatkowo Mongo zapewnia 3 Schemeless (ang. bez struktury) tu system bazodanowy niewymagający definiowania struktur ( jak w bazach relacyjnych poprzez DDL SQL). Dane zapisywane są w postaci dokumentów najczęściej w formie pseudo obiektowej (w wypadku MongoDB jest do format Json) 3
atomowość operacji na poziomie dokumentu i nie wymaga blokady kolekcji podczas dodawania danych bądź ich aktualizacji. Tylko usuwanie danych i zakładanie indeksów wymaga założenia blokady dla wątków odczytujących. Mongo oferuje też bardzo rozbudowane funkcje replikacji, sharding 4 i posiada wbudowane mechanizmy failover'a 5, potrafi też pracować w środowiskach rozproszonych. Jest więc odporne na awarie pojedynczego węzła systemu. Podstawową różnicą między MongoDB a systemami relacyjnymi jest brak możliwości wykonywania złączeń między kolekcjami mówiąc prosto MongoDB nie ma JOIN'ów, nie ma relacji. Ważnym ograniczeniem jest też brak transakcyjności dlatego też Mongo nie jest polecane dla systemów finansowo-księgowych, płatniczych czy bankowych. Należy zaznaczyć że MongoDB nie wypracowało jakiegoś odkrywczego podejścia do wyszukiwania czy wstawiania danych. Większość stosowanych mechanizmów jest znana i wykorzystywana od dawna również w bazach relacyjnych (np. indeksy oparte są na zwykłych drzewach B-Tree). To czemu MongoDB zawdzięcza swoją szybkość to głównie składowa dwóch rzeczy. Po pierwsze wszystkie dane trzymane są w pamięci operacyjnej i dopiero stamtąd zapisywane na dysk, po drugie język zapytań rozbudowany został o komendy umożliwiające operacje atomowe (jednoczesne zapytania modyfikujące i pobierające dane są dopuszczalne i nie blokują kolekcji). Nawet te dwie niewielkie modyfikacje powodują znaczący przyrost wydajności. Dodajmy do tego funkcjonalność kolekcji wbudowanej (embed), która po części zastępuje referencje używane w bazach relacyjnych, wykorzystanie zalet formalnej specyfikacji DBRef umożliwiającej łączenie obiektów z różnych kolekcji między sobą (co przyspiesza wyszukiwanie i łączenie wyników z różnych kolekcji) czy wbudowanie w MongoDB możliwości tworzenia struktur drzewa (nested tree, parent-child). To tylko przykładowe możliwości MongoDB a każde z nich daje przyrost prędkości. I właśnie to jest siłą tego systemu wykorzystuje on znane technologie, tak aby uzyskać wysoką wydajność dla bardzo konkretnych zastosowań. MongoDB nie sprawdzi się jako hurtownia danych nie jest do tego stworzony i większość jego zalet nie będzie miała w takim przypadku zastosowania. Jeśli jednak użyjemy tego systemu do zastosowań real-time (takich jak portale internetowe), wychodzi na jaw jego siła. 4 Sharding (ang. łuska) system pracy baz danych umożliwiający przechowywanie jednego logicznego obiektu na kilku fizycznych maszynach. 5 Failover (ang. obejście zawieszenia) tu w znaczeniu systemu do zabezpieczenia na wypadek awarii, tak aby zachować dostępność usługi. 4
Prezentacja możliwych zastosowań MongoDB MongoDB jest w stanie w całości przejąć obowiązki MySQL, jednak najlepszą drogą dla już istniejących portali jest ewolucyjne podejście i implementacja Mongo tam gdzie można najlepiej wykorzystać jego możliwości. Pierwszym z takich miejsc jest tak zwana druga warstwa cache'owania (secondcache). Najczęściej stosowanym systemem cache'owania w portalach internetowych jest Memcache jest to system który nie wspiera mechanizmów replikacji i failovera, więc w wypadku uszkodzenia maszyny, nie ma możliwości zapewnienia ciągłości dostępu do cache'a. W takim środowisku stawiamy MongoDB jako drugą warstwę. Systemy odpowiedzialne za odczyt danych z bazy i ich zapis do cache'a modyfikuje się o dodatkową funkcję która podczas zapisu danych zapisuje je dodatkowo do Mongo a przy odczycie w razie braku odpowiedzi z Memcache, próbuje uzyskać dane z Mongo. Samo MongoDB w takim systemie pracuje w systemie failoverowym (tzw. Replikacja Master- Master, jedna maszyna jest online, druga pracująca jako slave jest w trybie oczekiwania, w razie awarii pierwszej maszyny, druga przejmuje jej obowiązki i staje się masterem, a pierwsza po usunięciu usterki samoczynnie przełącza się w tryb slave'a i przyjmuje zreplikowane dane), co zapewnia bardzo duży stopień bezpieczeństwa i uodparnia sytem cache'owania na awarię jednego z podsystemów. Drugim etapem integracji MongoDB z portalem jest tak zwany LazyCache czyli izolacja warstwy prezentacji od warstwy danych. W tym systemie dochodzi kolejna maszyna Mongo pełniąca rolę kolejki. Systemy dostępu do danych zostają zmodyfikowane w taki sposób, że każde zapytanie odczytujące dane z bazy jest zapisywane w kolejce wraz z informacją o czasie cache'owania tych danych. Samego odczytu z bazy dokonuje mechanizm kolejki, wykonując zapamiętane zapytania w zadanym odstępie czasu. Pobrane dane są w wstępnie przetworzonej formie zapisywane do Mongo pełniącego funkcję secondcache'u. Dopiero stąd dane zapisywane się do Memcache'a (mechanizm mongo pozwala na zapamiętywanie całych list obiektów jak i pojedynczych obiektów co umożliwia aktualizację w Memcache'u danych w sposób w jaki do tej pory nie można tego było wykonać np. w razie aktualizacji obiektu o id 15 mongo może zaktualizować ten obiekt w Memcache'u jak również wszystkie listy które zawierają kopie tego obiektu sam Memcache tego nie potrafi). Sam Memcache nigdy nie wygasza danych które zapamiętał, tak więc nawet w wypadku uszkodzenia mechanizmu kolejki, serwis zawsze będzie miał dostęp do danych. Nie będą może one tak aktualne jak by mogły być, jednak sam fakt, że zawieszenie się bazy danych, lub mechanizmu kolejki nie będzie powodowało awarii serwisu jest ogromnym krokiem naprzód. Dodatkową zaletą jest fakt, że można zarządzać obciążeniem bazy danych modyfikując prędkością kolejki i np. przyspieszać bądź 5
spowalniać proces aktualizowania się danych w serwisie, i to nie tylko na poziomie całego portalu ale, przy zastosowaniu odpowiednio zaprojektowanych paneli z dostępem do danych kolejki, na poziomie pojedynczego zapytania. Zaprezentowanie zalet Mongo na przykładzie wybranych funkcjonalności portali społecznościowych MongoDB charakteryzuje się ogromną szybkością i pojemnością. Wszystkie dane przechowywane są w pamięci RAM i dopiero z stamtąd zapisywane na dysk. Powoduje to, że taka baza jest wymarzonym narzędziem dla wielu funkcjonalności społecznościowych. Funkcje takie jak ściana lub tablica, znajomi, chmura tagów, opierają się zasadniczo na jednej podstawowej zasadzie. To co pisze jedna osoba widoczne jest u wielu osób a dodatkowo nie można tu stosować mechanizmów cache'owania, ponieważ użytkownicy społecznościowi oczekują natychmiastowej reakcji na ich akcje (jeżeli piszę coś na ścianie mojego znajomego, on powinien to zobaczyć w tym samym momencie, jeżeli piszę coś na swojej ścianie, to wszyscy moi znajomi muszą zobaczyć to od razu!). Taki system z konieczności musi mieć możliwość ogarnąć ogromne ilości jednoczesnych zapisów z jednoczesnymi odczytami. W wypadku nawet niewielkich społeczności (wiadomosci24.pl) gdzie liczba użytkowników jest stosunkowo niewielka (20000) wymagałoby to od bazy MySQL wydajności na poziomie przekraczającym możliwości pojedynczego serwera, a pozostał by i tak problem blokad tabel na czas zapisu. W mongodb nie ma takiego problemu, zapisy nie blokują odczytów i są wykonywane na pamięci RAM. Odczyty są dość proste i nie ma konieczności stosowania relacji, założone indeksy są wyjątkowo trafne, operują bowiem na stałych parametrach (wyszukiwanie zawsze po id_uzytkownika, sortowanie zawsze po dacie wpisu, funkcjonalności takie jak ściana nie posiadają innych funkcji). W takiej sytuacji MongoDB jest wprost wymarzonym systemem, jakby został zaprojektowany właśnie w tym celu. Podsumowanie wyników wydajnościowych przeprowadzonych w środowisku produkcyjnym serwisów Gratka Technologie Podczas testowania MongoDB dział Rozwoju Gratka Technologie przeprowadził testy wydajnościowe na MySQL, Memcache i Mongo w środowisku analogicznym do produkcyjnego. Przeprowadzono dwa testy. Test pierwszy zakładał operacje na bazie użytkowników. Test przeprowadzono przy identycznych warunkach wejściowych dla baz MySQL i MongoDB i Memcache. Ilość danych w bazach: 620000 6
rekordów. Pobranie użytkownika po ID memcache 1.12 ms mongo 0.51 ms MySQL 8.34 ms Odpytanie o nieistniejące ID: memcache 0.65 ms mongo 0.45 ms MySQL 9.35 ms Drugi test zakładał przeszukiwanie bazy ogłoszeń działu nieruchomości w serwisie dom.gratka.pl. Baza zawierała 1mln rekordów a wyszukiwanie odbywało się po kilku polach z sortowaniem i limitem + count. Test przeprowadzono dla MySQL i MongoDB. MySQL: ~5s MongoDB: ~0.34s Wyniki mówią same za siebie. Dziękuję za uwagę Michał Giergielewicz. 7