Асинхронное распределенное выполнение задач. Stdlib, Celery,...

Preview:

DESCRIPTION

Автор: Роман Иманкулов (doist.io) Когда необходимо заставить веб-приложение выполнить тяжелую работу без ухудшения user experience, или нужно по-быстрому собрать кластер на коленке, возникает потребность в распределенном выполнении очередей команд. В докладе будут рассмотрены варианты организации таких очередей подручными средствами, будет выяснено, чем так хорош Celery, есть ли у него достойные альтернативы, и как написать рабочий менеджер очередей в тридцать строчек кода.

Citation preview

КЛАСТЕР НА КОЛЕНКЕCELERY, RQ, STDLIB И СОБСТВЕННЫЕ ВЕЛОСИПЕДЫ

Minsk Python Meetup, ноябрь 2013

 / Роман Иманкулов @rdotpy

ПАТТЕРН QUEUE

ПАТТЕРН QUEUE

CELERY — ТЯЖЕЛОВЕС АСИНХРОННОСТИ

CELERY — ИСПОЛЬЗОВАНИЕ ТРИВИАЛЬНОСоздали задачу (myworker.py)

from celery import Celeryapp = Celery('tasks', broker='redis://', backend='redis://')@app.taskdef sum(a, b): return a + b

Запустили worker

$ celery worker --app=myworker

CELERY — ИСПОЛЬЗОВАНИЕ ТРИВИАЛЬНОЗапустили задачу и получили результат

>>> async_result = sum.delay(2, 2)>>> print async_result.get()4

CELERY — ОТЛОЖЕННОЕ ВЫПОЛНЕНИЕКОМАНД

Задача будет выполнена не раньше, чем через 3 секунды

>>> sum.apply_async((2, 2), countdown=3).get()

CELERY — ПОВТОРНОЕ ВЫПОЛНЕНИЕКОМАНД

В случае неудачи задача будет выполнена повторно

@app.task(bind=True, max_retries=3)def get_url(self, url): try: return urllib2.urlopen(url).read() except IOError as exc: # попробовать выполнить задачу через 30 сек. # всего не более 3 попыток raise self.retry(exc=exc, countdown=30)

CELERY — ЗАМЕНА CRON-АОпределяем задачи для запуска

app.conf.CELERYBEAT_SCHEDULE = { 'add-every-30-seconds': { 'task': 'tasks.add', 'schedule': datetime.timedelta(seconds=30), 'args': (16, 16) },}

Запускаем Celery beat

$ celery beat

CELERY — ПРОДВИНУТЫЙ РОУТИНГЗапускаем несколько worker-ов

$ celery worker -Q premium$ nice celery worker # очередь по умолчанию

Распределяем задания по очередям

add.apply_async((2, 2), queue='premium')

CELERY CANVAS — ПЛАН АСИНХРОННЫХОПЕРАЦИЙ

Цепочка команд: асинхронное последовательное выполнение

>>> chain = (add.s(2, 2) | add.s(4) | add.s(8))>>> chain().get()16

Группа команд: асинхронное параллельное выполнение

>>> from celery import group>>> res = group(add.s(i, i) for i in xrange(10))()>>> res.get(timeout=1)[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

... a ещё chords, maps, starmaps и много чего ещё, что вам,возможно, никогда не пригодится.

RQ. ЛЕГКОВЕСНАЯАЛЬТЕРНАТИВА

RQ. ЗАПУСКАЕТ ВСЁСтарт worker-а

$ rqworker

Создаем очередь и отправляем в нее задачу

>>> q = rq.Queue(connection=redis.Redis())>>> job = q.enqueue(os.path.join, 'foo', 'bar')>>> print job.result'foo/bar'

RQ. ЗАПУСКАЕТ ВСЁ1.  Redis в качестве брокера и result storage2.  Нулевая настройка3.  Запуск любых импортируемых функций4.  Поддержка множества очередей5.  Простейшая система зависимостей задач

http://python-rq.org

ЧЕМ ЖЕ ОСОБЕННО ХОРОШ RQ?

ВОТ ЭТИМ ГРАФИКОМ!

СОБСТВЕННЫЕ МЕНЕДЖЕРЫ ОЧЕРЕДЕЙ

ЗАЧЕМ?Потому что простые решения сложных задач — это круче, чем

сложные — простых

THE BEST CODE IS NO CODE AT ALLJeff Atwood, Stackoverflow

MULTIPROCESSINGзапускает функции python в отдельных процессахAPI как у threadingимеет примитивы для обмена данными (queue, pipe)имеет примитивы для работы с shared-объектамиумеет работать по сети

MULTIPROCESSING

https://gist.github.com/imankulov/bbb49b57fc15ad171fa9

REDISLPUSH, BRPOP И ТРИДЦАТЬ СТРОК КОДА

https://gist.github.com/imankulov/702967fd559f718b4f1c

RQ ПРОТИВ НАШИХ РЕШЕНИЙ

СПАСИБО! ВОПРОСЫ? / Роман Иманкулов @rdotpy

Recommended