Умный запуск из крона, смотрим нагрузку сервера
Когда на сервере, или его кусочке - VDS, живут кроновые процессы (для СЕО продвижения, генерации контента и пр.) есть шансы не расчитать их интенсивность и положить сервер. Вообще-то, такие шансы есть и при хорошем просчете нагрузки, когда возникают временные затыки в сети/мускуле/прочем, и даже время, установленной посредством set_time_limit() оказывается превышенным.
Один из вариантов контроля за процессами состоит в независимой проверке времени выполнения, о чем я расскажу позже. Другой вариант - недопущение запуска скриптов из крона при критических условиях.
Сначала расскажу о том, как у меня организованы кроновые скрипты. Основная (программерская) проблема при их запускепроистекает из того, что скрипт должен вызываться как из коммандной строки (то есть вне апача), так и из браузера (для отладки). Эти два запуска происходят от имени разных юзеров, соответственно должен быть организован доступ к файлам - записав что-либо в файл (например, логи) не забудьте сделать ему chmod 0755, иначе запуски скрипта, пишушего в этот же файл под другим юзером слеят с Access Denied
Далее, у каждого уважающего себя софт-девелопера есть наборы тулзов, которые хранятся в отдельной папке и подключаются к скриптам без указания пути к этой папке, благодаря директиве include_path, установленной в файле .htaccess или php.ini. НО! При запуске из крона не задействуется апач и не обрабатывается .htaccess. Мне не нравится использование php.ini для этой цели, поскольку оно требует лишнего телодвижения при переезде на другой хостинг, а локальные php.ini могут и не обрабатываться при особо "удачной" настройке php (что опять-таки, потребует телодвижений).
А устанавливаю include_path я в специальном файле с названием cron.inc.php такого вида:
if (!isset($_SERVER['REMOTE_ADDR']))
{
ini_set('include_path',"./:../inc");
define('from_cron',1);
}
else
define('from_cron',0);
Этот файл находится в каждой папке, содержащей кроновые скрипты. Как видим, тут заодно устанавливается константа from_cron, которая может пригодиться.
Таким образом, структура кронового скрипта такова:
include "cron.inc.php"; include "моитулзы.inc.php"; // processing...
... и файл моитулзы.inc.php будет успешно подключаться как из браузера, так и из крона.
Вот в этом файле cron.inc.php мы и будем проверять текущую нагрузку сервера:
<?
class Cron_init
{
var $max_scripts_count = 1; // max number of scipts with the same names
var $max_loading = 0.2; // max CPU loading (from uptime command)
var $min_iddle = 70; // min CPU iddle
var $file2log = false; // file to log
function init()
{
$vmstat = `vmstat`;
if ($vmstat)
{
$vmstat = explode("\n",$vmstat);
$vmstat_keys = preg_split('/\s+/s',$vmstat[1]);
$vmstat_values = preg_split('/\s+/s',$vmstat[2]);
$vmstat = array();
for($i=0; $i<count($vmstat_keys); $i++)
{
$vmstat[$vmstat_keys[$i]] = $vmstat_values[$i];
}
if ($vmstat['id']<$this->min_iddle) $this->cancel('insufficient CPU iddle level');
}
$uptime = `uptime`; // format: 04:58:26 up 8 days, 18:19, 1 user, load average: 0.00, 0.00, 0.00
$m = preg_match_all('/\d{1,2}\.\d\d/i',$uptime,$machos);
if ($m)
{
list($one,$five,$fifteen) = $machos[0];
if ($one>$this->max_loading) $this->cancel('CPU loading');
}
$ps = `ps axu`;
$m = preg_match_all("|\d{1,2}:\d{2}[^\n;]+".$_SERVER['PHP_SELF']."[^\n;]*|",$ps,$machos);
if (!$m)
$clones = 0;
else
$clones = count($machos[0])-1;
if ($clones>=$this->max_scripts_count) $this->cancel("limit of copies of the script: $clones copy(s) found");
}
function cancel($reason)
{
if ($this->file2log)
{
error_log("\n".date("r")." Cancelling $_SERVER[PHP_SELF] due to $reason\n",3,$this->file2log);
@chmod($this->file2log,0755);
}
die();
}
}
if (!isset($_SERVER['REMOTE_ADDR']))
{
ini_set('include_path',"./:../inc");
define('from_cron',1);
$_ci = new Cron_init();
$_ci->file2log = "../logs/croninit.log";
$_ci->init();
}
else
define('from_cron',0);
?>
Как видим, здесь добавился класс Cron_init. Его задача - снять текущий скрипт если параметры нагрузки сервера превышают заданные. Параметры такие:
max_scripts_count - максимально допустимое количество копий текущего скрипта.
max_loading - максимально допустимая загрузка сервера (в терминах комманды uptime - средняя длина очереди процессов)
min_iddle - минимальный уровень тунеядства CPU :)
file2log - файл, в который будут писаться сообщения о снятии скриптов с дистанции.
Разумеется, для функционирования скрипта необходим доступ php к коммандной строке.

Recent comments
2 days 6 hours ago
2 days 6 hours ago
2 weeks 4 days ago
3 weeks 1 day ago
4 weeks 6 days ago
4 weeks 6 days ago
4 weeks 6 days ago
15 weeks 6 days ago
22 weeks 1 day ago
23 weeks 6 days ago