Ruby On Rails jest powolny...?

Piszę aplikację internetową do monitorowania przepływu produkcji w fabryce mebli. Ma tysiące danych do obsługi. Jak na razie uruchamiam RoR na Kundel + MySQL i jest naprawdę bardzo wolny (2-4min dla niektórych odsłon). Kiedy patrzę na dzienniki RoR, wydaje się, że zapytania do bazy danych nie są powolne (0-10ms).

Czy RoR jest powolny, gdy konwertuje dane z bazy danych na obiekt ? Czy Kundel jest powolny ?

Edit : Po pierwsze: byłem w dev. env. W środowisku produkcyjnym najwolniejszy widok zajmuje 2min (co zmniejszy się do mniej niż 1min na dobrym komputerze, mój ma 5 lat). Dzięki ruby-prof i odrobinie zdrowego rozsądku dowiedziałem się, które metody spowalniają aplikację. Problem polega na tym, że pojedyncze zapytania sql są wywoływane w pętlach na dużych zbiorach danych:

ofs = Ofkb.find_by_sql ["..some large sql query..."]

for of in ofs # About 700-1000 elements
   ops = Operation.find(..the single query..)
   etc.
end

Oto wyniki ruby-prof na tych metodach:

 %self     total     self     wait    child    calls  name
 32.19     97.91    97.91     0.00     0.00       55  IO#gets (ruby_runtime:0}
 28.31     86.39    86.08     0.00     0.32    32128  Mysql#query (ruby_runtime:0}
  6.14     18.66    18.66     0.00     0.00    12432  IO#write (ruby_runtime:0}
  0.80      2.53     2.42     0.00     0.11    32122  Mysql::Result#each_hash (ruby_runtime:0}

Problem w tym, że nie mogę uniknąć tych pojedynczych zapytań. Mam tysiące zdarzeń, z których muszę obliczać złożone dane. W tej chwili używam memcached na tych metodach, które są w porządku, chyba że pierwszy zażąda strony.

Author: Giann, 2009-02-19

11 answers

Zgadzam się ze wszystkimi. Musisz profilować. Nie ma sensu robić nic z kodem, dopóki nie wiesz, co konkretnie powoduje powolność. Próbując naprawić problem bez zrozumienia przyczyny jest jak złe samopoczucie i decydując się na wiele operacji, dopóki nie poczujesz się lepiej. Najpierw zdiagnozuj swój problem. Może to być coś małego, jak ustawienie sieciowe lub może to być jedna zła linia w kodzie.

Kilka wskazówek dotyczących profilowania:

Jak Profiluj Swoją Aplikację Rails

Testowanie Wydajności Aplikacji Rails

W Kuźni-Profilowanie aplikacji Rails

Po znalezieniu wąskiego gardła możesz dowiedzieć się, co zrobić.

Polecam te filmiki: Railslab Rails

Poprawione na podstawie wyników prof:

OK. Teraz, gdy widzisz, że twój problem polega na tym, że wykonujesz jakieś obliczenia za pomocą zapytania opartego na pętli przez wyniki innego zapytania active record radzę przyjrzeć się budowaniu niestandardowej instrukcji SQL łączącej początkowe kryteria wyboru i obliczenia pętli, aby uzyskać to, czego potrzebujesz. Możesz zdecydowanie przyspieszyć to, optymalizując SQL.

 17
Author: srboisvert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-20 15:44:55

Ile z tych zapytań 0-10 MS jest wykonywanych na dostęp do widoku? Jakie części modelu danych są odwołane? Czy używasz :include, aby uzyskać chętne ładowanie na swoje Stowarzyszenia?

Rails jest tak powolny, jak to robisz. Ze zrozumieniem przychodzi szybkość (Zwykle!)

Rozszerzając powyższe, czy masz skojarzenia has_many, gdzie w szczególności twój pogląd odnosi się do strony "wielu" Bez :include? Powoduje to, że Twój find(:all) na stole głównym zostanie wykonany z dołącz do szczegółów - jeśli masz dużą liczbę szczegółowych rekordów i przetwarzasz wszystkie z nich indywidualnie, może to być drogie.

Coś takiego:

Master.find(:all, :include => :details)

...może pomóc. Ale wciąż zgaduję z nielicznych informacji.

Jest stary Railscast na temat tutaj

 5
Author: Mike Woodhouse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 20:18:56

Podczas gdy R-n-r ma reputację powolnego , brzmi to zbyt ekstremalnie, aby być prostym problemem z językiem.

Powinieneś uruchomić profiler, aby dokładnie określić, które funkcje są wolne i dlaczego. Najczęstszą rzeczą spowalniającą aplikację internetową jest " N+1 problem". Oznacza to, że gdy masz n pozycji danych w bazie danych, aplikacja sprawia n oddzielnych zapytań do bazy danych zamiast jednego zapytania, które je pobiera. Ale nie możesz wiedzieć dopóki nie uruchomisz profiler. ruby-prof to jeden profiler, którego używałem.

Edit based on profile results edit:

Mocno wierzę, że można zawsze usuń pętlę zapytań. Jak mówi Mike Woodhouse, Rails sposobem na to jest określenie relacji między tabelami z has_many lub inne skojarzenie, a następnie niech rails automatycznie wygeneruje połączenie tabeli, jest to jasne, szybkie i "droga szyn". Ale jeśli zaczynasz od goły SQL lub jeśli skojarzenia nie działają w tym przypadku, możesz po prostu wygenerować odpowiednie połączenia samodzielnie. A jeśli Wszystko inne zawiedzie, możesz utworzyć widok lub tabelę denormalizowaną, która przechowuje wyniki, które wcześniej zostały znalezione za pomocą pętli. Rzeczywiście, fakt, że musisz iterację poprzez generowane zapytania Może być znakiem, że sam projekt tabeli ma pewne wady.

Wszystko, co powiedział, Jeśli buforowanie wyników zapytań działa wystarczająco dobrze dla Ciebie, a następnie pozostać z nim. Optymalizuj w razie potrzeby.

 5
Author: Joe Soul-bringer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-01 12:37:56

To nie jest normalne. Masz jakąś logikę, która Cię spowalnia. Próbując komentować fragmenty kodu, które Twoim zdaniem zajmują dużo czasu i sprawdź, czy to pomaga. Jeśli tak, to musisz wymyślić, jak zoptymalizować tę logikę.

Of you are doing lots for a loop iterating through a very large objects, then of course it will be slow.

Tego typu problemy mogą pojawić się w dowolnym języku lub frameworku. Podczas gdy Ruby nie jest tak szybki jak w innych językach, jest wystarczająco szybki przez większość czasu. Jeśli musisz stale obliczać z dużymi zestawami danych, Ruby może nie być odpowiednim językiem dla Ciebie. Spójrz na napisanie rozszerzenia Ruby C, które obsłuży Twój kod zmniejszający wydajność. Ale najpierw spróbuj zdiagnozować i refaktor.

Na koniec sprawdź RubyProf , aby zobaczyć, czy może pomóc Ci znaleźć wąskie gardło.

 4
Author: Alex Wayne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-20 09:51:35

Dwie poprzednie odpowiedzi są pomocne, zwłaszcza przy użyciu narzędzi do monitorowania wydajności. Używam New Relic RPM i bardzo mi to pomogło w przeszłości.

Jednak tego rodzaju narzędzia są naprawdę najlepsze, gdy próbujesz przyspieszyć z, powiedzmy, 3 sekund do mniej niż 1 sekundy.

2-4 minuty na renderowanie widoku nie są normalne w żadnych normalnych okolicznościach.

Czy mógłbyś nam pokazać niektóre dzienniki rozwoju, aby dowiedzieć się, gdzie wąskie gardła są?

Czy uwzględniasz czas potrzebny przeglądarce na załadowanie obrazów, javascriptów lub innych plików do tego całkowitego pomiaru?

 3
Author: btw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 18:07:15

Tak długi czas wykonania sprawi, że będę podejrzewał problem z siecią - może zapytanie DNS jest timing out na głównym serwerze DNS?

 0
Author: Ori Pessach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 18:13:06

Możesz spróbować użyć JRuby lub przełączyć się na Ruby 1.9.
Oba z nich powinny spowodować ogromne zwiększenie wydajności.
Problem z JRuby polega na tym, że kamienie używające C nie będą kompilować/działać. Istnieją odpowiedniki Javy, które są instalowane przez aplikację " gem " jruby, ale niektóre z nich po prostu nie działają]}

Zasadniczo będziesz miał ten sam problem z Ruby 1.9. Trochę zmieniła się składnia, ale głównym problemem jest to, że duża ilość klejnotów już nie działa. Ludzie się rozwijają aktualizacji (sprawdź postęp w http://isitruby19.com/)

 0
Author: Marc Seeger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 20:18:53

Dlaczego nie pobrać wszystkich danych i mieć pętli for znaleźć je lokalnie w pamięci, zamiast odpytywania bazy danych za każdym razem? 1000 zapytań dla pojedynczego widoku wskazuje, że coś jest poważnie nie tak z Twoim projektem.

 0
Author: Beep beep,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-20 20:18:48

Jest kilka dobrych screenów na ten temat http://railslab.newrelic.com/scaling-rails

Takie rzeczy jak buforowanie fragmet i używanie: include (aby uniknąć n+1) mogą pomóc. Wygląda na to, że już używasz memcached, więc dlaczego nie zwinąć adresu url, aby wstępnie ustawić pamięć podręczną?

 0
Author: MatthewFord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-25 11:19:15

Kiedy przywiązałem serwer do adresu IP Box zamiast 0.0.0.0, przyspieszyło to wszystko dla mnie.

 0
Author: hforbess,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-11 17:52:59

Możesz najpierw profilować kod przed zrobieniem czegokolwiek, jednak zapytania wewnątrz pętli są bardzo częstą przyczyną problemów z wydajnością i na pierwszy rzut oka wydaje się to Twoim problemem. W każdym razie możesz znaleźć praktyczny profiler tutaj :

Jak już wspomniano na innych odpowiedziach, jeśli oba modele są ze sobą powiązane, należy załadować Asocjacje, co implikuje polecenie Active Record do wykonania zapytań join:

#left outer join
ofkbs=Ofkb.includes(:operation).where(name: "banana")

Jeśli nie potrzebujesz ofkbs, a tylko operacje, można wykonać połączenie wewnętrzne

#inner join (discards the Ofkbs that do not have any operation)
operations=Operation.joins(:ofkb).where(ofkb:{name:"banana"})

To rozwiązanie preformuje tylko jedno zapytanie, a następnie pozwala na iterację danych, które zostaną już zebrane z DB:

operations=ofkbs.map{|of| of.operations}.flatten

operations.each do |o|
  do_whatever_you_want_with_operation(o)
end

Jeśli zapytania są bardzo skomplikowane, powinieneś użyć arel .

 0
Author: Pedro Morte Rolo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-23 11:23:43