Wielowątkowość Merba

Witam,

Przyznam się bez bicia, że mam nikłe pojęcie jeżeli chodzi o działanie serwerów i frameworków od strony renderowania odpowiedzi.

Dużo słyszy się o tym, że Merb jest “threadsafe”, dużo słyszało się o tym, że railsy nie są. Zacząłem zastanawiać się co za wielowątkowością Merba idzie. Czy jeżeli odpalimy merba na mongrelu (czy jakimkolwiek innym serwerze), to serwer może out of the box obsłużyć wiele żądań w tym samym czasie? Jakie są realne plusy wielowątkowości merba na dzień dzisiejszy?

Myślę, że sprawa jest dosyć jasna. Railsy nie są thread safe, zatem musisz stawiać kilka procesów aplikacji (np. mongrel) do obsłużenia kilku requestów jednocześnie. A co za tym idzie zapotrzebowanie na zasoby rośnie liniowo wraz z ilością procesów. Pomimo tego, że Ruby ma zielone wątki i tak opłacałoby się uruchamiać taką aplikację z kilkoma wątkami. Aplikacja przecież jest zależna od zewnętrznych czynników (IO, sieć, baza danych), zatem zysk powinien być oczywisty. Także jeśli chodzi np. o obsługę uploadu plików. Railsy przyjmują tylko 1 request w jednym czasie, zatem upload blokuje jeden proces całkowicie (a po co, skoro tylko czeka na wszystkie dane, co jest prawie zerowym obciążeniem dla CPU).

Nie wiem czy Merb + Mongrel potrafią działać na wielu wątkach “out of the box”.

[quote=radarek]Myślę, że sprawa jest dosyć jasna. Railsy nie są thread safe, zatem musisz stawiać kilka procesów aplikacji (np. mongrel) do obsłużenia kilku requestów jednocześnie. A co za tym idzie zapotrzebowanie na zasoby rośnie liniowo wraz z ilością procesów. Pomimo tego, że Ruby ma zielone wątki i tak opłacałoby się uruchamiać taką aplikację z kilkoma wątkami. Aplikacja przecież jest zależna od zewnętrznych czynników (IO, sieć, baza danych), zatem zysk powinien być oczywisty. Także jeśli chodzi np. o obsługę uploadu plików. Railsy przyjmują tylko 1 request w jednym czasie, zatem upload blokuje jeden proces całkowicie (a po co, skoro tylko czeka na wszystkie dane, co jest prawie zerowym obciążeniem dla CPU).

Nie wiem czy Merb + Mongrel potrafią działać na wielu wątkach “out of the box”.[/quote]
Opisujesz teraz minusy braku wielowątkowości w railsach. O tym wszystkim wiem… i wiem, że teoretycznie Merb powinien móc obsłużyć wiele zapytań. Dlatego zapytałem jak jest w praktyce. Bo na razie nikt się nie zachwycał: “hej, postawiłem merba na mongrelu i podczas uploadowania 200mb pliku dostaję odpowiedzi na inne żądania” :wink:

Ktoś coś wie o tym jak się zachowuje merb gdy wykonuje się długie zapytanie i wyślemy w tym samym czasie inne?

Opisałem minusy railsów, które są wynikiem braku wielowątkowości. Skoro merb ma taką możliwość to zamień te opisane minusy na plusy i masz gotową odpowiedź.

Gdybyś spotkał się z problemem uploadu plików w railsach wiedziałbyś, że jednym z proponowanych rozwiązań jest obsługa uploadu przez merb, który nie blokuje w ten sposób aplikacji.

W teorii. Ja pytam o praktykę - czy jeżeli postawię merba na mongrelu, to daje mi coś ta wielowątkowość, czy nadal obsługiwany jest tylko jeden request w tym samym czasie.

Spotkałem się, wiem o tym. Tylko rozwiązanie to polegało na tym, żeby uruchomić merba na innym porcie i przekierować do niego upload. Ale z tego nie wynika wcale odpowiedź na moje pytanie :slight_smile:

Ponowię pytanie: ktoś sprawdzał to w praktyce?

UPDATE:
Nie wiem dlaczego właściwie od razu sam nie sprawdziłem. Wygenerowałem aplikację merba, 2 akcje, jedna która trwa 20 sekund (sleep 20) i drugą pustą. Jeżeli uruchomi się tą pierwszą, to druga czeka aż pierwsza się skończy. Serwer odpaliłem standardowy (merb)

A teraz rodzi mi się w głowie pytanie: dlaczego tak się dzieje? Może ktoś przeglądał źródła merba, albo po prostu wie jakie są realne plusy wielowątkowości merba, ewentualnie dlaczego w tym momencie dalej jest ograniczenie do jednego requestu w tym samym czasie?

A spróbuj z tym uploadem plików. Wydaje mi się, że właśnie chodzi o fakt, że railsy zakładają lock od razu przy akceptacji połączenia (cały ActionPack nie jest thread safe). Nie wiem co z resztą, jednakże to do końca nie jest taki prosty. AR też zdaje się nie jest zbyt bezpieczny jeśli chodzi o wielowątkowość.

Dokumentacja to wyjaśnia:

Zatem póki co na sama akcja jest zakładany lock.
Możesz też pokombinować coś z tym zwracanym prociem.

Tylko Drogus napisał, że w akcji było sleep 20 a nie obiekty AR. Jutro rano demitologizacja Merba :slight_smile:

Szybki test “wielowątkowości Merba”:

Merb-core pobrany z repo gita.

cd sample/merb-very-flat

Do akcji index dodaje sleep 20

merb -I merb-very-flat.rb

W przeglądarce wywołuje:

/foo/index - czeka 20 sekund a ja w międzyczasie otwieram /foo/show - odpowiedź dostaję od razu.

Szybki wniosek - wywołanie akcji nie blokuje odpowiedzi na inne akcje.

Może teraz test z obiektami AR w akcji + porównanie z obiektami Sequela ?

A to psikus. Ściągnę zaraz najnowszą wersję i obczaję.

Hosiawak:
Sprawdziłem to i u mnie blokuje. Z tego wnioskuję, że coś robię źle :slight_smile: Mógłbyś wkleić zawartość kontrolera i/lub innych plików, w których coś zmieniałeś? :slight_smile:

To nie ma znaczenia, merb blokuje całą akcję, niezależnie czy korzystasz z AR czy nie (na wypadek gdybyś korzystał ;)).

Jak widać po kolejnym poście jest to już nieaktualne.

Merb core pobrany z repozytorium Git’a

Merb-Core Git

cd merb-core rake install sudo gem install pkg/merb-core-0.9.0.gem

[code=ruby]require ‘rubygems’
require ‘merb-core’

Merb::Router.prepare do |r|
r.default_routes
end

class Foo < Merb::Controller

Returning a string is the easiest.

def index
sleep 20
“Hello from the index action”
end

You could also render a string manually through Erubis.

def show
template_object = Erubis::Eruby.new(<<-EOL)

Hello, world


Here are the params: <%= params.inspect %>


EOL
render template_object.result(binding)
end

end

Merb.start :environment => ‘production’,
:adapter => ‘mongrel’,
:framework => {},
:log_level => ‘debug’,
:use_mutex => false,
:session_store => ‘none’,
:session_secret_key => ‘5b7d26c4d99b922929b7c30ce06be0fd58a71500’,
:exception_details => true,
:reload_classes => true,
:reload_time => 0.5[/code]

cd sample/merb-very-flat

Upewniasz się, że masz nowego Merba:

[code]merb -v

-> merb 0.9.0 (dev)[/code]
Jeśli masz 0.5.0 to odinstaluj: gem uninstall merb i zainstaluj na nowo merb-core.

Teraz:

merb -I merb-very-flat.rb

W FF otwierasz 2 taby:

http://localhost:4000/foo/index http://localhost:4000/foo/show
Zauważ, że akcja show zwraca odpowiedź niezależnie od akcji index, która blokuje:

Thu, 14 Feb 2008 11:13:33 GMT ~ Not Using Sessions Thu, 14 Feb 2008 11:16:18 GMT ~ Params: {} Thu, 14 Feb 2008 11:16:18 GMT ~ Cookies: {} Thu, 14 Feb 2008 11:16:18 GMT ~ Routed to: {:controller=>"foo", :action=>"index", :format=>nil, :id=>nil} Thu, 14 Feb 2008 11:16:22 GMT ~ Params: {} Thu, 14 Feb 2008 11:16:22 GMT ~ Cookies: {} Thu, 14 Feb 2008 11:16:22 GMT ~ Routed to: {:controller=>"foo", :action=>"show", :format=>nil, :id=>nil} Thu, 14 Feb 2008 11:16:22 GMT ~ {:before_filters_time=>1.4e-05, :after_filters_time=>1.4e-05, :action_time=>0.001276} Thu, 14 Feb 2008 11:16:38 GMT ~ {:before_filters_time=>1.5e-05, :after_filters_time=>2.5e-05, :action_time=>20.001198}

Zrobiłem testy z prostym selectem w akcji na obiektach AR i Sequel i bazie sqlite3.

W przypadku opisanym powyżej nie ma znaczenia czy używasz AR/Sequela w akcji czy nie. Z włączonym :use_mutex: zawsze dostajesz odpowiedź, z wyłączonym zawsze blokadę.

Blokadę zakłada opcja :use_mutex: w konfiguracji Merba:

merb -X on -e production
merb -X off -e production

Mała poprawka: jest odwrotnie (włączony mutex zakłada blokadę, czyli przepuszcza tylko 1 wątek).

Co do AR, to w przypadku wielu wątków trzeba mu ustawić odpowiednią opcję (w railsach to się ustawiało poprzez config.active_record.allow_concurrency = true). Z przeprowadzonych kiedyś prób wiem, że railsy wysypywały się przy wielu wątkach jeśli chodzi o dynamicznie ładowanie klas. Powodem tego był fakt, że “require” nie jest bezpieczny. Dołączając do tego sposób w jaki railsy ładują dynamicznie klasę powodowało to, że przy 2 konkurujących ze sobą wątkach jeden z nich dostawał “unitialized constant”.

Uważam, że odpalanie akcji wielowątkowo to ryzykowna sprawa i prędzej czy później można sobie tym zrobić krzywdę. Sam fakt, że blokada jest tylko na samej akcji, a nie całym requeście napawa mnie optymizmem :).

Hosiawak:
Bo ty takie hakierstwo zapodałeś :slight_smile: Ja po prostu dodałem kontroler do wygenerowanej aplikacji merba. Dodałem

c[:use_mutex] = false

do production.rb i rzeczywiście, długa akcja już nie blokuje tej krótszej. :slight_smile: