торнадо - перенос файла в cdn без блокировки - PullRequest
0 голосов
/ 23 декабря 2009

У меня есть модуль загрузки nginx, который обрабатывает загрузку с сайта, но мне все еще нужно перенести файлы (скажем, по 3-20 МБ каждый) на наш cdn, и я не хотел бы делегировать это фоновой работе.

Каков наилучший способ сделать это с торнадо, не блокируя другие запросы? Могу ли я сделать это в асинхронном обратном вызове?

Ответы [ 2 ]

5 голосов
/ 23 декабря 2009

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

Это позволит вам завершить загрузку через модуль nginx, затем в обработчике торнадо опубликовать сообщение, содержащее путь к загруженному файлу, и выйти. Отдельный процесс будет следить за этими сообщениями и обрабатывать передачу в ваш CDN. Этот тип службы будет полезен для многих других задач, которые могут быть обработаны в автономном режиме (отправка электронной почты и т. Д.). По мере роста вашей системы это также предоставляет вам механизм масштабирования, перемещая обработку очереди на отдельные машины.

Я использую архитектуру, очень похожую на эту. Просто добавьте процесс обработки сообщений в supervisord или что-либо еще, что вы используете для управления своими процессами.

С точки зрения реализации, если вы используете Ubuntu, установка RabbitMQ проста:

sudo apt-get install rabbitmq-server

В CentOS с репозиториями EPEL:

yum install rabbit-server

Существует несколько привязок Python к RabbitMQ. Pika является одним из них, и он создается сотрудником из LShift , ответственным за RabbitMQ.

Ниже приведен пример кода из репозитория Pika. Вы можете легко представить, как метод handle_delivery примет сообщение, содержащее путь к файлу, и отправит его в ваш CDN.

import sys
import pika
import asyncore

conn = pika.AsyncoreConnection(pika.ConnectionParameters(
        sys.argv[1] if len(sys.argv) > 1 else '127.0.0.1',
        credentials = pika.PlainCredentials('guest', 'guest')))

print 'Connected to %r' % (conn.server_properties,)

ch = conn.channel()
ch.queue_declare(queue="test", durable=True, exclusive=False, auto_delete=False)

should_quit = False

def handle_delivery(ch, method, header, body):
    print "method=%r" % (method,)
    print "header=%r" % (header,)
    print "  body=%r" % (body,)
    ch.basic_ack(delivery_tag = method.delivery_tag)

    global should_quit
    should_quit = True

tag = ch.basic_consume(handle_delivery, queue = 'test')
while conn.is_alive() and not should_quit:
    asyncore.loop(count = 1)
if conn.is_alive():
    ch.basic_cancel(tag)
    conn.close()

print conn.connection_close
0 голосов
/ 26 декабря 2009

совет по группе Google Tornado указывает на использование асинхронного обратного вызова (задокументировано в http://www.tornadoweb.org/documentation#non-blocking-asynchronous-requests) для перемещения файла в cdn.

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

При этом

все, что не требует для обработки в сети, не должно и должно быть отложено до очереди задач, например celeryd или аналогичной.

...