Дизайн Django для экранов веб-аналитики, которые занимают очень много времени, чтобы вычислить

У меня есть экран «аналитической панели», который виден моим пользователям веб-приложений django, которые занимают очень много времени для расчета. Это один из этих экранов, который проходит через каждую транзакцию в базе данных для пользователя и дает им метрики.

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

Решение, которое приходит на ум, заключается в том, чтобы рассчитать это в бэкэнде с помощью команды manage.py batch, а затем просто отобразить кешированные значения пользователю. Существует ли шаблон дизайна Django для облегчения этих типов моделей / дисплеев?

3 Solutions collect form web for “Дизайн Django для экранов веб-аналитики, которые занимают очень много времени, чтобы вычислить”

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

Автономная обработка

Существует два широко используемых подхода к работе, которые должны выполняться вне цикла запроса-ответа:

  • Работы Cron (часто упрощаются с помощью команды пользовательского управления)
  • Сельдерей

В относительном выражении cron проще настроить, а Celery – более мощный / гибкий. Это говорит о том, что сельдерей обладает фантастической документацией и всеобъемлющим набором тестов. Я использовал его в производстве практически для каждого проекта, и хотя он требует определенных требований, на самом деле это не медведь для настройки.

Cron

Работы Cron – это проверенный временем метод. Если вам нужно всего лишь запустить некоторую логику и сохранить некоторый результат в базе данных, задание cron имеет нулевые зависимости. Единственные биткие биты с заданиями cron – это запуск вашего кода в контексте проекта django, т. Е. Ваш код должен правильно загружать ваши settings.py, чтобы узнать о вашей базе данных и приложениях. Для непосвященных это может привести к некоторому обострению в угадывании надлежащего PYTHONPATH и тому подобное.

Если вы идете по маршруту cron, хороший подход заключается в написании пользовательской команды управления. Вам будет легко проверять вашу команду с терминала (и писать тесты), и вам не нужно будет делать какие-либо специальные hoopla в верхней части вашей команды управления для настройки надлежащей среды django. В процессе производства вы просто запускаете path/to/manage.py yourcommand . Я не уверен, работает ли этот подход без помощи virtualenv , который вы действительно должны использовать независимо.

Еще один аспект, который следует рассмотреть с помощью cronjob: если ваша логика занимает определенное количество времени для запуска, cron не знает этого. Симпатичный способ убить ваш сервер – это запускать двухчасовую кронушку, как это каждый час. Вы можете свернуть свой собственный механизм блокировки, чтобы предотвратить это, просто имейте в виду, что начинается, поскольку короткий cronjob может не оставаться таким, когда ваши данные растут, или когда ваша RDBMS ошибочно и т. Д. И т. Д.

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

Сельдерей

… это колени пчелы. Обычно люди отпугивают требование «по умолчанию» брокера AMQP. Это не ужасно сложная настройка RabbitMQ, но для этого требуется немного выйти за пределы удобного мира Python. Для многих задач я просто использую redis как свой магазин задач для Celery. Настройки просты :

 CELERY_RESULT_BACKEND = "redis" REDIS_HOST = "localhost" REDIS_PORT = 6379 REDIS_DB = 0 REDIS_CONNECT_RETRY = True 

Voilá, не нужно брокера AMQP.

Сельдерей обладает множеством преимуществ перед простыми работами cron. Как и cron, вы можете планировать периодические задания , но вы также можете запускать задачи в ответ на другие стимулы, не поддерживая цикл запроса / ответа.

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

  1. Пользователь запрашивает страницу, содержащую диаграмму средних значений.
  2. Проверить кеш – есть ли хранимый, непростой запрос, содержащий средние значения для этого пользователя?
    • Если да, используйте это.
    • Если нет, уберите задачу сельдерея, чтобы пересчитать ее, потребовать и кешировать результат. Поскольку запрос существующих данных дешев, запустите запрос, если вы хотите показывать устаревшие данные пользователю.
  3. Если диаграмма устарела. необязательно указать некоторые признаки того, что диаграмма устарела, или сделать некоторые ajax fanciness для ping django так часто и спросить, готова ли обновленная диаграмма.

Вы могли бы объединить это с периодической задачей, чтобы пересчитывать график каждый час для пользователей, у которых есть активный сеанс, для предотвращения отображения действительно устаревших диаграмм. Это не единственный способ обмануть кошку, но он предоставляет вам весь необходимый вам контроль, чтобы обеспечить свежесть при одновременном регулировании загрузки процессора задачей вычисления. Лучше всего, периодическая задача и задача «по требованию» разделяют одну и ту же логику – вы определяете задачу один раз и вызываете ее из обоих мест для добавления СУШКИ.

Кэширование

Каркас кеша Django предоставляет вам все необходимые для кэширования кеширование, сколько вы хотите, сколько хотите. Большинство производственных сайтов полагаются на memcached в качестве своего кэша, я в последнее время начал использовать redis с бэкэндом django-redis-cache , но я не уверен, что буду доверять ему на крупном производственном сайте.

Вот несколько примеров, демонстрирующих использование низкоуровневого API кеширования для выполнения описанного выше рабочего процесса:

 import pickle from django.core.cache import cache from django.shortcuts import render from mytasks import calculate_stuff from celery.task import task @task def calculate_stuff(user_id): # ... do your work to update the averages ... # now pull the latest series averages = TransactionAverage.objects.filter(user=user_id, ...) # cache the pickled result for ten minutes cache.set("averages_%s" % user_id, pickle.dumps(averages), 60*10) def myview(request, user_id): ctx = {} cached = cache.get("averages_%s" % user_id, None) if cached: averages = pickle.loads(cached) # use the cached queryset else: # fetch the latest available data for now, same as in the task averages = TransactionAverage.objects.filter(user=user_id, ...) # fire off the celery task to update the information in the background calculate_stuff.delay(user_id) # doesn't happen in-process. ctx['stale_chart'] = True # display a warning, if you like ctx['averages'] = averages # ... do your other work ... render(request, 'my_template.html', ctx) 

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

Простейшим и ИМО правильным решением для таких сценариев является предварительное вычисление всего по мере обновления вещей, так что, когда пользователь видит панель мониторинга, вы ничего не вычисляете, а просто показываете уже вычисленные значения.

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

Для запуска такого вычисления в фоновом режиме я обычно использую сельдерей , поэтому предположим, что пользователь добавляет элемент foo в view view_foo , мы вызываем задачу update_foo_count которая будет выполняться в фоновом режиме и будет обновлять количество foo, update_foo_count вы можете установить таймер сельдерея, который будет обновляться подсчитывать каждые 10 минут, проверяя, нужно ли повторное вычисление, пересчитать флаг можно установить в разных местах, где пользователь обновляет данные.

Вам нужно взглянуть на структуру кеша Django .

  • Достаточно ли дьянго-поршень?
  • Ошибка при установке с помощью Pipeon «pip»: не удается получить индексный URL-адрес http: //
  • Добавить флажок и удалить действия с помощью настраиваемого администратора Django change_list
  • Доступ к внешнему ключу
  • Загрузка асинхронного файла в Amazon S3 с помощью Django
  • Как запустить оболочку django из Emacs?
  • Поддерживает ли core django миграцию без приложения django-south или подобного приложения?
  • Просмотр Django с возвратом json без использования шаблона
  • Django Gunicorn не загружает статические файлы
  • Добавление пользовательских действий на страницу администрирования UserModel
  • Автоматическое определение тестовой муфты
  • Python - лучший язык программирования в мире.