Будет ли использование Redis с Rails приносить какую-либо выгоду производительности для этого конкретного вида запросов - PullRequest
2 голосов
/ 20 ноября 2011

Я не знаю, если это правильное место, чтобы задать вопрос, как это, но вот оно:

У меня есть приложение на Rails 3, похожее на интрасеть, управляющее примерно 20 тысячами пользователей, которые находятся во вложенном наборе (предварительно упорядоченное дерево - http://en.wikipedia.org/wiki/Nested_set_model). Эти пользователи вводят статистику (данные, просто числовые значения). Введенная статистика присваивается категории (мы называем ее указателем) и номеру недели.

Эти данные дополнительно обрабатываются и рассчитываются для результатов. Некоторые из них вычисляются по активности пользователей + результат из другой категории ... и т. Д То, что вводит пользователь, не всегда совпадает с тем, что он видит в отчетах.

Эти вычисления могут быть очень сложными, некоторые категории имеют очень специфические формулы.

Но остальное просто «дайте мне сумму всех введенных значений для этой категории для этого пользователя за эту неделю / месяц / год».

Проблема заключается в том, что эти статистические данные также необходимо суммировать для подмножества пользователей для выбранного пользователя (поэтому в основном он будет возвращать сумму всех значений для всех пользователей в рамках пользователя, включая самого себя).

Это приложение работает в течение 2 лет, и оно выполняет свою работу довольно хорошо ... но с все большим количеством пользователей это также довольно медленно, когда дело доходит до серверных отчетов, типа "дать мне список всех пользователей в разделе" я и их статистика. Одна строка для их подгруппы и одна строка для их личной статистики "). Конечно, пользователи хотят (и нуждаются) в том, чтобы их отчеты были как можно более актуальными, 5 минут для отражения вновь введенных данных - это слишком много для них. И этот конкретный отчет является их любимым: / Чтобы оставаться в реальном времени, мы не можем напрямую выполнять высокоинтенсивные sqls ... Это убило бы сервер. Поэтому я вычисляю их только один раз с помощью фонового процесса, а веб-интерфейс просто читает результаты. Эти sqls трудно оптимизировать, и я рад, что я перешел от этого подхода ... (кэширование не вариант. См. Ниже.)

Текущее приложение выглядит так:

  • внешний интерфейс: когда пользователь вводит новые данные, они сохраняются в простую таблицу mysql, например [user_id, pointer_id, date, value], и также вставляются в очередь.

  • backend: затем идет процесс calc_daemon, который каждые 5 секунд проверяет очередь на наличие новых «повторных вычислений». Мы выводим запросы, определяем, что еще нужно пересчитать вместе с ним (у указателей есть зависимости ... простейший случай: когда вы меняете статистику за неделю, мы должны пересчитать статистику за месяц и год ...). Это делает этот пересчет простым способом. Мы выбираем данные с помощью настраиваемых SQL-запросов для каждого указателя, сгенерированных их классами.

  • эти вычисленные результаты затем записываются обратно в mysql, но в секционированные таблицы (одна таблица в год). Одна строка в этой таблице похожа на [user_id, pointer_id, month_value, w1_value, w2_value, w3_value, w4_value]. Таким образом, таблицы имеют ~ 500 тыс. Записей (я в основном сократил количество записей в 5 раз).
  • когда веб-интерфейсу нужны эти результаты, он делает простые суммы для этих секционированных данных с двумя объединениями (из-за вложенного набора conds).

Проблема в том, что эти простые sqls с суммами, group by и join-on-the-subtree могут занимать около 200 мс каждая ... только для нескольких записей ... и нам нужно запустить много этих sqls .. Я думаю, что они оптимизированы как можно лучше, согласно explain ... но они слишком сложны для этого.

Итак ... ВОПРОС:

Могу ли я переписать это, чтобы использовать Redis (или другое быстрое хранилище значений ключей) и увидеть какую-то выгоду от этого, когда я использую Ruby и Rails? Насколько я понимаю, если я перепишу его для использования redis, мне придется выполнить к нему гораздо больше запросов, чем к mysql, а затем выполнить сумму в ruby ​​вручную ... так что производительность может быть подорвана значительно ... я не совсем уверен, смогу ли я написать все возможные запросы, которые у меня сейчас есть с Redis ... Загрузка пользователей в рельсы, а затем сделать что-то вроде "Redis, дать мне сумму для пользователей 1,2,3, 4,5 ... "не похоже на правильную идею ... Но, может быть, есть какая-то особенность в redis, которая могла бы сделать это проще?) ...Также древовидная структура должна быть похожа на вложенный набор, то есть она не может иметь одну запись в redis со списком всех дочерних идентификаторов для некоторого пользователя (что-то вроде children_for_user_10: [1,2,3]), потому что древовидная структура часто меняется ... Это также причина, почему У меня не может быть этих сумм в этих секционированных таблицах, потому что, когда дерево меняется, мне придется все пересчитать ... Вот почему я выполняю эти суммы в реальном времени.)

Или вы бы предложили мне переписать это приложение на другой язык (java?) И вместо этого вычислить результаты в памяти? :) (Я пытался сделать это SOA-способом, но не получилось, что в итоге я так или иначе получаю XXX мегабайт данных в ruby ​​... особенно при генерации отчетов ... и gc просто убивает это .. .) (и побочным эффектом является то, что один генерирующий отчет блокирует все приложение rails: /)

Предложения приветствуются.

1 Ответ

0 голосов
/ 16 апреля 2012

Redis будет быстрее, это база данных в памяти, но вы можете разместить все эти данные в памяти?Как отмечается в комментариях, перебирать ключи redis не рекомендуется, поэтому я бы не стал использовать их для хранения необработанных данных.Тем не менее, Redis часто используется для хранения результатов сумм (например, регистрация количества событий), например, он имеет быструю команду INCR.

Я предполагаю, что вы получите достаточное улучшение скорости, используя хранимую процедуру или более быстрый язык, чем ruby ​​(например, C-inline или Go), чтобы выполнить пересчет.Вы занимаетесь групповым пересчетом?Можно ли изменить группирование по коду, который упорядочивает набор результатов, а затем вручную проверяет, когда «группа» изменяется.Например, если вы выполняете цикл по пользователю и группируете по неделям внутри цикла, измените его на порядок по пользователю и неделе и сохраните переменные для текущих и предыдущих значений пользователя и недели, а также переменные для сумм.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...