Асинхронные задания в Django
Асинхронные задания в Django
Кирилл Перевозчиков @ DataRobot
github.com/Axik
О чём будет идти речь?
- Обзор очередей задач используемых в Django.
- Определим когда использовать то, или иное исполнение
- Преимущества & недостатки
- Pro tips & trics (Maybe not so "Pro").
"Очереди задач" и "асинхронные очереди задач" - оба термина означают "Asynchronous task queue" в Django-мире.
Нужно ли использовать очереди задач?
Django блокирующийся фреймворк
Нужно, если в цикле request-response существует операция существенная повышающая время задержки ответа.
Типичные примеры
- Рассылка электронных писем
- Вытягивание большого количества данных с third-party web-сервиса
- Insert или Update большого количества объектов в БД
- Выполнение времязатратных вычислений
- Отправка или обработка web-hooks
Окей, Google
"Django task queue project"
Celery
Pros:
- Стандарт для Django
- Можно использовать разные исполнения брокеров
- Гибкий в настройке
- Отлично подходит для больших проектов
Celery
Cons:
- Гибкий в настройке
- Тяжеловесный: множество процессов + external dependencies
- Неподходит для маленьких приложений
- Исходный код нечитабелен. 27k lines
Celery
Celery
Redis Queue
Pros:
- Гибкий в настройке
- Менее требовательный к памяти, чем Celery
- Отлично подходит для средних и маленьких проектов
- 3k lines. Прост и понятен.
Redis Queue
Cons:
- Только redis как брокер.
- Менее гибкая система настройки очереди, чем Celery
- Воркеры могут быть только Python.
- Простые плюшки задач по расписанию или Django-админки отсутствуют из коробки.
Django-background-tasks
Pros:
- Очень прост в настройке
- Очень прост в использовании
- Не требует дополнительных зависимостей, использует
Django ORM как брокер.
- Отлично подходит для прототипов, либо маленьких проектов
Django-background-tasks
Cons:
Какой же выбрать?
Сложная специальная логика для очереди, распределённая система воркеров?
Celery
Какой же выбрать?
Отсутствует специальная логика для очереди, не нужна распределённая система воркеров и хочется понимать исходный код библиотеки?
Redis Queue + Django RQ + RQ-Scheduler
Какой же выбрать?
Прототип на вчера, и не охота возиться с Redis?
Django-background-task
Celery case. RabbitMQ vs. Redis.
RabbitMQ
- Гибко настраиваемая маршрутизация
- Persistent queues (Гарантированная доставка)
Celery case. RabbitMQ vs. Redis.
Redis
- Высокая скорость обработки сообщений по сравнению с RabbitMQ
- Можно использовать одновременно и как key-value storage и как брокер в одной системе
Celery case. RabbitMQ vs. Redis.
Winner?
Redis, если:
-
Хочется лёгкого деплоя без заморочек
-
Отсутствие гарантированной доставки не критично.
Celery case. RabbitMQ vs. Redis.
Winner?
RabbitMQ, если:
-
Гарантированная доставка критична
-
Хочется использовать стабильное, используемое решение с солидной технической базой.
-
Advanced routing.
Redis не быстрее RabbitMQ
tasks.py
from celery import Celery
celery = Celery('tasks', broker='amqp://guest@localhost//')
#celery = Celery('tasks', broker='redis://localhost//')
@celery.task
def newtask(somestr, dt, value):
pass
test.py
from tasks import newtask
from datetime import datetime
import time
dt = datetime.utcnow()
st_time = time.time()
for i in xrange(100000):
newtask.delay('shortstring', dt, 67.8)
print(time.time() - st_time)
Запускаем celery worker
time celery -A tasks worker --loglevel=info -f tasks.log --concurrency 1
Результаты
Операция |
Попытка 1 |
Попытка 2 |
Попытка 3 |
Среднее |
Цена одного сообщения |
RabbitMQ - Добавление задачи в очередь |
56.96 |
54.18 |
57.13 |
56.09 |
0.0005609 |
Redis - Добавление задачи в очередь |
68.81 |
76.52 |
76.95 |
74.09 |
0.0007409 |
RabbitMQ - Обработка сообщения из очереди |
122.406 |
132.55 |
195.885 |
150.28 |
0.0015028 |
Redis - Обработка сообщения из очереди |
157.59 |
177.774 |
186.332 |
173.9 |
0.001739 |
Время добавление в очередь RabbitMQ составляет 75% от времени Redis.
Время обработки сообщения - 86%.
Не используйте базу данных как брокер.
Используйте больше, чем одну очередь для разных задач
Храните результаты выполнения, только если они вам нужны
Не передавать Django-ORM объекты в задачу.
Старайтесь передавать json-serializeble данные в функцию-задачи.
Применяйте философию views.py для tasks.py
Отложенные задачи, не значит бесплатные
Monitoring
- Flower для celery.
- Django-rq для Redis Queue.
Периодические очищайте "умершие" задачи
Используйте отдельную очередь для повтора задач с ошибкой