Очереди и фоновые воркеры — опора современной веб-архитектуры. Они разгружают приложение от тяжелых задач: отправка почты и 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
), аккуратные лимиты ресурсов и понятная стратегия логирования/ротации. Сформируйте один выверенный шаблон, проверьте его под нагрузкой — и очереди будут работать стабильно, без сюрпризов на проде.