2009-02-19 25 views
7

Я пишу веб-приложение для мониторинга потока производства фабрики мебели. Он обрабатывает тысячи данных. До сих пор я запускал RoR на Mongrel + MySQL, и это действительно очень медленно (2-4min для некоторых просмотров). Когда я смотрю на журналы RoR, кажется, что запросы к базе данных не медленны (0-10 мс).Ruby On Rails медленный ...?

Является ли RoR медленным, когда он преобразует данные базы данных в объект? Мегрел?

Редактировать: Первое: я был в dev. окр. В производственной среде самый медленный вид занимает 2мин (который будет работать менее чем на 1 мин на хорошем компьютере, мне 5 лет). С ruby-prof и немного здравым смыслом я выяснил, какие методы замедляют работу приложения. Проблема заключается в том, что отдельные запросы SQL называются петлями на Крупнейшими наборов данных:

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 

Здесь представлены результаты рубин-Prof на этих методах:

%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} 

Проблема: Я не могу избежать тех одного запросы. У меня есть тысячи событий, из которых мне приходится вычислять сложные данные. Прямо сейчас я использую memcached для тех методов, которые в порядке, если только ваш первый не запросит страницу.

+0

Ни то, ни другое, вероятно, написанный вами код, который является медленным, или тот факт, что вы работаете на этапе разработки. Если вы могли бы разместить соответствующее содержание мнений, мы могли бы дать правильный ответ. – TomHastjarjanto

+0

Согласитесь с @Tomh - это не типично вообще, даже с большими наборами данных. Нам нужна дополнительная информация, чтобы сделать какой-либо диагноз. –

+0

Это может показаться глупым, но убедитесь, что вы работаете в режиме производства.Режим Dev будет перезагружать все классы по каждому запросу. –

ответ

17

Я согласен со всеми остальными. Вы должны профиль. Нет никакого смысла делать что-либо с вашим кодом, пока вы не узнаете, что конкретно вызывает медленность. Попытка решить проблему, не понимая причину, - это как плохо себя чувствовать и решила провести много операций, пока не почувствуете себя лучше. Сначала диагностируйте вашу проблему.Это может быть что-то маленькое, как сетевые настройки, или это может быть одна неудачная строка в вашем коде.

Некоторые советы для профилирования:

How to Profile Your Rails Application

Performance Testing Rails Applications

At the Forge - Profiling Rails Applications

После того, как вы нашли узкое место вы можете выяснить, что делать.

Я рекомендую эти видео: Railslab Scaling Rails

Revised в настоящее время на основе результатов ПРОФ:

OK. Теперь, когда вы видите, что ваша проблема заключается в том, что вы делаете какие-то вычисления, используя запрос, основанный на прокрутке результатов другого активного запроса записи, я бы посоветовал вам изучить создание пользовательского оператора SQL, сочетающего ваши исходные критерии отбора и расчет цикла, чтобы получить то, что вам нужно. Вы можете определенно ускорить это, оптимизируя SQL.

4

Это не нормально. У вас есть логика, которая замедляет вас. Попытка комментировать биты и фрагменты вашего кода, которые, по вашему мнению, занимают много времени и видят, помогает ли это. Если это произойдет, вам нужно выяснить, как оптимизировать эту логику.

Вы делаете много вычислений по циклу, итерации через очень большое количество объектов, тогда, конечно, он будет медленным.

Эти типы проблем могут возникать на любом языке или в каркасе. Хотя Ruby не так быстро, как на других языках, он достаточно быстро занимает большую часть времени. Если вам нужно постоянно вычислять с большими наборами данных, то Ruby может быть не подходящим для вас языком. Посмотрите на письмо с расширением Ruby C, которое будет обрабатывать ваш дренажный код производительности. Но сначала попробуйте диагностировать и реорганизовать.

Наконец, проверьте RubyProf, чтобы узнать, может ли он помочь вам найти узкое место.

+0

Не было бы лучше сделать это «во-первых, проверить rubyprof» – srboisvert

+0

Почему ваш метод профилирования комментирует биты и фрагменты вашего кода вместо научной методики использования профилировщика? – yfeldblum

5

Сколько из этих 0-10ms запросов выполняется для каждого доступа к просмотру? На какие части вашей модели данных ссылаются? Используете ли вы: включить, чтобы получать активную загрузку в ваших ассоциациях?

Рельсы так же медленны, как вы это делаете. С пониманием приходит скорость (обычно!)

Расширение на выше, у вас есть has_many ассоциации, где, в частности, ваш взгляд ссылается на «много» сторону без :include? Это приведет к тому, что ваш find(:all) на главной таблице будет выполнен с присоединением к деталям - если у вас есть большое количество подробных записей и каждый из них обрабатывает их отдельно, это может стать дорогостоящим.

Что-то вроде этого:

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

... может помочь. Тем не менее, догадываясь от редкой информации.

Там старый Railscast на тему here

3

Предыдущие два ответа являются полезными, особенно с помощью инструментов мониторинга производительности.Я использую New Relic RPM, и это очень помогло мне в прошлом.

Однако эти инструменты действительно лучше, когда вы пытаетесь ускорить, скажем, от 3 секунд до 1 секунды.

2-4 минуты для визуализации абсолютно не нормальный при каких-либо нормальных обстоятельствах.

Не могли бы вы показать нам некоторые из ваших журналов разработки, чтобы выяснить, где узкие места?

Вы включаете время, которое браузер берет на себя, чтобы загрузить изображения, javascripts или другие файлы в это общее измерение?

+0

Yep New Relic отлично подходит для отслеживания этого материала. –

5

В то время как R-n-R has a reputation of being slow, это звучит слишком экстремально, чтобы быть простой проблемой с языком.

Вы должны запустить профилировщик, чтобы точно определить, какие функции медленны и почему. Наиболее распространенной причиной замедления веб-приложения является «n+1 problem». То есть, когда у вас есть n элементов данных в вашей базе данных, приложение делает n отдельных запросов в базе данных вместо того, чтобы делать один запрос, который их получает. Но вы не можете знать, пока не запустите профайлер. ruby-prof - это один профайлер, который я использовал.

Редактировать на основе результатов редактирования профиля:

Я твердо верю, что вы можете всегда удалить цикл запроса. Как говорит Майк Вудхаус, путь Rails для этого состоит в том, чтобы указать отношения между вашими таблицами с has_many или другими ассоциациями, а затем позволить рельсам автоматически генерировать соединение таблицы, это ясно, быстро и «путь Rails». Но если вы начинаете с голого SQL или если ассоциации не работают в этом случае, вы можете просто создать соответствующие объединения самостоятельно. И если все остальное не удается, вы можете создать таблицу представлений или денормализованную таблицу, которая содержит результаты, которые ранее были найдены через цикл. Действительно, тот факт, что вы должны итерации по сгенерированным запросам , может быть быть признаком того, что у вашего дизайна стола есть некоторые недостатки.

Все, что сказано, если кеширование результатов вашего запроса работает достаточно хорошо для вас, а затем оставайтесь с ним. Оптимизируйте при необходимости.

+0

Получил ли голосование, затем вверх, без комментариев? –

+0

Извините - это был я. Никакая цитата из-за того, что «R-n-R» (?) Была медленной, что казалось мне спорным и ненужным, а также неверным в моем опыте. –

+0

Не было никакой цитаты, но это довольно распространенное мнение, правда или нет. – Craig

0

Время выполнения этого долгого времени заставило бы меня подозревать проблему с сетью - возможно, DNS-запрос синхронизируется на основном DNS-сервере?

0

Вы можете попробовать использовать JRuby или переключиться на Ruby 1.9.
Оба они должны приводить к мощным повышениям производительности.
Проблема с JRuby заключается в том, что драгоценные камни, которые используют C, не будут компилироваться/работать. Существуют Java-эквиваленты, которые устанавливаются приложением jruby «gem», но некоторые из драгоценных камней просто не работают

У вас в основном будет такая же проблема с Ruby 1.9. Немного синтаксис изменился, но главная проблема заключается в том, что количество драгоценных камней больше не работает. Люди все еще находятся в процессе обновления (проверьте прогресс на http://isitruby19.com/)

0

Почему бы не предварительно получить все данные, а ваш цикл for найти его локально в памяти, а не запрашивать базу данных каждый раз? 1000 запросов для одного представления указывают на то, что с вашим дизайном что-то серьезно не так.

0

Есть некоторые хороший экран бросает на эту тему http://railslab.newrelic.com/scaling-rails

вещи, как кэширование fragmet и использование: включают в себя (чтобы избежать п + 1) может помочь. Похоже, вы уже используете memcached, поэтому почему бы не скрутить URL-адрес для предварительной выборки кеша?

0

Когда я привязал сервер к ip-адресу ящиков вместо 0.0.0.0, это ускорилось для меня.

0

Вы можете прокомментировать код прежде, чем что-либо сделать, хотя запросы внутри циклов являются очень распространенной причиной проблем с производительностью, и на первый взгляд это кажется вашей проблемой. Вы можете в любом случае найти практическое профилировщика here:

Как уже было сказано на другие ответы, если обе модели связаны, вы должны нетерпеливый нагрузки ассоциации, подразумевающей инструктирование Active Record для выполнения запросов для объединения:

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

Если вам не нужны ofkbs, но только те операции, можно выполнить внутреннее соединение

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

Это решение только преформ один запрос, и позволяет впоследствии перебирать данные, которые будут иметь уже б ееп собраны из БД:

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

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

Если запросы очень сложно, вы должны использовать arel вместо этого.