Klaster mongreli i blokada

Witam!
Mam następujący problem i proszę o pomoc. Moja aplikacja Rails-owa ma nieliczne metody kontrolerów, które wykonują się długo (od kilkunastu sekund do kilkunastu minut). Uruchomienie takiej akcji powoduje, że pozostali uzytkownicy aplikacji muszą czekać na zakończenie tej “czasowo-żernej” akcji. Aplikacja działa na konfiguracji Apacha z klastrem 4 mongreli na Debianie w środowisku "development’ (okres testowania) . Czy to jest normalne? Wydawało mi się, że żądanie (akcji kontrolera "czasowo-zernej) wywołuje jeden wątek, którym się zajmuje instancja mongrel-a, a pozostałe innymi żądaniami (tymi zdecydowanie krótszymi w opisywanym przypadku ) dzieląc się sprawiedliwie czasami wykonywania. Jak wynika z moich doświadczeń z eksploatacji aplikacji tak nie jest. Jak sobie poradzić z tym zjawiskiem?

A co konkretnie się dzieje w tych czasożernych akcjach ? Wyjaśnij albo podeślij kod.

Dzięki za zainteresowanie moim problemem. Kodu nie podeślę, bo to niestety tajemnica przedsiebiorstwa dla ktorego tworzę aplikację :-). Ale hipotetycznie wyjaśniam. Mam np akcje kontrolera, która bedzie wyznaczała pierwszy milion liczb pierwszych. Nie ulega wątpliwosci, że bedzie się dlugo wykonywała, nawet wygenerowanie widoku z milionem liczb bedzię trochę trwało. W tym czasie , czyli po zainicjowaniu metody " milion liczb pierwszych" przez jakieś użytkownika inni użytkownicy będa chcieli skorzystać z innych metod kontrolera, np dodawania dwóch liczb, inni np mnożenia. Zjawisko (przenosząc to na grunt tego co obserwuję w swojej aplikacji) będzie takie, że niestety muszą czekać zanim nie skończy sie dzialanie akcji z metodą “milion liczb pierwszych”. I to mnie zastanawia. Sądziłem, że klaster mongreli zabezpieczy mnie przed wystepowanie tego zjawiska. Jedna instancja mongrela zajmie sie generowaniem miliona liczb pierwszych, druga dodawaniem, a trzecia mnożeniem. Przy równomiernym przydziale czasu procesora na wątek, metoda 2 i 3 powinny skończyć się szybko bo wykonywane są szybko i np potrzebne bedzie tylko kilka cykli przełączania sie między wątkami (instancjami mongrela) a metoda 1 bedzie wykonywala sie dlugo (bo taka jest jej natura), ale nie będzie "zawlaszczała tylko sobie wszystkich zasobów, nie dopuszczając innych instancji do wykonywania.
W FAQ Mongrela znalażlem coś takiego:
"Q: Is it multi-threaded or can it handle concurrent requests? ¶
Mongrel uses one thread per request, but it will start closing connections when it gets “overloaded”. While Mongrel is processing HTTP requests and sending responses it uses Ruby’s threading system (which is more like Java’s original green threads and uses select).

Camping and Og+Nitro are supposed to be thread safe and work with Mongrel directly. This hasn’t been heavily tested so people should let me know if they get weird explosions under heavy load.

Ruby on Rails is not thread safe so there is a synchronized block around the calls to Dispatcher.dispatch. This means that everything is threaded right before and right after Rails runs. While Rails is running there is only one controller in operation at a time. This is why people typically have to run a small set of Mongrel processes (a “Pack of Mongrels”) to get good concurrency.

If you have long running actions then you’ll most likely have performance problems. You should for ways to offload work to another process so that your Rails app can keep working. "

Na ile pozwala mi taka sobie znajomość angielskiego, to jednak nic nie zrobię jeśli:
-albo nie przyspieszę wykonywania się metody do akceptowalnych czasów odpowiedzi poprzez np jej optymalizację,
-albo nie podzielę jej na wiele podprocesów (akcji elementarnych szybko się wykonujących) by wymusić na klastrze angażowania kolejnych instancji mongrela do ich wykonania dając szanse innym wątkom by były wykonane (czyli się załapały w kolejkę).

Pewnie się mylę, bo jak tak miało by być, to moim zdaniem byłoby to beznadziejne. To po co ten klaster jak to dziala podobnie jak na jednym mongrelu. Chyba że klaster mongerli ma być dla róznych maszyn, a nie jednoprocesorowego serwera.

Pamietaj ze jesli jakis proces mongrela zuzywa 100 % CPU, to wszystkie inne oczekuja na to az system da im dostep do czasu procesora, jesli jakas akcja jest super czasohlonna i zjada mase procka (praktycznie jego calosc) to nie zostaje juz na inne akcje nic i tutaj tego problemu nie przeskoczysz nawet wielowatkowoscia. Wielowatkowosc w pewnym sensie to po prostu procesy z warstwa abstrakcji. Barier technicznych nie przeskoczysz.

Jesli masz super czasohlonne akcje, no to majac Quad Core jestes w stanie zrobic sobie cluster, za to jak kazdy proces bedzie mial dostep do CPU odpowiedzialny bedzie kernel systemu,a w kernelu scheduler. Scheduler bedzie wyznaczal kiedy i do jakiego procka twoj proces dostanie dostep. Jesli masz 1 procesor, 4 procesy mongrela i akcje sa superchasochlonne i superprocesorzerne no to nie ma przebacz :slight_smile: taki cluster mongrela mozna wziasc i o kant otrzec bo ograniczen technicznych nie przeskoczysz.

Troche to lopatologiczne.

Milion liczb pierwszych 0_o
Takie rzeczy to tylko w C :wink:

oj tam c, jest inline_c w ruby :slight_smile: czy tam inline_ruby i jesli faktycznie musisz robic operacje na tylu liczbach rob je w tym czyli wstawki c w ruby, ktore podczas uruchamiania sie kompiluja, napewno bedziesz mial niesamowitego boost’a

Jesli te akcje sa faktycznie super wcholere zasoborzerne to JRuby tez moglby dac ci jakiegos boosta przy takich operacjach. Wogole to wpadnij na kanal :stuck_out_tongue: irc://irc.freenode.net/rubyonrails.pl

PaK, pozmyślałeś konkretnie :).

rojam, mongrel jest wielowątkowy, ale ponieważ railsy nie są i zakładają blokadę już od momentu dispatchingu to przetwarzanie jest de facto 1 wątkowe. Merb przykładowo odpalony na mongrelu pozwala na wiele wątków na raz.

Jednak nie martw się, istnieje sprawdzone rozwiązanie na Twój problem. BackgroundRB: http://backgroundrb.rubyforge.org/. Pogooglaj bo to dosyć popularne rozwiązanie. W skrócie chodzi o to, że odpalasz osobny wątek, poza requestem, i zwracasz sterowanie z akcji kontrolera. Następnie periodycznie (np ajaxem) odpytujesz serwer czy już skończył przeliczać. Poszukaj też na forum bo ten temat był już wałkowany.

Aha, widziałem też gdzieś rozwiązanie polegające na tym, że te procesy mongrela, które są zajęte (przetwarzają aktualnie żądanie) nie są wybierane przez balancer, zatem dopóki masz wolny choćby 1 węzeł klastra to żądania są przetwarzane. Aczkolwiek nie wiem czy to nie był moduł do nginxa. Musiałbym pogooglać ;).

Ok, znalazłem: http://brainspl.at/articles/2007/11/09/a-fair-proxy-balancer-for-nginx-and-mongrel . Jednak tylko nginx.

Aha, odnośnie pytania co daje klaster mongreli? Przede wszystkim daje Ci możliwość przetwarzania jednocześnie kilku requestów w tym samym czasie. A dodatkowo jeśli masz maszynę kilkuprocesorową/rdzeniową to wykorzystasz więcej niż 1 procek.

Radarek: ok napisalem niezle glupoty, zabardzo to uproscilem. Faktycznie jesli procesy mongrela beda mialy te same priorytety to zarzadca bedzie dazyl do tego aby kazdy z nich dostal ta sama ilosc CPU. Dopiero w monecie gdy jakis proces o wyzszym priorytecie zacznie jesc cpu to wtedy tamte mogal czekac prawda ? Sam kernel jesli np zacznie robic swap cycle (nie wiem czy dobre okreslenie, ale np moment w ktorym konczy sie pamiec fizyczna a potrzebna jest ona intensywinie) to procesy mongrela moga zaczac sie dusic ?

Jest jeszcze Background-Fu, ponoć prostszy w obsłudze ale nie napiszę nic więcej bo nie korzystałem.

Sugestie Radarka są bardzo dobre także idź w tym kierunku :slight_smile:

Dziękuję bardzo za wszystkie sugestie a szczególnie Radarkowi i Hosiawak-owi. W obecnej sytuacji (zbliżający sie termin wdrazania aplikacji) nie będę migrował do Merba. Pozostaje BackgroundRB, zważywszy, że jestem w stanie ściśle określić te akcje aplikacji, ktore wykonują się potencjalnie długo i tam zastosować zalecane przez Was rowiązanie. Rzadko korzystam z pomocy na listach dyskusyjnych, bo zwykle sam próbuję drążyć problematyczne tematy. Teraz zmusił mnie brak czasu. Tym bardziej jestem Wam Wszystkim wdzięczny za tak szybką pomoc. Rozumiem, że to wyczerpuje ten wątek.

Nie. Jeśli jakis proces ma większy proces będzie mieć większy priorytet to po prostu będzie dostawać większe kwanty czasu procesora. Ale procesy nadal będą działać równolegle. Zależy to oczywiście od samego algorytmu shedulera, których jest pewnie sporo ;). Ale sprawiedliwy scheduler do tego dąży. W twoim przypadku szybko mógłbyś doprowadzić do zagłodzenia procesu.

To już inna historia. Po prostu w tym momencie masz wąskie gardło - odczyt/zapis na dysku, co jest bardzo czasochłonne. Nie ma to nic wspólnego z konkurującymi procesami o CPU.

Dodam swoje 5 gr.

Wszystko pieknie, a jesli zadania beda wykonywane kilka czy kilkanascie minut i moze nie wystarczyc kilka czy wiecej procesow.

Mysle, ze procesy mongrela powinnismy zostawic samej aplikacji RoR.
Wydaje mi sie, ze Rojam powinien przemyslec problematyke i znalezc rozwiazanie poza aplikacja.
Zazwyczaj takie obciazenia przenosi sie poza serwer www/mysql do dedykowanej aplikacji/skryptu na innym serwerze.
I pozostaje przemyslec aplikacje pod katem obslugi Thread.

tczuninski: i taki efekt uzyskamy stosując BackgroundRB.

@Radarek: BackgroundRB jest paskudne w instalacji, średnio wygodne w obsłudze i ograniczone w możliwościach. Been there, done that. Z całym szacunkiem dla Ezry, który jest dla mnie jednym z mistrzów Rubiego, to jednak BackgroundRB udało mu się średnio - a w kolejnych releasach, zamiast upraszczać, jeszcze bardziej namieszał.

@Rojam: Wpadnij na Euruko, będę miał tam spicza (niedziela, 11:30) o prostym rozwiązaniu dokładnie takich problemów jak Twój :wink:

@Tczubinski: słusznie waść prawisz, nareszcie głos rozsądku z zakresu inżynierii oprogramowania :slight_smile:

Tomash, hm, trochę przesadzasz. Zostawisz złe opinie nie poparte konkretnymi przykładami (instalacja paskudna? średnio wygodne w obsłudze? jakie ograniczone możliwości?). Nigdzie indziej nie czytałem nic złego o BackgroundRB.

Ja pamiętam, że dokumentacja trochę zawiła była kiedyś, ale nie miałem z tym pluginem żadnych problemów.

Kiedy ostatnio próbowaliście instalować BackgrounDrb? Bo faktycznie jakiś czas temu (np. lato’07) było cacy i instalowało się prosto. Ale to, co się teraz wyprawia, to jakiś totalny kosmos.

Średnio wygodne w obsłudze - chodzi mi o kwestię wymiany danych z aplikacją “zlecającą”.

Ograniczone możliwości - zleconą pracę odpala “od ręki”, nie ma możliwości zlecenia jej wykonania w arbitralnej chwili w przyszłości. Znaczy, jeśli chcemy uzyskać taką funkcjonalność, trzeba się posiłkować np. sleepem (co niestety i wbrew pozorom obciąża procesor - BackgroundRb już czterema-pięcioma “śpiącymi” wyraźnie i odczuwalnie zamula maszynę) lub pisać własnego schedulera (masakra).

BackgroudRb atakuje problem zlecania zadań od bardzo dobrej strony (w końcu wiadomo - Ezra), ale do kompletności i uniwersalności troszkę mu brakuje.

Sorry, chłopaki, ale naprawdę z rozwiązaniami do “outsourcowania” zadań z aplikacji Railsowej miałem chyba więcej doświadczeń, niż z jakimkolwiek innym zagadnieniem z RoR :slight_smile:
(co wcale nie oznacza, że są to doświadczenia absolutnie kompletne czy megaspecjalistyczne :wink: )

Mnie niestety nie będzie na Euruko, więc fajnie by było jakbyś później wrzucił jakieś coś gdzieś w sieci. Albo porozmawiamy na bootstrapie (jak cholera znowu gdzieś nie wybyję…)

Co do backgroundRb - instalowałem 2-3 miesiące temu, ale do bardzo prostych zadań - odczytanie aktualnych wartości z API aplikacji i zaktualizowanie bazy danych. Zbyt dużo nie wymagałem - chętnie usłyszę o tych miejscach, w których BdRb nie daje sobie rady :slight_smile:

potwierdzam

[quote=Tomash]Ograniczone możliwości - zleconą pracę odpala “od ręki”, nie ma możliwości zlecenia jej wykonania w arbitralnej chwili w przyszłości. Znaczy, jeśli chcemy uzyskać taką funkcjonalność, trzeba się posiłkować np. sleepem (co niestety i wbrew pozorom obciąża procesor - BackgroundRb już czterema-pięcioma “śpiącymi” wyraźnie i odczuwalnie zamula maszynę) lub pisać własnego schedulera (masakra).

BackgroudRb atakuje problem zlecania zadań od bardzo dobrej strony (w końcu wiadomo - Ezra), ale do kompletności i uniwersalności troszkę mu brakuje.[/quote]
i jeszcze raz potwierdzam.

Ezra Zygmuntowicz jest wyjatkowo dobrym programista. BdRb mial zadatek na rozwiazanie trudnego tematu, mam wrazenie ze powstala z tego kobyla, ktorej tak jak kolega napisal m.in brakuje schedulera Jak widac to nie jest proste, mimo ze rozwiazania wydaja sie oczywiste.

Dodam, przydalo by sie cos lekkiego i zwinnego :slight_smile:

Z tego co pamietam to Rick lub Ezra wrzucil: http://pastie.caboo.se/pastes/15033 :wink:

http://ap4r.rubyforge.org/wiki/wiki.pl?GettingStarted

Ciekawe i kompleksowe rozwiazanie.

  • Moze byc podpiete pod aplikacje RoR lub w w prostym skrypcie ruby
  • Kolejka jest trwale budowana w bazie lub pliku (wystarczy do tego sqlite)

akcja → aplikacja → zapis obiektów w bazie i lub uruchomienie zadania → wykonuje nastepna kolejke → wykonuje akcje

miej wiecej taki ciag zdarzen. synchroniczna komunikacja aplikacji z kolejkowaniem odczyt/zapis, asynchronicznie wykonywanie zadania i przekazywanie informacji do aplikacji.

Proponuje skompletowac w tym watku wszystkie dobre rozwiazania.