چگونه درخواست‌های زمان‌بر را در جنگو هندل کنیم یا رساله‌ در حکمت مطلقه‌ی celery

ساختار تعاملی کاربر/django/RabbitMQ/Celeryشاید براتون پیش اومده باشه که با افزایش لود سرور، سرورتون موقع پاسخ به ریکوئست‌ها خیلی کند عمل کنه. یک کاری که برای مقابله با این اتفاق می‌شه انجام داد اینه که، یک سری تسک‌هایی رُ پیدا کنیم که باید در موقع درخواست کاربر انجام بشن ولی دو شرط زیر رُ داشته باشن:۱. اجرای بلافاصله‌ی آن‌ها الزامی نباشه۲. در پاسخی که به کاربر می‌دیم تغییری ایجاد نکنه(به نوعی در بالایی هم اومده!)حالا با پیدا کردن این تسک‌ها، اون‌ها رُ توی یک صف می‌ذاریم و در نهایت اون‌ها رُ با یه ترتیبی در پشت‌زمینه انجام می‌دیم.مثال واقعیدر ابتدای کار ما در بیستون با یک اپلیکیشن شروع کردیم، و این اپلیکیشن حدود ۱۰۰ کاربر فعال داشت. با کمک uWsgi و nginx لود این کاربرها و هندل می‌شد. با گذشت زمان و بیشتر شدن اپلیکیشن‌ها و همچنین کاربرانمان، با لود وحشتناکی مواجه شدیم! میانگین زمان پاسخ‌گویی بسیار بالا (در حد ۲۰ ثانیه) رسید و ما برای ارسال کد فعال‌سازی با مشکلات فراوانی روبرو شدیم. اولین کاری که باید می‌کردیم این بود که فرآیندی پیدا کنیم تا بتوانیم از رفع شدن مشکل مطلع شویم!برای این کار به ابزار استرس تست ab (مال حضرت آپاچی) رو آوردیم (در فرصت‌های آتی، عمری باشه خدمتتون این رُ هم می‌گم ولی فقط موقع بازی باهاش مواظب باشین به خودتونو DoS نکنین :) ). حالا می‌تونستیم با هر تغییر بطور دقیق میانگین زمان پاسخ را با شرایط تقریبا مساوی بسنجیم.لطفا خودتون رُ Dos نکنین :),oالبته کاربر دیگری که برای ما داشت، انجام بعضی فرآیند‌های گزارش‌گیری زمان‌بر بود که با استفاده از سلری در پشت پرده انجام می‌شود.بطور خلاصه celery چطوری کار می‌کنه؟جنگو به یک message broker (اینجا ما از RabbitMQ استفاده کردیم ولی شما می‌تونین از ردیس یا چیزهای دیگه هم استفاده کنین) یک پیامی (تسکی) رُ می‌فرسته. message broker هم این پیام رُ به یکی از ورکرهایی که مختص این کاره ارجاع می‌ده. در مرحله‌ی آخر هم ورکر مربوطه کار رُ‌ در پشت پرده انجام می‌ده و تمام :)یک مثال از پیاده‌سازیدر این مثال فرض شده سیستم عاملتون اوبونتو هست ولی اگه از سیستم عامل دیگه‌ای استفاده می‌کنین sudo supervisorctl rereadsudo supervisorctl updatesudo supervisorctl start celeryمی‌تونین با یه سری تغییرات ریز از همین دستورات استفاده کنین.اول باید بروکر رُ نصب کنیم، که اینجا ما از RabbitMQ استفاده می‌کنیم:sudo apt-get install rabbitmq-serverحالا باید RabbitMQ رُ تنظیم کنیم:sudo rabbitmqctl add_user [user_name] [password] sudo rabbitmqctl add_vhost [vhost_name] sudo rabbitmqctl set_permissions -p [vhost_name] [user_name] &quot.*&quot &quot.*&quot &quot.*&quotدر این‌جا باید قسمت‌های که بولد شدن رُ خودتون ست کنین. دقت کنین که ما اینجا همه‌ی پرمیشن‌ها روی virtural host رُ به یوزری که تازه ساختیم می‌دیم. اگه کاربری خاصی دارین به این موضوع دقت کنین.حالا باید celery رُ نصب کنیم. دقت کنین که اگه دارین از virtual env خاصی استفاده می‌کنین حتما مراحل نصب رُ روی اون env خاص اجرا کنین:pip install celeryحالا توی پروژه‌ی جنگوتون در فایل settings.py این‌ها رُ اضافه کنین:BROKER_URL = 'amqp://guest:guest@localhost:5672//' CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json'در کنار فایل settings.py یک فایل جدید به نام celery.py ایجاد کنین و این‌ها رُ داخلش بذارین:from __future__ import absolute_import import os from celery import Celery from django.conf import settings os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project_name.settings') app = Celery('project_name') app.config_from_object('django.conf:settings') #این قسمت باعث می‌شه که اپلیکیشن بتونه تسک‌هایی که برای سلری تعریف می‌شه رُ # خودکار تشخیص بده app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)و در نهایت فایل __init__.py رُ به این صورت تغییر بدین:from __future__ import absolute_import from .celery import app as celery_appحالا کافیه برای هر تسکی که می‌خواین توی پشت‌زمینه اجرا بشه یک انوتیشن @shared_task بذارین:@shared_task def handle_notification(text, keyword, channel, sender, reciever, notification_id, req_ip=None): pass # یه کار خفن طولانی :)حالا هر جا لازمه از این متد استفاده کنین کافیه اینطوری صداش کنین:handle_notification.delay(text, keyword, channel, sender, reciever, notification_id,ip)حالا تنها کاری که باید بکنیم اینه که سلری رُ ران کنیم. برای این‌که بصورت سرویس ران بشه ما از supervisor استفاده می‌کنیم:sudo apt-get install supervisorحالا یک فایل با اسم celery.conf برای سلری می‌سازیم و این‌ها رُ داخلش می‌ذاریم:[program:celery] command=[path_to_your_virtual_env]/bin/celery --app=project_name worker --loglevel=INFO directory=[path_to_your_project] user=[system_user_name] autostart=true autorestart=true redirect_stderr=trueو در نهایت با اجرای این دستورات کارمون تموم می‌شه:sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start celeryتوجه داشته باشین که این فقط یه کاربرد خیلی محدود از سلری هست و کارهای خفن بیشتری باهاش می‌شه کرد، که توصیه می‌کنم حتما دنبالش برین :)پی‌نوشت:عکس اول از اینجا برداشتم.