Написать в расписании cron * * * * * очень просто: задача запускается каждую минуту, и результат появляется почти сразу. Но эта короткая строка создаёт новый процесс 1440 раз в сутки и более сорока тысяч раз в месяц. Если каждый запуск — лёгкая проверка на полсекунды, вреда почти нет. Однако часто при этом загружается весь фреймворк сайта, открывается соединение с базой, и ресурсы тратятся даже тогда, когда делать нечего. В этой статье разберём, что именно ежеминутный cron делает с сервером и как использовать его разумно.
Во что обходится каждый запуск
Когда cron вызывает PHP-скрипт, сервер создаёт новый процесс PHP, загружает интерпретатор, читает и компилирует код. В WordPress или Laravel сверху загружается всё ядро, плагины и настройки, а в базу уходит несколько запросов. Всё это делается ради ответа на вопрос «есть ли работа?», и в большинстве случаев ответ — «нет». То есть процессорное время и память тратятся не на полезную работу, а на постоянную подготовку к ней.
На виртуальном хостинге на одном сервере работают сотни сайтов. Если каждый клиент добавит одну-две ежеминутные задачи, в начале каждой минуты одновременно просыпается множество процессов. Такой пик нагрузки сказывается на скорости ответа всех сайтов, включая ваш. Поэтому на многих тарифах ограничивают процессор и число процессов, и частый тяжёлый cron первым упирается в эти лимиты.
Наложение запусков — самый опасный случай
Проблема резко обостряется, когда скрипт работает дольше минуты. Допустим, внешний API отвечает медленно, и скрипт завис на 3 минуты. За это время cron запускает ещё две копии, они тоже зависают, затем ещё. За несколько минут десятки одинаковых процессов заполняют память, число подключений к базе достигает предела, и сайт начинает показывать «Database Error». Такой каскадный сбой часто случается ночью, когда никто не следит.
Самый простой способ защиты — блокировка через flock. Она не запустит новую копию, пока не завершится предыдущая, а просто пропустит запуск:
* * * * * /usr/bin/flock -n /tmp/queue.lock /usr/bin/php /var/www/user/data/www/misol.uz/cron/queue.php >> /var/www/user/data/logs/queue.log 2>&1
Вызов своего сайта через wget или curl
Некоторые инструкции советуют писать в cron команду вроде wget -q -O - https://misol.uz/cron.php. В этом случае задача проходит через веб-сервер: занимает один из воркеров PHP-FPM, стоит в одной очереди с посетителями и подчиняется таймаутам. Ежеминутный такой вызов отнимает воркеры, предназначенные для реальных пользователей. По возможности запускайте скрипт напрямую через PHP CLI — он не влияет на веб-очередь и лучше подходит для долгих задач.
Каким задачам действительно нужна каждая минута
Ежеминутная частота оправдана только там, где задержка ощутимо вредит: проверка статуса оплаты, отправка очереди SMS, коды подтверждения. Для обновления курса валют, генерации sitemap, очистки старых сессий или сбора статистики хватит раза в 15–30 минут, а то и раза в сутки. Задайте себе для каждой задачи вопрос: «что случится, если результат опоздает на 10 минут?» Если ответ — «ничего», снижайте частоту.
| Задача | Разумная частота | Выражение cron |
|---|---|---|
| Проверка статуса оплаты | каждые 1–2 минуты | */2 * * * * |
| Обновление курса валют | каждые 30 минут | */30 * * * * |
| Генерация sitemap | раз в сутки | 15 4 * * * |
| Очистка старых файлов | раз в неделю | 30 3 * * 0 |
Ещё одна полезная привычка — ставить задачи не на начало часа, а на произвольную минуту. Многие пишут 0 * * * *, и в начале каждого часа нагрузка на сервер резко растёт. Запись вроде 17 * * * * помогает обойти этот пик.
Лёгкая проверка, тяжёлая работа — только по необходимости
Если задачу действительно нужно проверять часто, сделайте начало скрипта максимально лёгким. Сначала выполняется дешёвая проверка — например, наличие файла-флага или один простой запрос к базе, — и только при наличии работы загружается фреймворк. Тогда большинство запусков завершаются мгновенно.
<?php
// cron/queue.php
if (!file_exists(__DIR__ . '/../data/queue.flag')) {
exit; // работы нет, фреймворк не загружается
}
require __DIR__ . '/../bootstrap.php';
// ... обработка очереди ...
unlink(__DIR__ . '/../data/queue.flag');
Тяжёлые, но несрочные задачи можно запускать с пониженным приоритетом. Команды nice и ionice дают процессу меньшую долю процессора и диска, и посетители сайта не замечают замедления:
15 4 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c3 /usr/bin/php /var/www/user/data/www/misol.uz/cron/sitemap.php >> /var/www/user/data/logs/sitemap.log 2>&1
Пример: сайт клиники
На сайте частной клиники в Ташкенте скрипт напоминаний о приёме запускался каждую минуту. Каждый раз он загружал всю CMS и вытягивал из базы все записи на завтра, хотя напоминаний в день было лишь несколько десятков. В утренние часы сайт тормозил, а в панели хостинга появлялись предупреждения о лимите процессора. Скрипт перевели на запуск раз в 10 минут, добавили flock и изменили запрос так, чтобы он брал только записи без отправленного напоминания. Пациенты по-прежнему получали напоминания вовремя, а сайт стал быстро работать и по утрам.
Измерьте нагрузку сами
Чтобы узнать, сколько времени и памяти занимает один запуск, выполните скрипт в терминале через /usr/bin/time -v. В выводе будут строки «Elapsed (wall clock) time» и «Maximum resident set size». Умножив эти значения на число запусков в сутки, вы увидите, сколько ресурсов задача потребляет в целом.
/usr/bin/time -v /usr/bin/php /var/www/user/data/www/misol.uz/cron/queue.php
На хостинге sayt.uz список и расписание заданий cron видны в панели ISPmanager, в которую вы входите из кабинета sayt.uz. Если сайт тормозит и непонятно, виноват ли cron, обратитесь в техподдержку — на стороне сервера можно посмотреть, какие процессы потребляют больше всего ресурсов.