LINUX.ORG.RU
ФорумAdmin

Отлов зависших php скриптов, на сервере


0

1

Подскажите чем лучше отлавливать php скрипты по нагрузке на процессор и времени выполнения, есть Сервер, на нем крутится апач2 с виртуальными хостами > 100 сайтов, дочерний процесс апача от имени пользователя стартует, у каждого виртуального хоста свой пользователь заведен. Начал с парсера mod_stat apache, но такой костыль выходит... Может есть по эффективней что нибудь?

Хочется ловить скрипты с завышенным time limit, и CPU% аварийно завершать их, и складывать в лог т.к. чудо сайтов с вирусами и криворуким кодом очень много. Что посоветуете?

CentOS 6.3



Последнее исправление: commeta (всего исправлений: 1)

присоединяюсь к вопросу

r0ck3r ★★★★★
()

Хочется ловить скрипты с завышенным time limit, и CPU% аварийно

Чем не устраивает http://php.net/manual/ru/function.set-time-limit.php

Он будет делать работу за вас. В логе смотрите по статусу все скрипты.

zgen ★★★★★
()
Последнее исправление: zgen (всего исправлений: 2)

One alternative would to attempt to kill all the Apache processes using PHP. It will send a kill signal to all Apache processes, except the one it is running under. This might work if the Apache process running under a shared process without setuid(). Attempt at your own risk.

http://stackoverflow.com/a/13847598

по ссылке пример скрипта, убивающего лишние процессы.

как насчет такого?

rikardoac
()

как это делать грамотно: все HTTP запросы идут через единую точку входа (тут у большинства будет облом) в которой записывается время старта и pid (по возможности параметры запроса для последующего диагноза), по выполнении запроса записи удаляются, в какойнить убогой java - вся эта инфа болталась бы в памяти.

в дальнейшем внешний демон (в тойже убогой яве простой поток из памяти) берет эти записи и грохает те что задержались на этом свете

Deleted
()

Сегодня ковырялся, вычищал вирус. Запустил чекалку - таймаут, гад отрабатывал, НО отваливался браузер (ч/з 30 сек), а процесс php-cgi продолжал висеть!

С другой стороны в FAQ на чекалку были упомянуты квоты по использованию проца (как причина несрабатывания).

ziemin ★★
()
Ответ на: комментарий от rikardoac

http://stackoverflow.com/a/13847598
по ссылке пример скрипта, убивающего лишние процессы.

этот скрипт просто убивает процессы определенного пользователя.

commeta
() автор топика
Ответ на: комментарий от Deleted

все HTTP запросы идут через единую точку входа (тут у большинства будет облом) в которой записывается время старта и pid (по возможности параметры запроса для последующего диагноза)

Предлагаешь модуль для апача создавать?

commeta
() автор топика
Ответ на: комментарий от commeta

предлагаю перед тем как писать на пхп подумать и писать так чтобы сия задача решалась парой строчек.

Deleted
()
Ответ на: комментарий от Deleted

предлагаю перед тем как писать на пхп подумать и писать так чтобы сия задача решалась парой строчек.

это надо бы разработчикам посоветовать на досуге, да вот беда сайтов больше сотни на сервере и кто их делал понятия не имею, а админу только и остается что чужой криворукий код на уровне процессов отрубать

commeta
() автор топика
Ответ на: комментарий от Deleted

ну у тебя в топике не написано что это сервер с произвольными php чудоскриптами.

Исправил.

commeta
() автор топика

Написать ещё один который будет их опрашивать, а они корректно отвечать, ответил значит трудится, не ответил убить.

Dron ★★★★★
()
Ответ на: комментарий от Dron

Написать ещё один который будет их опрашивать, а они корректно отвечать, ответил значит трудится, не ответил убить.

ребят я может как то не так выразился... но сервер с сайтами в продакшене, там движки, самописные сайты, и т.д. скриптов больше 10000

commeta
() автор топика
Ответ на: комментарий от commeta

тем что любой вебмастер используя функцию set_time_limit может заставить работать скрипт бесконечно.

Посмотрите сами по теме:

http://www.php.net/manual/ru/info.configuration.php#ini.max-execution-time

Выставляете, переводите в safe mode.

zgen ★★★★★
()
ps axwo pid,user,comm,etime | grep httpd | grep -vE '(root|www)'

вот тебе все дети с пидами и временем работы в формате mm:ss - а дальше решай что с ними делать. скрипт по крону раз в минуту. да, у линуксового ps аргументы могут отличаться но такой функционал есть, это решение для бсд.

Komintern ★★★★★
()
Ответ на: комментарий от zgen

переводите в safe mode

большинство кривого кода не работает в safe mode

Komintern ★★★★★
()
Ответ на: комментарий от Komintern

не, с безопасным режимом куча других проблем появляется.

ps axwo pid,user,comm,etime | grep httpd | grep -vE '(root|www)'

в этом случае не видно скрипта создающего проблемы

commeta
() автор топика
Ответ на: комментарий от commeta

если кому интересно вот костыль, требует mod_stat apache, умеет ловить и завершать скрипты и складывать в лог, по идее на си надо переписывать если ничего лучше не придумаю.

<?php
error_reporting(E_ERROR);
$statusurl= "http://127.0.0.1:81/server-status";

class parse_server_status {
	var $parseUrl;
	function parse_server_status($url) {
		$this->parseUrl = $url;
	}
	
	function getActiveConnections() {
		$f = implode(file($this->parseUrl."?dat=".time()),"");
		
		$f = $this->str_nach($f,"Srv");
		$f = $this->str_nach($f,"</tr>");
		
		$f = $this->str_bis($f,"<hr />");
		$f = $this->str_bis($f,"</table>");
		
		$f2 = explode("</tr>", $f);
		
		$active = array();
		
		for($i=0;$i<count($f2);$i++) {
			// {{{
			$l = $f2[$i];
			$l = str_replace("<tr>", "", $l);
			$l = str_replace("<td nowrap>", "<td>", $l);
			
			$c = explode("</td><td>", $l);
			
			for($j=0;$j<count($c);$j++) {
				// {{{
				$c[$j] = trim($c[$j]);
				// }}}
			}
			
			
			if($c[3]!="." && !stristr($c[12],"server-status") && $c[11]!="?") {
				
				$c[11] = str_replace("www.","",$c[11]);
				
				$active[] = array("PID" => $c[1],
						  "M" => strip_tags($c[3]),
						  "SS" => strip_tags($c[5]),
						  "CPU" => strip_tags($c[4]),
						  "VHost" => strip_tags($c[11]),
						  "Request" => strip_tags($c[12])
						  ); 
			}
		}
		
		$active = $this->array_sort($active, "VHost");

		return($active);
	}
	
	
	function str_bis($haystack, $needle) {
		$s = substr($haystack, 0, strpos($haystack, $needle) );
		return($s);
	}
	
	function str_nach($haystack, $needle) {
		$s = substr($haystack, strpos($haystack, $needle)+strlen($needle) );
		return($s);
	}
	
	function str_zwischen($haystack, $needle1, $needle2) {
		$s = str_nach($haystack, $needle1);
		$s = str_bis($s, $needle2);
		return($s);
	}
	
	function str_zwischenKlammer($T, $von, $bis) {
		$i = strpos($T, $von);
		$neu = "";
		if(!stristr($T, $von)) return;
		$T = substr($T, $i+strlen($von));
		$j=0;
		for($k=0;$k<strlen($T);$k++) {
			$c = substr($T, $k,1);
			if($c=="(") $j++;
			if($c==")") {
				if($j<=0) return($neu);
				else $j--;
			}
			$neu .= $c;
		}
	}
	function array_sort($array, $key, $direction="asc") {
	   for ($i = 0; $i < sizeof($array); $i++) {
		   $sort_values[$i] = $array[$i][$key];
	   }
	   if($direction=="asc") asort ($sort_values); else arsort($sort_values);
	   reset ($sort_values);
	   while (list ($arr_key, $arr_val) = each ($sort_values)) {
			 $sorted_arr[] = $array[$arr_key];
	   }
	   return $sorted_arr;
	}	
	
}

$PSS = new parse_server_status($statusurl);

function saveLogFile($logging){
    if (is_writable('/var/log/logPHPlongTime')) {
	if (!$handle = fopen('/var/log/logPHPlongTime', 'a')) die("unable to open log file!");
	if (fwrite($handle, $logging) === FALSE)  die("unable to write log file!");
	fclose($handle);
    } else {
	die("log file is not writable");
    }
}

while(true){
    $active = $PSS->getActiveConnections();

    for($i=1;$i<count($active);$i++){
	if( $active[$i][SS] > 80 && $active[$i][M] == "W") {
	    // $active[$i][PID] // PID OS process ID
	    // $active[$i][SS] // SS Seconds since beginning of most recent request
	    // $active[$i][VHost] //Vhost
	    // $active[$i][M] //Mode of operation
	    // $active[$i][Request] //Request
	    saveLogFile($active[$i][VHost]." ".$active[$i][Request]." ".$active[$i][SS]."\n");
	    exec( "kill ".$active[$i][PID] );
	}
	if( $active[$i][SS] > 500) {
	    exec("service httpd restart");
	}
    }
    sleep(10);
}
?>
commeta
() автор топика
Ответ на: комментарий от commeta

с предлагаемым списком можно делать все. например lsof -p по PID и грепать оттуда скрипт. можно добавить в order еще %cpu и сортировку по нему.

Komintern ★★★★★
()
Ответ на: комментарий от Komintern

с предлагаемым списком можно делать все. например lsof -p по PID и грепать оттуда скрипт. можно добавить в order еще %cpu и сортировку по нему.

а можно подробнее, это как, увидеть из списка процессов apache скрипт php который в данный момент выполняется?

commeta
() автор топика
Ответ на: комментарий от Komintern

Да понятно что с данными из server-status можно любую информацию по процессу узнать, хотел я без server-status обойтись костыль ведь... Надо исходники mod_status посмотреть, может смогу чего оттуда выдернуть.

commeta
() автор топика
Ответ на: комментарий от commeta

А я думаю кто мне отрубает скрипт обновления инет-магаза в кроне...

gobot ★★★★
()

Задача не тривиальная, сразу скажу. Там ведь инклюды всякие, о которых веб-сервер не знает и не обязан знать. По сути у большинства движков запускается только 1 скрипт из сайта - index.php, который разруливает уже через mod_rewrite все остальное. Тут нужен профайлинг ставить какой-то глобальный для всех сайтов. В эту сторону смотреть короче.

gobot ★★★★
()
Ответ на: комментарий от gobot

Не, мне не надо вплоть до файлов отлавливать, достаточно индексного скрипта, и профайлинг тут не нужен, мне не движки дебагить а за сервером следить чтобы они ресурсы не сжирали.

commeta
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.