Готові до справжньої магії паралелізму? Сподіваюсь, що так, бо попереду в нас налаштування кількох воркерів, оптимізація ресурсів і правильний розподіл задач. Так, це той самий момент, коли ви відчуєте себе архітектором розподілених систем!
Коли ви проектуєте застосунок, можливо, доведеться виконувати багато фонових задач. Наприклад:
- Надсилання email-повідомлень після реєстрації.
- Обробка та рендеринг великих зображень.
- Збір аналітики в реальному часі.
Якщо виконувати кожну таку задачу послідовно, система просто задихнеться. Робочий процес буде повільним, сервери перевантаженими, а користувачі — розчаровані від марних очікувань.
Celery — інструмент, який дозволяє розподіляти і паралельно обробляти задачі, використовуючи багатопоточний підхід. Однак за замовчуванням Celery не працює на повну потужність. Щоб розкрити весь потенціал цього інструменту, треба налаштувати паралельну обробку.
Налаштування Celery для паралельної обробки
Celery використовує концепцію воркерів (workers). Воркер — це процес, який приймає задачі з черги та виконує їх. Чим більше у вас воркерів, тим більше задач ваша система може обробляти одночасно.
Якщо ви ще не додали Celery у проєкт, саме час це зробити. Переконайтесь, що у вас встановлений Python версії 3.8+ і база даних (наприклад, Redis) для зберігання черг.
pip install celery[redis]
Ми будемо використовувати Redis як брокер повідомлень, але ви можете вибрати RabbitMQ (він навіть бажаніший для великих проєктів).
Якщо ви не знайомі з початковим налаштуванням Celery, раджу заглянути в офіційну документацію Celery і освіжити базові налаштування.
Тепер налаштуємо конфігурацію. Ось приклад файлу celery.py для вашого проєкту:
from celery import Celery
# Ініціалізація Celery додатку
app = Celery(
'my_project',
broker='redis://localhost:6379/0', # Використовуємо Redis як брокер
backend='redis://localhost:6379/0' # Redis як backend для результатів
)
# Загальні налаштування для Celery
app.conf.update(
task_track_started=True, # Відстежуємо старт задач
result_expires=3600, # Результати задач дійсні протягом години
)
# Автоматичний імпорт задач з tasks.py
app.autodiscover_tasks(['tasks'])
Тепер всі задачі у вашому проєкті будуть "люб'язно" передаватися воркерам через Redis.
Додавання паралелізму
Паралельна обробка в Celery налаштовується через запуск кількох воркерів. Розберемо основу цього процесу.
Кількість воркерів залежить від:
- Кількості ядер процесора.
- Доступної пам'яті.
- Навантаження на вашу систему.
Для більшості застосунків можна починати з базового рівня: одного воркера на ядро процесора. Наприклад, якщо на сервері 4 ядра, запускайте 4 воркери.
Запуск воркерів
Використайте наступну команду для запуску кількох воркерів:
celery -A my_project worker --loglevel=info --concurrency=4
Тут:
-A my_project— вказує на ім'я вашого Celery додатку.--loglevel=info— встановлює рівень логування (debug, info, warning).--concurrency=4— задає кількість воркерів.
Запустивши цю команду, ви побачите вивід з інформацією про воркерів. Кожен воркер буде виконувати задачі у своєму оточенні.
Налаштування ресурсів для воркерів
Щоб уникнути "падіння" сервера через витоки пам'яті (або просто великі об'єми даних), можна обмежити використання пам'яті воркером. Це досягається за допомогою параметра --maxtasksperchild:
celery -A my_project worker --loglevel=info --concurrency=4 --maxtasksperchild=100
Кожен воркер буде перезапущений після виконання 100 задач. Це корисно для довговічних воркерів.
Щоб обмежити кількість задач, які воркер бере "за раз", можна використати конфігурацію worker_prefetch_multiplier:
app.conf.worker_prefetch_multiplier = 1
Це змушує воркер обробляти лише одну задачу за раз, замість того щоб "захоплювати" кілька задач з черги.
Запуск воркерів у продакшені
У реальних застосунках ви, швидше за все, не будете запускати воркерів вручну (інакше навіщо нам DevOps та автоматизація?). Використовуйте інструменти, такі як Systemd або Docker.
Наведемо приклад запуску через Systemd.
Створимо файл сервісу для запуску воркера:
[Unit]
Description=Celery Worker
After=network.target
[Service]
User=celery
Group=celery
WorkingDirectory=/path/to/your/project
ExecStart=/path/to/venv/bin/celery -A my_project worker --loglevel=info --concurrency=4
Restart=always
[Install]
WantedBy=multi-user.target
Тепер ваші воркери будуть перезапускатися автоматично у разі відмови.
Використання Docker
Якщо ви розгортаєте застосунок через Docker, налаштування воркерів стає ще простішим. Ось приклад docker-compose.yaml:
version: '3'
services:
broker:
image: redis:5.0
ports:
- "6379:6379"
worker:
image: my_project_image
command: celery -A my_project worker --loglevel=info --concurrency=4
environment:
- CELERY_BROKER_URL=redis://broker:6379/0
depends_on:
- broker
За допомогою Docker ви можете легко масштабувати кількість воркерів, додаючи більше контейнерів.
Перевірка працездатності
Після налаштування запустимо просту задачу. Приклад файлу tasks.py:
from celery import shared_task
import time
@shared_task
def add(x, y):
time.sleep(5) # Імітація довгої задачі
return x + y
Тепер запустіть задачу:
from tasks import add
result = add.delay(4, 6)
print(f"Task ID: {result.id}")
print(f"Task Status: {result.status}") # Друкує статус (Pending, Started, Success)
Ви можете подивитись результат виконання задачі через деякий час:
print(result.get(timeout=10))
Типові помилки
Проблема: воркери "захоплюють" забагато задач і не справляються з навантаженням.
Рішення: встановіть worker_prefetch_multiplier і перевірте споживання пам'яті.
Проблема: задачі "зависають" у черзі.
Рішення: перевірте підключення до брокера й рівень логування (--loglevel=debug).
Тепер вам доступна вся сила паралельної обробки Celery. Ви можете масштабувати свою систему, додавати воркерів і налаштовувати їх під конкретні сценарії. Пам'ятайте: коктейль з Celery та RabbitMQ може творити дива, якщо його грамотно "збовтати". 😉
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ