Очереди и фоновые воркеры — опора современной веб-архитектуры. Они разгружают приложение от тяжелых задач: отправка почты и push-уведомлений, генерация медиаконтента, интеграции, вебхуки, перерасчет кеша. На VDS мы сами решаем, кто будет следить за этими процессами, как их запускать, перезапускать и где хранить логи. На практике почти всегда выбор упирается в два варианта — Supervisor или systemd. Ниже — плюсы, минусы и готовые заготовки под php workers и laravel queue.
Зачем отдельные воркеры и очереди на VDS
HTTP-запросы должны быть быстрыми и предсказуемыми. Все, что может жить в фоне, уезжает в queues. Воркеры забирают задания из брокера (БД, Redis, AMQP) и выполняют их, не влияя на задержки веб-части. Это упрощает масштабирование: мы регулируем количество воркеров, приоритеты очередей, лимиты CPU и памяти независимо от фронтового трафика.
На VDS именно вы отвечаете за жизненный цикл процессов: автозапуск при старте, контроль падений, ограничения ресурсов, перезапуск при деплое (restart), хранение и ротация logs. Поэтому важно выбрать удобный механизм присмотра за воркерами и один раз аккуратно оформить базовый шаблон.
Supervisor vs systemd: что выбрать
Оба инструмента умеют запускать демоны, перезапускать их при сбое, собирать логи и управлять группами процессов. Разница — в культурном слое, интеграции с системой и возможностях тонкой настройки.
Когда Supervisor удобнее
Supervisor — классический процесс-менеджер на питоне, простой и понятный. Его любят за быстрый старт и удобные команды состояния. Он особенно привычен PHP-разработчикам благодаря множеству готовых примеров для laravel queue. Конфигурации компактны, просто копируются между серверами, легко собирать «группы» процессов (program/group) и держать по нескольку воркеров на очередь. Логи — отдельными файлами, с ротацией по размеру и бэкапами.
Минусы: дополнительная зависимость, отдельный демон, отдельная система логирования, меньше интеграции с лимитами ядра, cgroups и безопасностью. Некоторые корпоративные политики предпочитают чистый systemd без сторонних демонов.
Когда systemd логичнее
systemd — нативный для современных дистрибутивов. Он управляет автозапуском, зависимостями, лимитами CPU/IO/Memory, cgroups, изоляцией, журналом событий. Ядро и дистрибутив «знают» о ваших сервисах: их видно в systemctl, логи в journalctl, ресурсы регулируются без костылей. Перезапуск при деплое оформляется через ExecReload, а тонкая песочница и юнит-настройки помогают безопасности.
Из нюансов: конфигурации чуть многословнее, нужно понимать семантику типов сервисов (simple/notify/forking) и аккуратно работать с daemon-reload. Если предпочитаете хранить логи в файлах, а не в journald, понадобится минимальная донастройка.
Короткая сводка различий
- Простота старта: Supervisor проще на первых порах; systemd требует привыкания, но без сторонних зависимостей.
- Ресурсные лимиты и изоляция: systemd сильнее (cgroups, CPU/IO/Memory, sandboxing).
- Логи: Supervisor — файлы; systemd — journald (с возможностью перенаправления в syslog/файл).
- Операции и диагностика: оба хороши; в systemd единая точка управления для всей системы.
Если у вас типичный стек на PHP и первую очередь надо поднять «прямо сейчас» — начните с Supervisor. Если строите стандартизируемую базу под десятки сервисов, лимиты и безопасность — берите systemd.

Базовая схема для PHP workers и Laravel queue
PHP-воркеры, как правило, запускаются через CLI (без FPM): команда вроде php artisan queue:work или отдельный раннер. Важно задать:
- Очереди и приоритеты: например,
--queue=high,default,low. - Ограничения устойчивости:
--tries=3,--backoff=5,--timeout=120. - Обновление воркеров:
queue:restartпри деплое, либо--max-jobs/--max-time/--memoryдля регулярной «ротации» процесса и освобождения памяти. - Количество процессов: по числу ядер или немного меньше; ориентируйтесь на CPU-bound/IO-bound характер задач.
- Пользователь: не root, обычно
www-dataили отдельный системный пользователь проекта.
Примеры конфигураций
systemd unit для Laravel queue
[Unit]
Description=Laravel queue worker (high)
After=network.target
StartLimitIntervalSec=300
StartLimitBurst=10
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/project/current
Environment=APP_ENV=production
ExecStart=/usr/bin/php artisan queue:work --queue=high,default --sleep=2 --tries=3 --max-jobs=500 --max-time=3600 --memory=256
ExecReload=/usr/bin/php artisan queue:restart
Restart=always
RestartSec=5
# Управление ресурсами
CPUWeight=100
IOWeight=100
MemoryMax=512M
TasksMax=100
# Акуратное завершение
KillSignal=SIGTERM
TimeoutStopSec=30
# Логи в journald
StandardOutput=journal
StandardError=journal
SyslogIdentifier=laravel-queue-high
[Install]
WantedBy=multi-user.target
Поддерживайте по одному юниту на класс очереди (high/default/low). Для масштабирования добавляйте копии с суффиксами (laravel-queue-high@1.service, @2) или используйте шаблонные юниты. На деплой встраивайте systemctl reload — он дернет ExecReload, что безопасно для воркеров Laravel (они поймают флаг и gracefully завершатся).
Supervisor program для Laravel queue
[program:laravel-queue-high]
command=/usr/bin/php artisan queue:work --queue=high,default --sleep=2 --tries=3 --max-jobs=500 --max-time=3600 --memory=256
directory=/var/www/project/current
user=www-data
numprocs=2
autostart=true
autorestart=true
stopsignal=TERM
stopasgroup=true
killasgroup=true
stdout_logfile=/var/log/supervisor/laravel-queue-high.log
stdout_logfile_maxbytes=20MB
stdout_logfile_backups=5
redirect_stderr=true
environment=APP_ENV="production"
Команды управления: supervisorctl reread и supervisorctl update после изменения конфигов, supervisorctl status/start/stop/restart — для повседневных операций. На деплой — php artisan queue:restart или supervisorctl signal для мягкой смены процессов.
Перезапуски и деплой без простоев
Laravel queue:restart и graceful shutdown
php artisan queue:restart выставляет флаг в кеше, который улавливают воркеры: они завершают текущие задания и выходят. Это лучший способ «перезагрузить код» без сброса незавершенных задач и без потерь. В связке с --max-jobs и --max-time воркеры будут периодически перезапускаться сами, снижая риск накопления фрагментации памяти в долгоживущем процессе PHP.
Reload/Restart в systemd
В systemd используйте ExecReload с queue:restart, чтобы «мягко» обновить воркеры во время деплоя. Полный restart пригодится при критических сбоях, но помните: он прерывает процесс немедленно (если не дать время на TimeoutStopSec).
Rolling рестарт группы воркеров
Если у вас несколько воркеров на очередь (например, 4 процесса на high), обновляйте их по одному: отправьте reload юнитам с суффиксами, дайте им завершить задание, затем переходите к следующему. Это исключит провалы производительности на пике. В Supervisor того же эффекта можно добиться последовательными signal/restart конкретных процессов.
Перезапуск по ресурсам
Типичные ловушки — медленная деградация и утечки памяти. Для php workers почти обязательно задавайте --memory, --max-jobs и (по ситуации) --max-time. В systemd можно добавить MemoryMax, чтобы ядро завершало процесс при превышении (будет зафиксировано как failure и перезапущено). В Supervisor схожий эффект достигается периодической «ротацией» воркеров через --max-jobs и автоперезапуском.
Если запускаете периодические задачи, посмотрите системные таймеры как замену cron: это упрощает единое управление через systemd — подробности в материале systemd timers и cron.
Логи: journald, logrotate и файлы Supervisor
У логов два направления — трассировка проблем в реальном времени и долгосрочное хранение с ротацией. Ключевые задачи: видеть ошибки мгновенно, не терять историю и не заполнять диск.
systemd/journald
Для юнитов с StandardOutput=journal используйте journalctl -u <unit> -f для «хвоста» и journalctl -u <unit> --since "-1h" для разборов. Чтобы логи переживали перезагрузку, включите persistent-хранилище journald:
# /etc/systemd/journald.conf
Storage=persistent
SystemMaxUse=1G
RuntimeMaxUse=256M
RateLimitIntervalSec=30
RateLimitBurst=1000
После правок перезапустите journald. Такие лимиты удержат объем и не дадут логам бесконтрольно разрастись. При желании выведите логи юнита в syslog/файл через SyslogIdentifier и соответствующее правило в системе логирования.

Supervisor: файлы и ротация
Supervisor логирует stdout/stderr в файлы. Обязательно задавайте лимиты по размеру и бэкапам: stdout_logfile_maxbytes, stdout_logfile_backups, redirect_stderr=true. Если нужен классический logrotate — добавьте правило:
/var/log/supervisor/*.log {
daily
rotate 7
missingok
notifempty
compress
delaycompress
copytruncate
}
Не используйте «вечные» файлы без ротации: достаточно одной «слетевшей» задачи, чтобы размотать диск на сотни гигабайт.
Обслуживание и диагностика
- Статус и перезапуски:
systemctl status <unit>,systemctl restart <unit>,supervisorctl status,supervisorctl restart <program>. - Логи:
journalctl -u <unit> -fили «хвост» файла Supervisor. - Права и окружение: проверьте
User,WorkingDirectory,Environment, пути к PHP/интерпретатору, переменным доступа к Redis/DB. - Ограничения:
ulimit -n(кол-во файлов),LimitNOFILEв systemd, размеры памяти (в systemd —MemoryMax). - OOM killer: если воркеры гибнут без логов, проверьте
dmesg/journald на OOM и снизьте память или число процессов. - Таймауты и зависания: для Laravel уточните
--timeout,--backoff, оберните внешние вызовы в разумные таймауты (HTTP/DB).
Безопасность и производительность
- Не запускайте воркеры от root. Создайте отдельного пользователя или используйте
www-data. - В systemd применяйте песочницу:
NoNewPrivileges=true,PrivateTmp=true,ProtectSystem=full,ProtectHome=true— постепенно, проверяя совместимость. - Регулируйте нагрузку:
CPUWeight/IOWeight, при необходимостиCPUQuota, чтобы php workers не выжирали все ядра. - Делите очереди на классы: high/critical для пользовательских действий; default для обычных задач; low — для отложенных и тяжелых.
- Ставьте базовые лимиты устойчивости:
--tries,--backoff,--memory,--max-jobs. Это ваш страховочный трос.
Подбираете ресурсы под воркеры и очереди? Смотрите чек-лист по выбору конфигурации сервера в материалах про размеры инстанса: как выбрать план VDS по CPU и RAM.
Чек-лист запуска очередей на новом VDS
- Выбрать оркестратор: Supervisor (быстрый старт) или systemd (нативная интеграция, лимиты).
- Создать отдельного пользователя и директорию проекта с корректными правами.
- Определить очереди и приоритеты, задать параметры запуска воркеров (
--tries,--backoff,--timeout,--memory,--max-jobs). - Оформить конфиг: юнит systemd или program Supervisor. Включить автозапуск и autorestart.
- Настроить логи: journald с лимитами или файлы Supervisor с ротацией.
- Прописать процедуру деплоя:
queue:restartи последовательный reload/restart воркеров. - Поставить ресурсные лимиты: CPU/IO/Memory, лимиты на открытые файлы.
- Проверить graceful shutdown: симулировать рестарт во время выполнения задачи.
- Задокументировать команды оператора: как смотреть logs, как делать restart, в каких файлах лежат конфиги.
Итог
И Supervisor, и systemd надежно тянут фоновые процессы на VDS. Выбор — дело привычки и требований к интеграции с системой. Для проектов на PHP и laravel queue критичны три вещи: предсказуемые перезапуски (graceful restart с queue:restart), аккуратные лимиты ресурсов и понятная стратегия логирования/ротации. Сформируйте один выверенный шаблон, проверьте его под нагрузкой — и очереди будут работать стабильно, без сюрпризов на проде.


