Skalowanie RoR
Posted by Jarosław Zabiełło Sun, 06 Aug 2006 12:54:00 GMT
Mit o rzekomej niskiej wydajności Railsów wydaje się być przesadzony. Interpreter Rubiego jest co prawda wolniejszy od interpretera Pythona (i tym samym Django jest szybsze od Railsów). Ale już porównanie Django, Railsów i pehapowego Symphony pokazuje że Rails jest wyraźnie szybszy od Symphony (który używa PHP5 i akceleratora!). Skoro PHP jest wolniejszy, to z szybkością Railsów nie jest aż tak źle, prawda? Ale to nie wszystko, Rails posiada wygodny mechanizm który pozwala bez trudu powalić na kolana typową aplikację Django.
Siła skalowania poziomego.
Gdy mamy na myśli wydajność całej aplikacji to nie sposób pominąć ważny jej element: skalowalność. Aplikację webową można skalować pionowo (dokładając więcej RAM’u, mocniejszy procesor) lub poziomo (dokładając po prostu kolejny serwer). Ta ostatnia opcja jest szczególnie interesująca, bo dołożenie mocniejszego procesora nie można ciągnąć bez końca.
Ruby on Rails świetnie skaluje się poziomo. Zamiast klasycznego zestawu Lighttpd + kilka procesów fasctgi polecam znacznie lepszy zestaw oparty na procesach mongrel.
Scenariusz 1:
Lighttpd na froncie obsługuje wszystkie statyczne pliki. Pozostałe kieruje do Pound (szybkiego i lekkiego load balancera1), który z kolei kieruje ruch do kilku procesów mongrela (każdy z nich może być nawet na innej maszynie).
Scenariusz 2:
Apache 2.2 na froncie z wbudowanym modułem load balancera rozkłada ruch na kilka procesów mongrela.
Przykład.
Zakładam, że użyję Lighttpd + Pound + 4 procesy mongrela z rozłożonym ruchem na 2 serwery. Fragment pliku konfiguracyjnego dla serwera Lighttpd:
$HTTP["host"] == "domena.host" {
$HTTP["url"] !~ "^/(cgi-bin|images|stylesheets|javascripts)" {
proxy.server = ( "/" => ( ( "host" => "127.0.0.1" , "port" => 9000 ) ))
}
server.document-root = "/home/httpd/domena.host/public"
server.indexfiles = ("dispatch.fcgi")
server.error-handler-404 = "/dispatch.fcgi"
}Lighttpd obsługuje wszystkie pliki statyczne. Robi to wyjątkowo szybko, lepiej niż Apache. Cały pozostały ruch jest spięty za pomocą proxy z procesem na porcie 9000. Na tym porcie będzie nasłuchiwał Pound, który zajmie się rozkładaniem ruchu na pozostałe serwery. Plik konfiguracyjny dla Pound’a może wyglądać:
User "nobody"
ListenHTTP
Address 0.0.0.0
Port 9000
Service
BackEnd
Address 127.0.0.1
Port 9001
End
BackEnd
Address 127.0.0.2
Port 9002
End
BackEnd
Address 127.0.0.3
Port 9003
End
BackEnd
Address 127.0.0.4
Port 9004
End
End
EndPozostało tylko uruchomić mongrela. Po zainstalowaniu (gem install mongrel), przechodzimy do folderu z naszą aplikacją railsów i odpalamy
mongrel_rails cluster::configure -e production \
-p 9000 -N 4 -c /opt/ror/mojprojekt -a 127.0.0.1 \
--user mongrel --group mongrel (Parametr -a chroni nas przed możliwością zewnętrznego odpalenia w przeglądarce Railsów działającej bezpośrednio na którymś z procesów mongrela).
Powinien powstać plik: config/mongrel_cluster.yml
---
port: "9000"
environment: production
address: 127.0.0.1
pid_file: log/mongrel.pid
servers: 4Cluster odpalamy za pomocą
mongrel_rails cluster::startDodatkową zaletą używania mongrela jest możliwość wygodnego restartowania dowolnej aplikacji Railsów (a można ich mieć przecież wiele) bez konieczności restartowania serwera HTTP (mongrel_rails cluster::restart)
Poza tym mongrel świetnie nadaje się do zastąpienia Webricka, standardowego serwera HTTP zalecanego do tej pory do pracy developerskiej. Zamiast
ruby script/servermongrel_rails startDomyślnie podniesie się serwer HTTP na porcie 3000 i w trybie development (czyli identycznie jak Webrick). Mongrel jest jednak znacznie szybszy!
Dla użytkowników windozy też jest dobra wiadomość. Mongrel można zainstalować jako usługę windowsów i zarządzać standardowo tak jak inne usługi. Można np. odpalić sobie na jednym porcie Rails w trybie produkcyjnym, a na drugim – w trybie developerskim. W tym drugim wypadku nie trzeba restartować serwera bo zmiany w kodzie automatycznie przeładowują serwerek (tak jak Webrick)
Oczywiście to wszystko ślicznie działa z Capistrano, railsowym systemem automatycznie synchronizującym zmiany na n-serwerach.
Jak dla mnie, mongrel wnosi nową jakość do pracy z Railsami i warto przyjrzeć się mu dokładniej. Nie zdziwiłbym się, jakby następne wersje Railsów standardowo zalecały używanie mongrela, a nie Webricka.
Tak jak siłą Google są tysiące mniejszych maszyn a nie jedna – super szybka, tak nawet najszybszy serwer wyposażony w Apache i mod_python (który używa domyślnie Django) nie ma szans w starciu z clusterem Railsów opartym na procesach mongrel i korzystających z kilku serwerów.

Wykres z artykułu Scaling Rails with Apache 2.2, mod_proxy_balancer and Mongrel
-
1 Dlaczego nie wykorzystywany jest load balancer wbudowany w Lighttpd? Bo jest kiepsko zaimplementowany i są problemy z restartem procesów. Dlatego zalecany jest zewnętrzny load balancer lub użycie najnowszej wersji Apache 2.2 który ma ten moduł dobrze zaimplementowany.


Kanały IRC![[Dilber w Onecie]](/images/larry.png)


Ponoć pen jest szybszy od pounda, z drugiej strony ten drugi jest wygodniejszy. W gemie Mongrela znajdują się dodatkowe recipes do capistrano plus skrypt startowy system V – wystarczy podlinkowac.
oops, w gemie mongrel_cluster
Muszę zobaczyć ten skrypt startowy. Nie wiedząc o tym, napisałem go sobie od zera. :)
Tutaj jest fajne howto: http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/ ;)
lighttpd w trunku svn’a posiada juz poprawna obsluge proxy, czyli dziala prawidłowo jako load balancer. Nie napisałeś jak dokładnie rozwiązać sprawę wysyłania statycznych stron do lighttpd. :) (Tutaj link ze szczegółami)
Ależ napisałem. Przyjrzyj się dokładnie:
Ten wpis mówi, że jeśli w url NIE występuje na początku żadne ze słów: cgi-bin, images, stylesheets czy javascripts, to wtedy ma przekazywać request do load balancera. Wszystkie inne requesty mają być obsługiwane przez Lighttpd (czyli ze ścieżki document.root)
Co do lighttpd i svn, to wolę poczekać na wersję oficjalną.
To, że Symphony jest wolny, nie znaczy, że PHP jest wolniejszy od Rubiego (jest oczywiście odwrotnie). Zupełnie błędny i mylący czytelników wniosek!
a YARV się bardzo szybko rozwija ;)
Chciałem jedynie wskazać język CML używany w Lighttpd jakos mod_cml i zarządzanie keszowanymi statycznymi stron (page cache) które Railsy generują. Ale oczywiście można i tak jak napisałeś powyżej, żeby keszować tylko images/javascripts/stylesheets
To, że Symphony jest dużo wolniejszy od Railsów nawet z włączoną akceleracją to coś jednak oznacza (albo Symphony jest bardzo źle napisane albo w PHP nie da się pisać szybkich skomplikowanych systemów – osobiście skłaniam się do tego drugiego wniosku).
Co do Rubiego i PHP – pewnie poszczególne funkcje PHP w porównaniu z odpowiednikami w Rubim są szybsze. Tylko komu zależy na pojedynczych funkcjach ? Zawsze można skorzystać z RubyInline dla jakiegoś krytycznego fragmentu kodu i napisać implementację w C :)
a to się w Rubym robi bajecznie prosto nawet bez swiga ;)
Na poczatku tez mialem podobna konfiguracje. Mialem problemy z lighttpd mod_proxy i fast_cgi i rozwiazalem to nieco inaczej. Dzieki dobremu przykladowi z sieci. Jak znajde to wrzuce tutaj.
Postawilem pound na 80 z BACK ENDami na 9000-4, nastepnie mongrel_cluster 9000-4 I wszystko dziala bez lighttpd.
Jesli chodzi o lighttpd(bez proxy) to uzywam go do lzejszych statycznych spraw.
Co myslicie o tym?
Dodam jeszcze, ze w pound.cfg to mam na samym koncu.
Service BackEnd Address 127.0.0.1 Port 3000 End End
Dzieki temu reszta zostaje przekierowana na port 3000 na ktorym jest lighttpd, ktory obsluguje wszystko co statyczne.
Zalozenie Pound jest byc na froncie i obslugiwac i filtorwac bezpiecznie http/https oczywiscie z balansowaniem. Taki szybki i zreczny doktor/mechanik :)
A ja z innej beczki. Jakiego softu uzyles do stworzenia tego diagramu? Wyglada to naprawde znakomicie i ciekaw jestem czy to cos komercyjnego czy jakos open-source.
W ogólne nie tworzyłem, podlinkowałem dynamicznie obrazek z angielskiego artykułu.