تورنادو - نقل ملف إلى CDN دون الحظر
سؤال
لديّ تحميلات موقع وحدة تحميل NGINX ، ولكن ما زلت بحاجة إلى نقل الملفات (دعنا نقول 3-20 ميغابايت لكل منهما) إلى CDN لدينا ، ويفضل عدم تفويض ذلك إلى وظيفة الخلفية.
ما هي أفضل طريقة للقيام بذلك مع Tornado دون منع الطلبات الأخرى؟ هل يمكنني القيام بذلك في رد اتصال غير متزامن؟
المحلول 2
تشير المشورة بشأن مجموعة Tornado Google إلى استخدام رد اتصال Async (موثق في http://www.tornadoweb.org/documentation#non-locking-asynchronous-requests) لنقل الملف إلى CDN.
تكتب وحدة تحميل NGINX الملف إلى القرص ثم تمرر المعلمات التي تصف التحميل (s) مرة أخرى إلى العرض. لذلك ، فإن الملف ليس في الذاكرة ، ولكن الوقت الذي يستغرقه القراءة من القرص - مما قد يتسبب في حظر عملية الطلب نفسها ، ولكن ليس عمليات الإعصار الأخرى ، AFAIK - لا تذكر.
ومع ذلك ، أي شيء لا يفعل بحاجة إلى يجب أن تتم معالجتها عبر الإنترنت يجب ألا تكون كذلك ، ويجب تأجيلها إلى قائمة انتظار مهمة مثل celeryd
أو مشابه.
نصائح أخرى
قد تجدها مفيدة في الهندسة المعمارية الإجمالية لموقعك لإضافة خدمة قائمة انتظار الرسائل مثل الأرنب.
هذا من شأنه أن يتيح لك إكمال التحميل عبر وحدة Nginx ، ثم في معالج Tornado ، قم بنشر رسالة تحتوي على مسار الملف المحمّل والخروج. ستكون عملية منفصلة مشاهدة هذه الرسائل والتعامل مع النقل إلى CDN الخاص بك. سيكون هذا النوع من الخدمة مفيدًا للعديد من المهام الأخرى التي يمكن التعامل معها في وضع عدم الاتصال (إرسال رسائل البريد الإلكتروني ، إلخ ..). مع نمو نظامك ، يوفر لك هذا أيضًا آلية لتوسيع نطاقها عن طريق نقل معالجة قائمة الانتظار إلى آلات منفصلة.
أنا أستخدم بنية مشابهة جدًا لهذا. فقط تأكد من إضافة عملية المستهلك للرسالة إلى المشرف أو أي شيء تستخدمه لإدارة العمليات الخاصة بك.
من حيث التنفيذ ، إذا كنت في Ubuntu تثبيت RabbitMQ أمر بسيط:
sudo apt-get install rabbitmq-server
على centos w/epel مستودعات:
yum install rabbit-server
هناك عدد من روابط بيثون إلى الأرانب. بيكا هل أحدهم ويتم إنشاؤه بواسطة الموظف من lshift, ، المسؤول عن الأرانب.
أدناه قليلا من عينة من الرموز من Pika repo. يمكنك بسهولة أن تتخيل كيف ستقبل طريقة Handle_delivery رسالة تحتوي على filepath ودفعها إلى 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