• Home
  • STRONA ISOLUTION.PL
  • LOGOWANIE
  • POMOC

Eksperyment ze skalowaniem aplikacji WWW

Wojtek Paciorkowski | 04/01/2009

Pracowałem ostatnio nad prototypem architektury dla aplikacji WWW, która z racji bycia typowym portalem społecznościowym, stawia wysokie wymagania w kwestii wydajności i skalowania. Zadanie było bardzo ciekawe i ucieszyłem się na myśl, że to właśnie mojej osobie powierzono tak kluczowe zadanie.

Zbudowanie wydajnej i skalowalnej aplikacji dla szerokiego grona odbiorców nie jest łatwe. Pomijając zagadnienia funkcjonalne systemu, pozostaje do rozwiązania szereg problemów niefunkcjonalnych. Weźmy na przykład problem współbieżności, czyli jak wydajnie obsłużyć setki lub może tysiące przychodzących połączeń HTTP. Umówmy się, że sieć (nasze łącze do internetu) nie stanowi problemu, pozostaje zatem do rozwiązania problem sprzętowo-programowy.

Zakładając, że budowana aplikacja będzie dość standardową aplikacją trój-warstwową (prezentacja - logika - baza danych), zagadnienie współbieżności należy rozpatrywać w każdej z tych warstw z osobna.

Warstwa prezentacji

W warstwie prezentacji dużym ograniczeniem jest ilość wątków, które są w stanie efektywnie obsługiwać przychodzące żądania HTTP. Nawet w systemach wieloprocesorowych czy (co dziś bardziej popularne) wielordzeniowych nie można liczyć na to, że ta liczba będzie znaczna. Przekroczenie pewniej wartości krytycznej spowoduje to, że w naszym systemie moc obliczeniową zaczniemy marnować na przełączanie pomiędzy wątkami, zamiast ich realizację. Zakładając (wyssaną z palca wartość) 200 wątków na 4 rdzeniowej maszynie, przy użyciu Servlet API (czyli całkiem synchronicznego API) daje to 200 obsługiwanych połączeń w danej chwili. Dlaczego? Otóż dlatego, że w Servlet API każde połączenie jest wiązane na cały czas jego obsługi z 1 wątkiem. Jest to dość poważne utrudnienie, które skutkuje ograniczeniem przepustowości. Istnieją na szczęście dwie drogi rozwiązania problemu. Pierwsza, której nie będę tutaj opisywał, polega na rezygnacji z Servlet API na rzecz mniej standardowych implementacji protokołu HTTP (na przykład AsyncWeb, który pozwala zbudować warstwę GUI w oparciu o zdarzenia asynchroniczne) lub stosowaniu rozszerzeń Servlet API (na przykład konektory Grizzly wbudowane w Glassfish) które dodają obsługę Ajax oraz Comet.

Druga droga polega na relatywnie prostym i sprawdzonym rozwiązaniu, czyli horyzontalnym skalowaniu aplikacji. Skoro 1 serwer jest w stanie obsłużyć współbieżnie 200 połączeń dodajmy jeszcze 4 identyczne serwery i (w teorii) obsługujemy 1000 połączeń. Wystarczy jeszcze tylko dodać load-balancer i mamy gotowy klaster 5 serwerów. Tylko czy zawsze potrzebny jest klaster? Klastrowanie daje nam dwie zalety: równomierne rozłożenie obciążenia oraz obsługę sytuacji krytycznych (fail-over).

Ale klastrowanie ma też swoje wady. Podstawową z nich jest konieczność replikacji stanu aplikacji czyli sesji HTTP. To właśnie replikacja sesji HTTP umożliwia obsługę awarii (gdy jeden serwer ma awarię, możemy liczyć na inny serwer posiadający kopię sesji), ale jest też bardzo kosztowna i trudna w implementacji. Replikacja wymaga większej ilości pamięci (bo umówmy się, każda sesja musi się znaleźć na conajmniej 2 różnych maszynach) oraz wymaga kopiowania stanu za każdym razem gdy ulega on zmianie (a to łączy się z serializacją/deserializacją i przesyłem po sieci).

Skoro budowanie klastra jest takie kosztowne, a od budowanej aplikacji nie zależy ludzkie zdrowie (transport/energetyka) czy stan portfela (bankowość/handel), to możemy sobie pozwolić na rezygnację z klastrowania. Albo dokładniej, na rezygnację z obsługi sytuacji krytycznych. Taki uszczuplony klaster, który dostarcza tylko równomiernego rozkładania obciążenia na n serwerów, jest tańszy w realizacji i nazywany jest farmą serwerów. Jeśli któryś z serwerów w farmie ulegnie awarii, istnieje ryzyko że kilkudziesięciu, może kilkuset użytkowników będzie musiało się zalogować ponownie do aplikacji oraz że spadnie przepustowość całego systemu, ale my możemy taki stan rzeczy zaakceptować.

Warstwa logiki biznesowej

W warstwie logiki biznesowej problemy są podobne jak w warstwie prezentacji i skupiają się wokół zarządzania wątkami i znanej już zasady o ich liczbie krytycznej. Dodatkowym problemem staje się umiejscowienie tej warstwy w aplikacji. Według starej szkoły J2EE taka warstwa byłaby zaimplementowana w oparciu o zdalne komponenty EJB i osadzona na innej grupie serwerów niż te 5 z warstwy prezentacji. Brzmi kusząco, bo znów można zbudować klaster, który dostarczy rozłożenia obciążenia i obsługi awarii właśnie w warstwie zdalnych wywołań EJB. Ale jeśli się temu przyjrzeć z bliska wyraźnie widać, że koszt jest niewspółmiernie duży w stosunku do korzyści jakie ten klaster może przynieść.

Marting Fowler zdefiniował Pierwsze Prawo Obiektów Rozproszonych , które brzmi: nie rozpraszaj swoich obiektów. Dlaczego? Ponieważ wymagają zwiększonych zasobów na realizację rozproszonej komunikacji: serializację/deserializację i transfer po sieci. W efekcie zmniejsza się przepustowość aplikacji, gdyż każdy wątek w warstwie prezentacji musi w chwili wywołania zdalnego do warstwy biznesowej poczekać, aż w tej warstwie zakończy się przetwarzanie i sterowanie powróci do warstwy prezentacji. A każdy zablokowany wątek jest wątkiem zmarnowanym.

Więc co w zamian? Architektura kolokowana, czyli osadzenie warstwy biznesowej na tych samych serwerach co warstwa prezentacji i komunikacja po lokalnych interface. Osiągnąć to można przez stosowanie lokalnych interface’ów EJB, albo najzwyklejszych POJO uruchamianych w dowolnym kontenerze IoC/DI. Dzięki temu architektura aplikacji znacząco się upraszcza bez konieczności rezygnacji z rozkładania obciążenia, które już mamy zaimplementowane w warstwie prezentacji.

Warstwa danych

Skoro w dwóch pierwszych warstwach problem skalowania i wydajności został wstępnie rozwiązany, czas znaleźć takie rozwiązanie w warstwie danych. Nie od dziś wiadomo, że bazy danych są najczęstszym wąskim gardłem w systemach współbieżnych.

We wspomnianym na początku systemie odgórnie narzucona została implementacja bazy danych, a wybór klienta padł na MySQL 5. Wiadomo, darmowa baza, open source, no i od niedawna produkt Sun’a. Czy to dobry wybór? I tak i nie. Z jednej strony jest to baza która znajduje zastosowanie w dużych systemach i nosi cechy przystosowania do wysokich wymagań (obsługa transakcji rozproszonych XA, wbudowana i relatywnie prosta w konfiguracji replikacja) z drugiej strony boryka się z problemami współbieżności, co uwidacznia się w momencie, gdy wyślemy na bazę wiele równoległych zapytań modyfikujących dane.

Jak można temu zaradzić? Jednym z pomysłów, które testowałem w prototypie, jest mechanizm ręcznego uszeregowania transakcji zapisujących, a dokładniej mówiąc, ograniczenia ilości współbieżnych zapisów przez zastosowanie kolejkowania. Pomysł polega na tym, aby wszystkie transakcje zapisujące wysłać na kolejkę JMS, gdzie parametryzowalna ilość odbiorców komunikatów realizowałaby zapisy. Dodatkowo, zapisy będą realizowane na jednej instancji bazy, zwanej Master, a odczyty na wielu replikach zwanych Slave. Replik może być nawet tyle ile serwerów w farmie warstwy prezentacji/biznesowej, co pozwoli realizować dość szybko odczyty, natomiast Master byłby jeden i łączność z nim będzie realizowana przez jeden serwer realizujący transakcje zapisujące.

Podsumowując, wszystkie odczyty będą realizowane tradycyjnie w warstwie biznesowej (po lokalnych interface’ach), natomiast zapisy będą realizowane na zdalnym serwerze z komunikacją po JMS, co pozwala sterować ilością współbieżnych odbiorców i wprowadzać ewentualne zapasowe serwery zapisujące.

Na koniec

W kolejnych artykułach zamierzam opisać:

  • pełną architekturę rozwiązania
  • konfigurację replikacji MySQL
  • implementację trasowania transakcji odczytujących/zapisujących
  • implementację zdalnego wywoływania metod po JMS
  • sposoby testowania wydajności opisanego rozwiązania

Categories
Aplikacje Web, Architektura, Bazy danych
Tags
Architektura, JEE, skalowanie
Comments rss
Comments rss
Trackback
Trackback

« GWT (AJAX) for Isolution Workflow Optymalizacja pracy systemu bazodanowego (na przykładzie IBM DB2) »

12 responses

Witam, nie wiem co prawda, na jaką ilość użytkowników planowana

Piotr Maj Ubuntu Linux Mozilla Firefox 3.0.5 | 05/01/2009

Witam, nie wiem co prawda, na jaką ilość użytkowników planowana jest aplikacja i jaka będzie charakterystyka przetwarzanych danych, jaka będzie dynamika przyrostu liczby użytkowników (właściwie bardzo mało wiem ;), chciałbym jednak wskazać kilka rzeczy, które, moim zdaniem, nie służą skalowaniu proponowanego rozwiązania.

1. Logika biznesowa

Rozwiązanie polegające na połączeniu logiki biznesowej z warstwą prezentacji uważam za niedobre, a wręcz złe. Dlaczego?

Co z deploymentem nowej wersji warstwy biznesowej? Sesje HTTP w proponowanym rozwiązaniu nie są replikowane, więc każdy upgrade farmy (np. załatanie buga) będzie powodował wylogowanie wszystkich użytkowników. Proponowane rozwiązanie jest po prostu niepraktyczne. Restart warstwy usług nie powinien w żaden sposób wpływać na widok.

Architektura kolokowana jest, moim zdaniem, dobra do wieloetapowego przetwarzania wsadowego, jeśli obiekty przesyłane między kolejnymi etapami są na tyle duże, że koszt ich transportu jest nieuzasadniony.

W przypadku serwisów internetowych, nazwijmy je Web 2.0, dużo lepiej sprawdza się stworzenie warstwy biznesowej w duchu SOA, czyli dedykowanych maszyn świadczących usługi na rzecz serwerów webowych w formie bezstanowej, a więc łatwej do skalowania.

2. Warstwa danych

Problem z jednym masterem jest taki, że zawsze uderza się w sufit (a to z I/O, a to z CPU, a to z wielkością bazy). Kolejkowanie zapisów rozwiązuje jeden problem, ale powoduje co najmniej 4 następne:

- nie masz gwarancji, kiedy slave, z którego czytasz, zobaczy dane (w przypadku serwisu społecznościowego problem dość poważny, bo w momencie wzmożonej intensywności pracy użytkowników właściwie nikt nie zobaczy danych w rozsądnym czasie - znowu, jeśli projekt okaże się sukcesem),
- kolejka taka to dodatkowy komponent do administracji, z własną bazą, replikacją, klastrami (bo żaden zapis nie może zginąć!), a więc dodatkowy operacyjny koszmar,
- części operacji nie można (nie powinno się) robić wsadowo: np. zmiana hasła, uprawnień, blokowanie użytkownika,
- nie wiadomo od razu, czy wkładane do bazy dane są dobre - jeśli nie są to użytkownik nie ma jak zareagować, bo nie dostaje natychmiastowej informacji, że coś jest nie tak.

Przykład dużych, działających od lat serwisów społecznościowych uczy, że jest tylko jedyna słuszna droga na skalowanie takiej bazy danych i jest to sharding. Sharding ma tą przewagę nad 1:master-N:slaves, że daje wiele jednoczesnych punktów zapisu i tym samym umożliwia niemal nieograniczone skalowanie. Oczywiście zapanowanie nad danymi w shardach, gdzie nie ma zawsze mamy klucze obce, czy transakcje itp., to już inna historia.

To moje 2 grosze. Dużo inspiracji w tej materii można znaleźć pod adresem: http://highscalability.com/ - polecam ten serwis, jest to niesamowite źródło praktycznej wiedzy w zakresie skalowania aplikacji.

pozdrawiam
piotr

Moje 3 grosze, z wieczora: 1) "Restart warstwy usług nie powinien w

saren Ubuntu Linux Mozilla Firefox 3.0.4 | 07/01/2009

Moje 3 grosze, z wieczora:

1)
“Restart warstwy usług nie powinien w żaden sposób wpływać na widok.” - to brzmi bardzo poważnie, ale, moim skromnym zdaniem, jest argument czysto akademicki. Jak często będziesz miał w aplikacji typu portal społecznościowy modyfikacje logiki biznesowej bez modyfikacji warstwy prezentacji? Ok, pewna część przypadków załatania błędu tak; ale tylko _niewielka_ część.
Poza tym, w portalach społecznościowych, w sesji http raczej nie przechowujemy więcej niż dane autoryzacyjne - musimy wiedzieć z kim rozmawiamy, i tyle. W tej sytuacji nietrudno sobie wyobrazić mechanizm replikacji tak uszczuplonej sesji między klientami - choćby przy pomocy starego dobrego cookie i synchronizacji id sesji na poziomie bd.
Oczywiście zwiększamy narzut na bazę - ale i tak [zazwyczaj] w tego typu serwisach prezentujemy informację o innych użytkownikach zalogowanych/niezalogowanych; więc i tak musimy przenieść to przez bazę danych.

2)
Sharding, czy jak inni wolą horizontal partitioning jest fajny w zastosowaniach typu flickr czy nasza-klasa, gdzie większość obrabianych danych jest w sposób oczywisty związana z klientem/użytkownikiem i nie ma złożonych zapytań wyszukujących dane od potencjalnie wszystkich użytkowników. W przypadku aplikacji Wojtka niestety krytyczne są bardzo wyszukiwania nietrywialnie przeszukujące dane z profili wszystkich użytkowników; sharding by je zabił.

3) “- części operacji nie można (nie powinno się) robić wsadowo: np. zmiana hasła, uprawnień, blokowanie użytkownika,
- nie wiadomo od razu, czy wkładane do bazy dane są dobre - jeśli nie są to użytkownik nie ma jak zareagować, bo nie dostaje natychmiastowej informacji, że coś jest nie tak.”

Kolejki to nie tylko komunikacja asynchroniczna, wybrane zapisy można wysyłać synchronicznie, regulować kolejność ich realizacji priorytetami. To ofc nie rozwiązuje wszystkich potencjalnych problemów (sufit jest zawsze), ale pozwala ten sufit podnieść.

Podsumowując, wydaje mi się że rozwiązanie Wojtka się broni, nie jest idealne ale takiego nie ma.
Oczywiście, jest mi łatwiej komentować, bo lepiej znam wymagania aplikacji.

pozdrawiam
Marcin

Moje kolejne 4 grosze: 1) Restart samej warstwy usług może i

Piotr Maj Ubuntu Linux Mozilla Firefox 3.0.5 | 20/01/2009

Moje kolejne 4 grosze:

1) Restart samej warstwy usług może i jest rozważaniem akademickim (choć z mojego doświadczenia wynika, że występuje dość często w fazie skalowania systemu i optymalizacji).

Dużo większą wadą tego połączenia jest to, że od razu zabieracie sobie możliwość skalowania tych dwóch warstw oddzielnie. Takie combo będzie się skalować wprost proporcjonalnie do najcięższego komponentu. Jeśli warstwa usług biznesowych przestanie się wyrabiać, to trzeba będzie dołożyć do farmy
dodatkowy serwer, który będzie tylko w części wykorzystany przez owe usługi, bo część maszyny będzie zajęta przez “fronty” (których np. wcale więcej nie potrzeba).

2) Ciężkie wyszukiwanie wg różnych kryteriów czasem lepiej jest zrobić w oparciu o dedydowaną usługę, np. Lucene z indexem zoptymalizowanym do tego typu przeszukiwań.

Oczywiście wszystko jest kwestią skali, do jakiegoś momentu zadawanie ciężkich zapytań do bazy w zupełności wystarczy i w sumie jest to bardzo dobre rozwiązanie na start. Optymalizację można zostawić na później.

Tak w ogóle to cieszę się bardzo, że podjęliście temat skalowalności - niewiele się w Polsce pisze na ten temat. Mam nadzieję, że podzielicie się również swoimi doświadczeniami z implementacji tegoż rozwiazania.

–
pozdrawiam
piotr maj

Teraz ja:) AD 1) Zależy, co jest kluczowe: pamięć czy

Marcin Sarniak Ubuntu Linux Mozilla Firefox 3.0.5 | 28/01/2009

Teraz ja:)

AD 1) Zależy, co jest kluczowe: pamięć czy procesor.

Jeśli procesor to nie ma znaczenia czy mam 10 maszyn na web i 90 na serwisy, czy 100 maszyn które równo dzielą między siebie 10% obciążenia web, 90% obciążenia serwisów.

Jeśli pamięć, to znowu zależy jaka jest charakterystyka zużycia pamięci naszego serwisu. Załóżmy, że jest liniowo zależna od ilości żądań (oczywiście, niektóre żądania mogą być lekkie, inne ciężkie, przyjmujemy tu żądanie uśrednione). Wprowadźmy sobie wzór:

mem = ż * (aw + au) + bw + bu ;-)

mem - ilość użytej pamięci
ż = ilość żądań
aw = wielkość pamięci używana przez warstwę web na obsługę jednego żądania uśrednionego
au = analogiczne dla aw, dla warstwy usług
bw = wielkość stała pamięci zużywana przez warstwę web
bu = jak wyżej, dla warstwy usług
;-) = symbol wskazujący, że powyższy wzór nie powinien być traktowany zbyt serio

I teraz tak: jeśli bu i bw są względnie małe (tzn. pamięć zajęta przez classloader itp. jest względnie mała): to nadal nie ma znaczenia, czy możemy rozdzielić usługi od web, czy nie: w obu przypadkach obsługa jednego requestu zajmuje pewną stałą ilość zasobów (aw + au) i podobnie jak w przypadku procesora - rozdzielenie tego na różne grupy komputerów nic nie zmienia.

Jeśli bw i/lub bu są względnie duże to oczywiście Twoje rozwiązanie zaczyna mieć przewagę. Kiedy bw i bu będą względnie duże? Kiedy będziemy chcieli stosować jakieś kesze itp. Czy w tym wypadku Wojtek planował ich stosowanie? Nie wiem:)

AD 2)
Tu nie chodzi o wyszukiwania pełnotekstowe czy temu podobne. To coś jak znalezienie wspólnych znajomych 4-tego stopnia (czyli ja znam X, X zna Y, Y zna Z, Z zna Ciebie) tyle że dużo bardziej skomplikowane i niestety bardzo dynamiczne - tak że odpadają rozwiązania preindeksujące dane. Nie chce mi sie wchodzić w szczegóły, w każdym razie to, o ile znam lucene, compas itp to nie jest ta bajka.

pozdrawiam
Marcin

zyraweg... Ashley Leggat Nude Pictures ...

zyraweg Windows XP Mozilla Firefox 3.0.10 | 27/08/2009

zyraweg…

Ashley Leggat Nude Pictures …

xyzyluzo... donnie baker pics ...

xyzyluzo BRAZIL Windows XP Mozilla Firefox 3.0.10 | 25/09/2009

xyzyluzo…

donnie baker pics …

< blockquote >< a href="http://medicamentspot.com/">Medicamentspot.com. Canadian Health&Care.No prescription online pharmacy.Best

CHRISTIAN | 21/07/2010

< blockquote >< a href=”http://medicamentspot.com/”>Medicamentspot.com. Canadian Health&Care.No prescription online pharmacy.Best quality drugs.Special Internet Prices. No prescription drugs. Buy pills online< /a >…

Buy:Retin-A.Human Growth Hormone.Petcam (Metacam) Oral Suspension.Mega Hoodia.Prednisolone.Prevacid.Arimidex.Lumigan.Zyban.100% Pure Okinawan Coral Calcium.Nexium.Actos.Zovirax.Accutane.Valtrex.Synthroid….

friendly http://jfriendly259.AUTOPARTSTHAI.INFO/tag/Wonderflex+Plastic+plastic+friendly/ : Plastic... Wonderflex...

Wonderflex Mac OS X Safari 525.27.1 | 29/08/2010

friendly http://jfriendly259.AUTOPARTSTHAI.INFO/tag/Wonderflex+Plastic+plastic+friendly/ : Plastic…

Wonderflex…

Kitchen http://agrillz-lyqd.ANTIQUEFURNINISHING.INFO/tag/Kitchen+electric+Cooking/ : electric... Kitchen...

Kitchen Ubuntu Linux Mozilla Firefox 3.0.6 | 29/08/2010

Kitchen http://agrillz-lyqd.ANTIQUEFURNINISHING.INFO/tag/Kitchen+electric+Cooking/ : electric…

Kitchen…

Furniture http://oteatjvnbey.05KIAPARTS.US/tag/Starting+an+Business+sale+Furniture/ : Furniture... an...

Furniture Windows XP Internet Explorer 6.0 | 29/08/2010

Furniture http://oteatjvnbey.05KIAPARTS.US/tag/Starting+an+Business+sale+Furniture/ : Furniture…

an…

downtown http://hpatioojamu.AWESOMEBABYCLOTHES.INFO/tag/shops+cruz+downtown/ : shops... cruz...

shops Mac OS X Safari 525.19 | 29/08/2010

downtown http://hpatioojamu.AWESOMEBABYCLOTHES.INFO/tag/shops+cruz+downtown/ : shops…

cruz…

Cartridges http://xlights9nzlr0l.03GMCPARTS.US/tag/hp+Cartridges+Epson/ : hp... Epson...

hp Ubuntu Linux Mozilla Firefox 3.0.5 | 30/08/2010

Cartridges http://xlights9nzlr0l.03GMCPARTS.US/tag/hp+Cartridges+Epson/ : hp…

Epson…

Leave a comment

You can use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

Navigation

  • Aplikacje Web
  • Architektura
  • Bazy danych
  • EJB
  • Narzędzia
  • Spring
  • Testowanie
  • UML
  • WEB Service
  • XML

Search

rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox