czerwca 07

Podczas rozwoju dużego portalu webowego każdy prędzej czy później stanie przed problemem wydajności. Przeważnie najbardziej wąskim gardłem jest baza danych. Łatwo jest rozproszy obrazki na więcej serwerów, nawet content html czy pliki php. Najgorzej jest ze skalowalnością bazy. Nie dość że jest to problem od strony technicznej to również jest to najbardziej kosztowne. Po pewnej ilości użytkowników okazuje się że cachowanie, czy generowanie statyczne wszystkiego co było możliwe nie jest już wystarczające a na dodatek wielu użytkowników wykorzystuje opcję przeglądu czy search które pochłaniają najwięcej zasobów bazy danych. W takich przypadkach z pomocą może przyjść nam sphinx. Oczywiście jak w każdym przypadku jego zastosowanie niesie ze sobą wiele plusów i minusów a zadaniem tego artykułu będzie pokazanie jak sobie z tym wszystkim poradzić i jak optymalnie wykorzystać możliwości sphinx’a.

Sphinx to darmowy silnik SQL full-text search na licencji GPL 2. Jest to program pozwalający na zaindeksowanie wybranej przez nas części bazy danych i przeszukiwanie go w bardzo wydajny sposób . W chwili obecnej pozwala na podłączenie sie do MySQL’a i PostgreSQL’a. Posiada natywny support do PHP, Pythona, Javy, Perl’a i Ruby.

Ponieważ jest on niezależny od działania silnika bazy danych i niezależnie przechowuje przeszukiwane przez nas tabele posiada dwie bardzo poważne wady. Pierwszą z nich jest dodatkowe miejsce które zajmie na serwerze, drugą z nich jest obciążenie które wygeneruje podczas tworzenia swoich tabel i to że tabele te będą widokiem danych z chwili w której były generowane a nie danymi z czasu rzeczywistego. Jednak te dwa problemy nie dyskwalifikują Sphinxa do wielu zastosowań. Jedną z głównych jego zalet jest oszczędność mocy serwera podczas przeszukiwania danych, potrafi wygenerować interesujące nas wyniki w czasie kilkadziesiąt razy krótszym niż zrobił by to silnik naszej bazy. Można go też postawić na dodatkowej maszynie co pozwoli na ułatwienie skalowalności naszego portalu.

Rozwiązanie to z pewnością nie nadaje się do wykorzystywania przy danych które muszą być analizowane na bieżąco. Można jednak użyć go spokojnie przy mniej krytycznych danych. Choćby przeszukiwanie archiwum listy dyskusyjnej. Czy konieczne jest aby osoba widziała stan archiwum sprzed sekundy? Czy wystarczy jeżeli silnik będzie bazował na danych regenerowanych kilka razy dziennie. Można też zastosować go do przeglądu profili portalu społecznościowego. Wyobraźmy sobie użytkowników którzy próbują przeszukiwać milion profili naszego portalu po wybranych słowach kluczowych w profilu. Czy dla nich krytyczne będzie to czy silnik analizuje bieżące dane czy sprzed czterech godzin? W zamian za te małe niedogodności otrzymujemy mechanizm który pozwoli obniżyć koszt takiego wyszukiwania kilkadziesiąt razy i uniknąć sytuacji w których bardziej skomplikowane zapytanie użytkownika zwalnia działanie całego portalu i męczy bazę danych przez kilka minut.

Aby porównać wydajnościowo rozwiązanie oparte na sphinxie i poszukiwanie danych w postgresql stworzyłem tabelę o nazwie profile. Zawiera ona informacje o profilach prawie miliona użytkowników. Między innymi w profilu znajduje się kolumna desc która zawiera opis danego profilu. Wyobraźmy sobie zwykły serwis w którym użytkownicy chcą znajdować osoby z wybranymi słowami kluczowymi w opisie. Interesującym nas słowem będzie słowo „fun”. Dodam też że postgresql jest tak zoptymalizowany że całą tabele z profilami jest w stanie zmieścić w cachu a wszystkie niezbędne operacje wykonać w pamięci. Tabela była już używana i wykonano analizę jej struktury co powinno zoptymalizować jej wykorzystanie.

Zaczynając od PostgreSQL:

SELECT profile_id from profile WHERE desc ilike ‘%fun%’;

Czas wykonania zapytania to 2150 ms

Teraz to samo zapytanie do wcześniej przygotowanej bazy Sphinxa

Czas wykonania – 104 ms

Widać że różnica jest dwudziestu krotna! Może się wydawać że taka strata dwóch sekund to niewiele, ale teraz wyobraź sobie serwis w którym z opcji search korzysta dziesięć osób na sekundę. Zastosowanie bezpośrednio zapytań do bazy danych a zapytań do sphinxa może spowodować że na sprzęt wydasz kilkaset dolarów miesięcznie mniej! Dodatkowo baza sphinxa może leżeć na innej maszynie wtedy obciążenia typu search nie będą obciążały głównej bazy danych która i tak ma bez tego mnóstwo zapytań.

Dodatkową ciekawą możliwością sphinxa jest zastosowanie procedur morfologii. Umożliwia to znajdowanie słów o podobnym znaczeniu lub z innymi końcówkami. Świetnie nadaje się do silników encyklopedii, wyszukiwarek czy słowników. Niestety w chwili obecnej jest dostępne jedynie w wersji angielskiej i rosyjskiej słownika.

Teraz należy powiedzieć kilka słów o zasobach zużywanych przez sphinxa. Ponieważ program ten tworzy własną kopię danych z bazy danych, zużyje trochę miejsca na dysku. Jego indeksy jednak przechowują jedynie niezbędne dane a nie całe wiersze tabel. Przy dobrze ustawionych parametrach sphinx zajmie 5-20% wielkości oryginalnej tabeli. Użyje też trochę ramu ponieważ będzie starał się umieścić wszystkie swoje indeksy w pamięci by uzyskać większą wydajność.

Potrzebny będzie również czas na wygenerowanie naszych tabel , lecz nie powinno stanowić to problemu ponieważ dzieje się to bardzo szybko:

indexing index ‘test1’…

collected 866890 docs, 45.3 MB

sorted 6.9 Mhits, 100.0% done

total 866890 docs, 45262403 bytes

total 10.719 sec, 4222616.51 bytes/sec, 80873.83 docs/sec

Dodatkowo do indexów sphinxa możemy nie tylko wrzucać dane tabele, ale również całe skomplikowane zapytania co spowoduje że ich wynik nie będzie musiał być wielokrotnie obrabiany a wyniki wstępnej obróbki będą przechowywane w indexach sphinx’a.

Ciekawą funkcją jest też ograniczenie liczby dopasowywanych powtórzeń (max_matches). Załóżmy że ktoś szuka osób z hasłem „fun” w opisie profilu i pojawia się 40 000 profili. Wyświetlając po 10 profili na stronę wiadomo że osoba ta nie przejrzy więcej niż 500 stron i dlatego ilość zapamiętywanych wyników można ograniczyć np. Do 5000.

Dużą zaletą jest też ograniczenie indeksów jakie będziemy musieli zakładać na oryginalnej bazie. Zwłaszcza dla niektórych rzadko używanych zapytań. Każdy indeks wymaga obsługi podczas insertu lub update’u krotki a my większość indeksów będziemy mogli przenieść do mechanizmy sphinxa. Pozwoli to również zaoszczędzić miejsce które zajmuje oryginalna baza.

Samo użycie sphinxa jest stosunkowo proste, wystarczy przygotowac odpowiedni plik konfiguracyjny i włączyć indexer. Po tej operacji odpalić specjalnego demona który będzie stał na porcie i serwował dane z indexów. Moja przykładowa konfiguracja wyglądała następująco:

source src1

{

type = pgsql

strip_html = 0

index_html_attrs =

sql_host = localhost

sql_user = pgsql

sql_pass =

sql_db = abstracts

sql_port = 5432

sql_query_pre =

#zapytanie filtrujące dane do indeksu

sql_query = \

SELECT profile_id, lower(“desc”) \

FROM profile

# zapytanie otwierające całą krotke w bazie danych

sql_query_info = SELECT * FROM profile WHERE profile_id=$id

}

index test1

{

source = src1

path = /var/db/sphinxsearch/data/test1

docinfo = extern

#obsluga slowników (np. stem_en – angielski)

morphology = none

stopwords =

min_word_len = 1

charset_type = sbcs

min_prefix_len = 0

min_infix_len = 0

}

indexer

{

mem_limit = 256M

}

searchd

{

port = 3312

log = /var/log/sphinxsearch/searchd.log

query_log = /var/log/sphinxsearch/sphinx-query.log

read_timeout = 5

max_children = 30

pid_file = /var/run/sphinxsearch/searchd.pid

# maxymalna ilosc dopasowanych krotek

max_matches = 5000

}

Po wygenerowaniu indexów należy odwołać się do nich w programie który budujemy. W php może wyglądać to następująco:

<?

require ( “sphinxapi.php” );

// ustawienie parametrów połączenia

$cl = new SphinxClient ();

$cl->SetServer ( ‘localhost’, ‘3312’ );

$cl->SetMatchMode ( SPH_MATCH_ALL );

// limit znalezionych krotek które nas interesują

$cl->SetLimits ( 0, 4999, 4999);

// zapytanie

$res = $cl->Query ($v,’fun’);

// zwrócenie ilości wierszy

echo „qty: „.$res[‘total_found’].”\n”;

reset($res[‘matches’]);

while(list($kk,$vv)=each($res[‘matches’]))

{

// wygenerowanie wyniku

}

?>

Konkluzje:

Plusy rozwiązania

  • kilkudziesięciokrotny wzrost wydaności

  • możliwość indexowania gotowych skomplikowanych zapytań

  • możliwość przeniesienia części obciążenia na inny serwer

  • możliwość wykorzystania słowników

  • łatwa konfiguracja

  • ograniczenie liczby indeksów używanych na oryginalnej bazie

Minusy rozwiązania

  • dodatkowa przestrzeń na dane na dysku i w pamięci (choć stosunkowo niewielka)

  • dane nie są generowane z bieżącej chwili

8 Responses to “Wydajność bazy danych, gdy silnik SQL już nie wyrabia.”

  1. pinki Says:

    Witam

    A czy nie lepiej użyć jakiegoś silnika do wyszukiwania? Ja używam Lucene. Wiesz może jakie są wady i zalety sphinx vs. np.: Lucene?

    Ale tak czy siak sprawdzę jak działa ten sphinx :)

    pozdr

  2. admin Says:

    http://jayant7k.blogspot.com/2006/06/benchmarking-results-of-mysql-lucene.html
    tutaj jest benchmark z 2006 roku choć od tego czasu wiele się mogło zmienić a autor nie do końca opisuje środowisko w jakim to robił. Wychodzi na to ze Lucene było troszkę lepsze.
    http://pagetracer.com/2008/02/15/sphinx-and-lucene-search-engines-first-impressions/
    ten artykuł jest bardziej odczuciem autora i twierdzi on że sphinx jest dużo łatwiejszy w implementacji, szybciej buduje index który zajmuje mniej miejsca a jego wydajność jest troche lepsza od lucene. Osobiście nie mam żadnych doświadczeń z lucene więc ciężko mi się wypowiadać.

  3. Antek Says:

    W PostgreSQL jest silnik tsearch. Bawiłem się z nim kiedyś i uważam, że działa wybornie.
    Ciekawi mnie jak sphinx – szczególnie morfologia – radzi sobie z językiem polskim.

  4. c3zi Says:

    Z tego co wiem to narazie nie radzi sobie z językiem polskim 😉 Jest chyba rosyjski oraz angielski do wyboru. Może jeszcze chiński …

  5. riklaunim Says:

    Sphinx jest wydajny i łatwy w implementacji i uruchomieniu. HyperEstraier, Solr-Lucene już nie tak łatwo – plus trzeba sprawdzać czy ma gotowe wsparcie dla języka polskiego :) Dla Postgresa jest też OpenFTS.

  6. orcus Says:

    TAk jak antek napisał w PostgreSql jest tsearch (w 8.3 już w dystrybucji a nie w contrib) i jest świetny. Dodam tylko ze tsearch obsługuje polskie słowniki.

  7. macijekiner Says:

    Do sphinxa mozna podpiac wordforms – slownik odmian. Mozna go wygenerowac np ze slownika OO. Z powodzeniem wykorzystuje to rozwiazanie w projektach ktore wspoltworzylem.

  8. tomek Says:

    a jak jest z wydajnoscia sphinx vs tsearch?

    z tego co wiem to np oraclowy full text search jest wolniejszy od lucene zarowna pod wzgledem szybkosci indeksowania jak tez wyszukiwania….

Leave a Reply

Preview: