Blog Departamentu IT Onet.pl
System sesji w Onet.pl
Sesje
HTTP to podstawowy protokół komunikacyjny wykorzystywany w sieci Internet. Jego największą zaletą jest niewątpliwie prostota, która jednak komplikuje realizację niektórych zadań. Jednym z nich jest przekazanie informacji o użytkowniku pomiędzy kolejnymi żądaniami. Przez lata wymyślono kilka sposobów rozwiązanie tego problemu, a najpopularniejszy z nich to tzw. sesje. Składa się na niego wewnętrzny system do przechowywania danych wraz z identyfikatorem sesji (ang. session id, sid), który pozwala pobrać zapisane wcześniej dane sesyjne. O ile w przypadku identyfikatora obecnie standardem jest przekazywanie go pomiędzy kolejnymi żądaniami z wykorzystaniem mechanizmu ciasteczek (ang. cookies), o tyle rozwiązań wspomagających przechowywanie danych sesyjnych po stronie serwera jest wiele. Najprostsze z nich wykorzystują pliki zapisane na dysku twardym serwera, bazę danych albo pamięć operacyjną. Bardziej zaawansowane systemy łączą trwałość zapisu danych na dysku, z szybkością dostępu do pamięci RAM. W niniejszym artykule zostaną omówione wady i zalety dotychczasowego system obsługi sesji w Onet. oraz zostanie przedstawiony jego następca.
System sesji w Onet
Przez ostatnie lata w portalu funkcjonował mechanizm oparty o serwery aplikacyjne napisane w C++ i korzystające z Memcached oraz MySQL. Dane mogły być składowane w pamięci (co jest szybkie) albo, gdy wymagały większej trwałości, w bazie danych (ale to rozwiązanie było oczywiście dużo wolniejsze). Dodatkowo sesje były rozdzielone pomiędzy różne przestrzenie nazw, a cały system miał zapewniony mechanizm automatycznej zmiany konfiguracji w przypadku awarii jednego z serwerów, tak aby zapewnić ciągłość działania (ang. failover). Niestety oprócz problemów wydajnościowych borykaliśmy się z ograniczonymi możliwościami w zakresie skalowania, utrzymania i rozwoju, co było wynikiem dużego stopnia skomplikowania całego rozwiązania.

Nowe rozwiązanie
W czasie prac nad nowym rozwiązaniem sesyjnym przyjęliśmy założenie, że dane zawarte w sesjach użytkowników nie są krytyczne, zaś najważniejsza jest szybkość działania, skalowanie i łatwe utrzymanie. Swoją uwagę skupiliśmy na nowoczesnych nierelacyjnych systemach bazodanowych (tzw. NoSQL), które oferują dużą różnorodność i lepsze dopasowanie do konkretnych potrzeb.
Podczas pracy nad nowym systemem sesji zostały wzięte pod uwagę bazy: CouchDB, Project Voldemort, MongoDB, Redis.
Wybrane cechy porównywanych baz danych:
| Voldemort | CouchDB | MongoDB | Redis | |
| Język | Java | Erlang | C++ | C |
| Trwałość danych | poprzez pluginy: BerkleyDB Mysql |
dysk: własny format | dysk: własny format | dysk: własny format, asynchroniczne zapisywanie zmian do append-only file |
| Model danych | blob/text | dokument, JSON |
dokument, binarny JSON |
klucz-wartość, lista, zbiór |
| Typ danych | serializowany | różne | różne | różne |
| Replikacja | master-master (trzeba obsługiwać ew. konflikty) |
master-master (trzeba obsługiwać ew. konflikty) |
master – slave (możliwa replikacja master-master, jednak problemy gdy występują jednoczesne zapisy) |
master-slave |
| Partycjonowanie | wbudowane | nie | faza alfa (2010) | nie |
| Interfejs | JAVA API | REST | natywne, biblioteki dla różnych języków | natywne, biblioteki dla różnych języków |
| Zapewnienie spójności |
wersjonowanie, read-repair |
MVCC | atomowe operacje na dokumentach | jeden wątek bazy danych – wszystkie operacje są atomowe |
| Kto za tym stoi? | LindedIn | Apache | 10gen | Salvatore Sanfilippo (aka antirez), projekt sponsoruje vmware |
Wydajność części rozwiązań była niezadowalająca, inne nie posiadały wyraźnej przewagi nad pozostałymi. Ostateczny wybór padł na Redis, wydajną bazę klucz-wartość przechowującą dane w pamięci. Redis zapewnia replikację, separację danych w ramach osobnych przestrzeni nazw oraz replikację danych na dysk twardy. Ważnym czynnikiem wyróżniającym Redisa na tle innych rozwiązań jest zastosowanie mechanizmu „append-only file”, tj. zapisywanie informacji o zmianach na końcu pliku, dzięki czemu jest w stanie zapewnić wysoką wydajność.
Mając wybrany mechanizm przechowywania danych przygotowaliśmy serwer aplikacyjny umożliwiający zarządzanie sesjami. Do komunikacji wykorzystaliśmy wzorzec REST, logikę zaimplementowaliśmy w języku Python z wykorzystaniem serwera Tornado, a dystrybucję zapytań na dwa serwery zapewnia nginx. Praca Redisa w trybie master-slave oraz skrypty przełączające ruch na działający serwer w przypadku awarii jednego z nich zapewniły nam odporność na awarie.

Ewolucja: Membase
Po pewnym czasie dały zauważyć się słabości nowego systemu. Redisem można było zarządzać tylko przez autorski interfejs, nie mieliśmy automatycznej klastrowalności. Aby zwiększyć wydajność systemu, po stronie tornado potrzebne by było napisanie warstwy zapewniającej partycjonowanie poziome – zapisywanie danych z tej samej przestrzeni nazw do różnych instacji bazy (ang. sharding).
Naprzeciw tym słabościom wychodzi Membase, baza klucz-wartość która ma możliwość zapisu danych na dysk (w przeciwieństwie do Memcached). Wspiera klastrowalność ze zmianą ilości serwerów w czasie działania, zapewnia odporność na awarię jednego z serwerów oraz ma gotowy interfejs administracyjny z monitoringiem wydajności. Implementacja pierwszej wersji systemu w języku Python pozwoliła na łatwą podmianę warstwy przechowywania danych na Membase.

Wydajność
Porównanie przepustowości(ilość zapytań na sekundę) systemów sesji, w pojedyńczej konfiguracji produkcyjnej, dla średniego obciążenia 25% procesorów:

Tornado z Redisem zapewnia o wiele lepszą wydajność niż bardziej skomplikowany system oparty o MySQL. Jednak nie należy wnioskować z tego, że Redis jest lepszą bazą niż MySQL. Te dwa systemy spełniają różne wymagania, ten oparty o relacyjną bazę danych ma dużo wyższe parametry bezpieczeństwa przechowywania danych. Sesje oparte o Redis dzięki mniejszej ilości operacji dyskowych mogą mieć wyższą wydajność.
Różnica w wydajności pomiędzy sesjami opartymi o Redis i Membase, również bierze się z różnych wymagań jakie spełniają te systemy. Architektura Membase pozwala na łatwe zwiększenie wydajności klastra oraz łatwą administrację systemem, przez co ma nieco mniejszą przepustowość. Można sobie wyobrazić sytuację, żeby podobne rozwiązanie zaimplementować dla Redisa, jednak nie wiadomo czy dałoby to większą wydajność, natomiast zwiększyłoby znacznie koszt całego projektu.
Podsumowanie
Ewolucja systemu sesji w Onet pokazuje, że nawet prosty funkcjonalnie system może stać się bardzo skomplikowany, jeżeli jest potrzeba zapewnienia odporności na awarię i łatwości administracji. Wymyślanie koła na nowo to dodatkowy koszt, lepiej skorzystać z gotowych rozwiązań OpenSource, wykorzystując elementy, które mają zapewniony ciągły rozwój. Integracja gotowych rozwiązań pozwoliła na szybkie zbudowanie nowego systemu sesji. Podział na moduły daje łatwość wymiany pojedynczego komponentu bez ingerowania w pozostałe części, dzięki czemu podmiana silnika bazy klucz-wartość była stosunkowo prostą do wykonania operacją. W wyniku ciągle prowadzonych prac optymalizacyjnych udało się zastąpić stary i skomplikowany system nowym, bardziej wydajnym, który dobrze się skaluje i jest łatwy w administracji.
Marcin Wróbel
programista
Powiązane notki:
| Drukuj artykuł | Ten wpis został napisany przez IT@Onet na 30.09.2011 o 08:00, i jest w kategorii DreamLab. Podążaj za odpowiedziami do tego wpisu przez RSS 2.0. Możesz napisać komentarz, lub trackbacka z Twojej własnej strony. |