Сельдерей: обзор архитектуры и как она работает - Vinta Software

  1. Брокер
  2. Веб и рабочие узлы

Асинхронные очереди задач - это инструменты, позволяющие программным элементам запускаться на отдельном компьютере / процессе

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

В этой статье вы поймете, как работает очередь задач и каковы компоненты ее архитектуры. Мы сосредоточимся на Сельдерей , самый популярный инструмент для работы в проектах Python. Большинство других инструментов используют ту же архитектуру, поэтому принципы также применяются.

В общих чертах, причина, по которой мы используем очереди асинхронных задач, заключается в том, что мы хотим быстро отвечать нашим пользователям. Самый простой вариант использования для этого - делегировать длительные задания ЦП. Но самая популярная причина, по которой люди используют асинхронные задачи, - это выполнение внешних вызовов API. Всякий раз, когда вы зависите от внешних служб, вы больше не контролируете, сколько времени потребуется, чтобы быть готовым. Также может быть так, что они никогда не будут готовы, так как система может быть повреждена или сломана. Еще одно хорошее применение для асинхронных задач - это подготовка и кэширование значений результатов. Вы также можете использовать их для распространения массовых вставок в базу данных с течением времени. Это может помочь вам избежать DDoS'а в вашей собственной базе данных. Задания Cron - еще один хороший пример того, что вы можете с ними сделать. Существует множество инструментов для управления асинхронными задачами в Python. RQ кажется, в последнее время привлекают внимание, но Сельдерей пока что абсолютный чемпион

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

Затем потребители проверяют начало очереди на наличие ожидающих заданий, выбирают первое и выполняют

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

Брокер

Концепция брокера очень проста: очередь. Но каковы доступные способы реализации очереди в компьютерной системе? Одним из самых простых будет использовать текстовый файл. Текстовые файлы могут содержать последовательность описаний выполняемых заданий, поэтому мы можем использовать их в качестве посредника нашей системы. Проблема с текстовыми файлами заключается в том, что они не предназначены для решения реальных проблем приложений, таких как сеть и одновременный доступ. Из-за этого нам нужно что-то более надежное. С другой стороны, базы данных SQL способны работать в сети и работать с одновременным доступом. Проблема с ними в том, что они слишком медленные. Базы данных NoSQL, напротив, довольно быстрые, но во многих случаях им не хватает надежности. Поэтому при построении очередей мы должны использовать быстрые, надежные инструменты с поддержкой параллелизма, такие как RabbitMQ , Redis а также SQS ,

Сельдерей полностью поддерживает RabbitMQ и Redis. Хотя SQS и Работник зоопарка также доступны, они предлагаются с ограниченными возможностями. ( смотри здесь больше )

Веб и рабочие узлы

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

Вот очень простой пример задачи Celery и код для ее выполнения:

# Это происходит в `рабочем узле` из импорта из сельдерея. Celery app = Celery (...) @ app.task def add (a, b): return a + b # Это происходит в` веб-узле` из импорта импорта задач. г = доп. задержка (4, 5). get () print (r) # 9

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

Вот пример Django:

# Это происходит в `worker node` @ app.task def update_attendees (event, n): event.attendees_number = n event.save () # Это идет в` web node` event = Event.objects.get (name = 'DjangoCon') update_attendees.delay (событие, 9001)

В этом случае веб-узел ставит задачу обновить количество посетителей события. Обратите внимание, что мы передаем объект события в задачу. Не делай этого .

Не передавайте сложные объекты в качестве параметров задачи

Объекты сериализуются и сохраняются в брокере. Затем они десериализуются перед передачей на задание. Передача сложных объектов, таких как экземпляр модели, в качестве параметра сопряжена с несколькими проблемами. Прежде всего, в старых версиях Celery Pickle использовался как метод сериализации по умолчанию. Как вы, возможно, знаете, Pickle имеет уязвимости в безопасности. Допуская сложные объекты, вы увеличиваете шансы на разоблачение. Последняя версия Celery решает эту проблему, используя JSON в качестве метода сериализации по умолчанию. Что еще более важно: объект базы данных, который вы передали, может измениться между временем, когда вы ставите задачу, и временем ее выполнения. В этом случае вы будете работать с устаревшей версией.

Что вы хотите сделать, это передать идентификатор объекта и получить свежую копию из базы данных в начале задачи:

@ app.task def update_attendees (event_id, n): e = Event.objects.get (id = id_event) e.attendees_number = n e.save () e = Event.objects.get (name = 'DjangoCon') update_attendees. задержка (e.id, 9001)

В предыдущих примерах мы вызывали задержку и собирались вместе, как если бы они были одним действием. На самом деле это две разные вещи. Функция delay помещает задачу в очередь и возвращает обещание, которое можно использовать для отслеживания состояния и получения результата, когда он будет готов. Вызов get в этом обещании заблокирует выполнение до тех пор, пока результат не станет доступен. Задача добавления должна где-то хранить результат, чтобы к нему мог обращаться процесс, который его вызвал. Это означает, что мы пропустили часть архитектуры. Помимо веб, брокерских и рабочих компонентов, есть также бэкэнд для результатов.

Помимо веб, брокерских и рабочих компонентов, есть также бэкэнд для результатов

Бэкэнд результатов будет использоваться для хранения результатов задачи. На практике вы можете использовать тот же экземпляр, который вы используете для брокера, чтобы также хранить результаты. Есть и другие технологии Помимо поддерживаемых параметров брокера, которые могут быть использованы в качестве бэкэнда результатов в Celery, но есть некоторые различия в зависимости от того, что вы используете. Например, в Postgres метод get выполнит опрос, чтобы проверить, готов ли результат. Для других инструментов, таких как Redis, это делается по протоколу pub / sub.

Хорошо, это должно охватывать основы компонентов в архитектуре Celery. Надеюсь, что это помогло вам лучше понять, как это работает, и теперь вы чувствуете себя более уверенно.

Узнайте больше из нашего блога:
- Как убедиться, что ваши задачи Celery Beat работают
- Multitenancy: манипулирование данными клиентов в Django

Но каковы доступные способы реализации очереди в компьютерной системе?