Обработка количества задач при сохранении производительности - PullRequest
2 голосов
/ 05 октября 2011

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

У меня есть приложение ruby ​​on rails с глобальной навигацией, которая содержит количество задач (см. Изображение ниже)

Global navitation with task counts

Проблема в том, что для генерации этих подсчетов требуются интенсивные запросы. И потому что это глобально, это на КАЖДОЙ странице. Они также должны обновляться, поскольку люди заботятся о задачах. Это делает его особенно сложным.

Тем не менее, сейчас я кеширую навигационный HTML в течение 10 минут через memcached. Если кто-то позаботится о задаче, да ладно. Нав обновляется каждые 10 минут. Ужасное решение, я знаю, но это моя мера остановки, пока я не найду правильное решение.

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

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

1 голос
/ 15 мая 2012

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

class User

  def counters
    needs_update(user_id)
    memcache.read(counter_user_id)
  end

  def needs_update(user_id)
      some_job_queue_for_counters.insert(Job.new(User.update_counters(user_id)))
  end

  #executed by the job runner
  def update_counters user_id
     counter_hash = {:counter1 => complex_logic1, :counter2 => complex_logic2 ...}
     memcache.write(counter_user_id, counter_hash.to_json.gzipped)
  end

end

Обратите внимание на пару моментов.

  1. Сделайте AJAX-вызов из браузера, скажем, раз в 1 минуту или более, в зависимости от времени выполнения счетчикалогика.
  2. Метод счетчиков работает настолько быстро, насколько это возможно, потому что memcache.read () возвращает сжатую строку json.Обработка нуля для генерации ответа.
  3. Вы можете разогреть кэш памяти для всех пользователей один раз при запуске приложения.Затем после этого обновления счетчика происходит только для пользователей, которые вызывают метод couters, т. Е. Для пользователей, которые сохранили браузер / мобильное приложение открытым.
  4. needs_update метод может объединять задания для user_id, чтобы избежать дублирования.
0 голосов
/ 05 октября 2011

Обновление:

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

Более сложное решение будет:

Кэшируйте это в 2 слоя (navHTML, а затем отдельные элементы / пользователи / элементы состояния).Вам нужно будет найти способ обновления области действия, чтобы они знали, для какого количества они должны инициировать сброс.Поэтому, если вы изменяете статус доставки на конечном автомате, вы должны сбросить все счетчики для этой доставки и удалить навигационный кеш для затронутых пользователей.

Я бы поместил все ключи для каждого элемента доставки в кэш в некотором пространстве имен, например, "delivery: 234324-user: 123-status", поэтому всякий раз, когда изменяется Delivery с id # 234324, вы выполняете итерацию иудалите все элементы кэша, которые принадлежат этой доставке (вероятно, лучше всего сохранять ее как можно более тупой).Вы можете вычислить и сохранить количество кешей, когда кто-то запрашивает страницу, и просто удаляет кеш при изменении реального объекта.Затем вы можете полностью кэшировать навигационный html, но всякий раз, когда что-то меняется с вашим пользователем и идентификатором (например, user-123), вы удаляете навигационный кеш, а также принудительно перезагружаете navHTML.Добавьте к этому некоторое время кеша для навигации (например, максимальный возраст 1 мин или что-то в этом роде), чтобы учесть ошибки.Элемент навигации должен создавать через кеш отдельных элементов, чтобы он не проходил через каждый элемент.

Возможно, вы захотите добавить Cache Sweeper, связанный с вашими связанными моделями http://guides.rubyonrails.org/caching_with_rails.html


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

http://railscasts.com/episodes/23-counter-cache-column

Этоможно использовать его автоматически с отношением has_many или обновлять счетчики вручную.Я предполагаю, что если ваша модель сложна и у вас есть отношение «многие ко многим», вы можете поместить счетчики в реляционный объект.

...