Szybszy, asynchroniczny Mongrel z EventMachine lub Swiftiply

Opublikowane przez Jarosław Zabiełło Mon, 24 Dec 2007 13:21:00 GMT

Dużo się zmieniło od czasu zalecania używania Railsów w trybie FastCGI. To się nie sprawdziło i miejsce zestawu Lighttpd + FastCGI zajął Apache2/Nginx + proxy do Mongrel clustera. Z Mongrel clusterem jest jednak problem, że nie działa poza systemami uniksowymi. Poza tym udało mi się zaobserwować kilka razy pewną niestabilność dla mongrel clustera: czasami pojedynczy Mongrel się zawiesi i trzeba restartować cały ich klaster. Większą stabilność i dużo większą wydajność (szczególnie przy wielu równoległych żądaniach) zapewniać Mongrel działający z Swiftiply lub z EventMachine.

Swiftiply

Swiftiply jest reklamowany jako klasterowy proxy dla aplikacji internetowych. Korzysta z trwałych połączeń z klientami i można go skalować bez zmian w konfiguracji i restartów. Po prostu podpina się kolejny Mongrel z kolejnego komputera do tego samego adresu IP i zostaje automatycznie włączony do pętli obsługi zdarzeń. Dzięki Ezrze Zygmuntowiczowi, gem Swiftiply udostępnia też gotowy, przerobiony Mongrel działający zarówno z Swiftiply jak i EventMachine. Sam serwer Swiftiply może działać w ogóle bez zewnętrznego serwera HTTP, ale ci co cenią sobie max. wydajność pewnie i tak będą chcieli na froncie postawić szybkiego Nginxa. Wystarczy spiąć go przez mod_proxy do jednego (sic!) Mongrela odpalonego w trybie Swiftiply.

EventMachine

EventMachine to biblioteka napisana w C dla programów Rubiego, Javy i C++. Służy do obsługi zdarzeń w sposób asynchroniczny zamiast wielowątkowy (podobnie jak to robi pythonowy Twisted). EventMachine jest biblioteką bardzo szybką. Serwer pracujący asynchronicznie nie wpada w blokady i jest często szybszy od serwerów pracujących wielowątkowo.

Zamiast tworzyć wiele procesów Mongrela aby zapewnić równoległą pracę dla Rails, wystarczy odpalić jeden (sic!) proces Mongrela asynchronicznego. Asynchroniczny Mongrel działa zarówno z Railsami jaki Merbem. Nie muszę mówić, jakie są oszczędności na pamięci w porównaniu do klastra procesów Mongrela który zwykle zaleca się używać dla Railsów! Z prostych testów porównawczych wyszło mi że Mongrel asynchroniczny jest jakieś dwa razy szybszy od Mongrela wielowątkowego. (Zobacz też Mongrel vs Evented Mongrel)

Jak to skonfigurować?

Po zainstalowaniu gemu Swiftiply stary skrypt mongrel_rails zostaje zastąpiony nowszym (ale tak, że jest zgodny ze starym mongrelem wielowątkowym). Sterowanie trybem pracy dokonywane jest przez ustawienie stosownej zmiennej środowiskowej. Np. aby odpalić Mongrela w trybie asynchronicznym wystarczy napisać

EVENT=1 mongrel_rails start

Poniżej prosty skrypt startujący jaki napisałem dla Ubuntu (wszystkie opcje wyświetli polecenie mongrel_rails start [email protected])

#!/usr/bin/ruby

ADDR='127.0.0.1' 
PORT=7100
# Ścieżka do projektu RoR:
ROOT='/home/app/rails/homepage/current'

PID="#{ROOT}/log/blog.pid"
USER='www-data'
GROUP='www-data'
APPL='/usr/bin/mongrel_rails'
cmd_start = "env EVENT=1 #{APPL} start -a #{ADDR} -p #{PORT} --user #{USER} --group #{GROUP} -P #{PID} -e production -d" 
cmd_stop = "#{APPL} stop -P #{PID}"

curdir = Dir.pwd
Dir.chdir ROOT

case ARGV.first
when 'start'
  system cmd_start
when 'stop'
  system cmd_stop if File.exists?(PID)
when 'restart'
  system cmd_stop if File.exists?(PID)
  system cmd_start
else
  puts "Usage: sudo #{__FILE__} {start|stop|restart}"
end
Dir.chdir curdir

Jeszcze tylko komenda

cd /etc/init.d
update-rc.d -f mogrel_home.rb defaults

i Ubuntu będzie automatycznie ten skrypt uruchamiał podczas restartu maszyny.

Odnośnie Nginxa to nie trzeba wiele zmieniać poza tym, aby skierować proxy na jeden port (w tym wypadku 7100)

upstream mongrel_blog {
  server 127.0.0.1:7100;
}

server {
  # ... inne opcje
  location / {
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect false;
    # ... reszta opcji
    if (!-f $request_filename) {
      proxy_pass http://mongrel_blog;
      break;
    }
  }
}

Stary mongrel_cluster doczekał się konkurencji w postaci gema mongrel_cow_cluster który również powinien szybciej działać od mongrel_cluster’a. Nawet zwolennicy Webricka mogą sobie doinstalować coś szybszego od domyślnego Webricka – forkowy webrick-high-performance (tylko systemy uniksowe). Ale wydaje mi się, że najlepszym rozwiązaniem jest Mongrel asynchroniczny.

Zobacz też entuzjastyczną opinię Ezry Zygmuntowicza o event Mongrelu i o Swiftiply.

Tagi , , , , ,  | 7 comments

Comments

  1. Avatar comboy powiedział 1 day later:

    Spróbowałem. W porównnaiu do zwykłego, pojedyńczego mongrela wydaje się wolniejszy. Chodzi o to że po w pisaniu urla trzeba było czekać nawet sekunde dwie zanim coś wogóle zaczęło się dziać. Nie prowadziłem żadnych benchmarków, w logach req/sec się zbytnio nie zmieniły, ale to wrażenie dla odwiedzającego wydaje mi się gorsze.

  2. Avatar Jarosław Zabiełło powiedział 1 day later:

    A co to za test “wpisać urla”? :) Zapuść przynajmniej ab -n 1000 -c 10 albo coś podobnego. Ezra stwierdza że event Mongrel chodzi nie tylko wyraźnie szybciej ale i zużywa też mniej pamięci. Nie wiem jak duży zysk jest w RoR, ale w Merb jest spory.

  3. Avatar Jarosław Zabiełło powiedział 6 days later:

    Musiałem trochę przebudować treść artykułu, bo był trochę niejasny i wkradły się błędy w listingu.

  4. Avatar iddqd powiedział 10 days later:

    Widzę, że jesteś entuzjastą Ruby. To co piszesz bardzo fajnie się czyta ale na Twoim miejscu byłbym ostrożniejszy w opisywaniu technologii. Mongrel/Swiftiply są bardzo niestabilne przy dużych obciążeniach (idle ~5%) i jeśli ktoś je użyje na podstawie takich entuzjastycznych tekstów może ładnie się naciąć.

    Pozdrawiam.

  5. Avatar wypas powiedział 14 days later:

    a ten wynalazek?

    http://www.rubyinside.com/thin-a-ruby-http-daemon-thats-faster-than-mongrel-688.html

    ?? jest jeszcze szybszy podobno :)

  6. Avatar exor powiedział 3 months later:

    No wlasnie, piszesz, ze tandem apache+mod_proxy+mongrel_cluster sie nie sprawdzil? Co sie dzialo? Wieszal sie?

    Bo chyba mam to samo – po restarcie mongrel_cluster wszystko jest ok, ale tak przez pare godzin… Potem apache sie nie moze podlaczyc do zadnego z trzech uruchomionych mongreli. Netstat pokazuje caly czas otwarte porty.

    Czy taki sam efekt miales?

    Pzdr.

  7. Avatar Jarosław Zabiełło powiedział 3 months later:

    @exor: Miałem coś podobnego, nie wiem czy to samo. Pojedyńcze mongrele czasem padały w clusterze, znikały procesy. W efekcie, przy zastosowanym load balancingu, na kilka requestów niektóre wywalały błąd.

(leave url/email »)

   Pomoc języka formatowania Obejrzyj komentarz