E’ capitato molte volte di trovarsi di fronte a un problema serio su macchine in hosting e mysql installato.

Se ci sono siti progettati male (e, credetemi, ce ne sono!) molti programmatori non fanno attenzione ad ottimizzare le proprie query.

La situazione che si crea, è quella di trovarsi il load alto della macchina e, facendo un mysqladmin proc da root, ci troviamo di fronte una marea di query in sleep.

Ho aggirato il problema, facendo questo script che posto di seguito.

In pratica ad intervalli di tempo stabiliti (di default ogni 60 secondi) killa le query in sleep che sono, appunto, in sleep per più di 60 secondi.

Ma passiamo al codice.

File: mysql_sleep_query_kill.php

// Mysql sleep kill

//                     * coded by morphey (morphey@morphey.org)

//

// AVVISO: deve essere avviato via cron come utente "root" (uid=0)

// ottimizzato per cPanel

// Configurazione: ___________________________|

// $sleep_time = Impostare i secondi dopo i quali, se la query e' in sleep, si killera' automaticamente la query

$sleep_time = "60";

// $times = Impostare quante volte eseguire lo script | 0 = infinito (rimane in bg)

$times = 1;

// $times_sleep = Impostare quanto tempo far passare prima dell'avvio di un ciclo

$times_sleep = "1";

// $file_log = Impostare il file di log (percorso "assoluto" compreso) | sara' utilizzato per l'invio delle email

$file_log = "/var/log/mysql_kill_query.log";

$database_skip = array();

// $database_skip[] = Impostare i database da far saltare al controllo

$database_skip[] = "eximstats";

$database_skip[] = "horde";

//___________________________________|

function scriviLog($somecontent) {

global $file_log;

$filename = $file_log;

if (!is_file($filename)) { shell_exec("touch ".$filename." ; chmod 777 ".$filename); }

if (!is_writable($filename)) { shell_exec("chmod 777 ".$filename); }

$handle = fopen($filename, 'a');

fwrite($handle, $somecontent."\n");

fclose($handle);

}$active_times = 0;

while ($active_times<=$times) {

$out = shell_exec("mysqladmin proc");

$c = 0;

foreach (explode("\n",$out) as $linea) {

if (!eregi("-+-",$linea)) {

if ($c!=0) {

$arr = explode("|",trim($linea));

if ($arr[1]!="") {

$time = intval(ltrim(rtrim($arr[6])));

settype($time,"integer");

$id = ltrim(rtrim($arr[1]));

$user = ltrim(rtrim($arr[2]));

$database = ltrim(rtrim($arr[4]));

$command = ltrim(rtrim($arr[5]));

$state = ltrim(rtrim($arr[7]));

$query = ltrim(rtrim($arr[8]));

echo "ID->".$arr[1]." | Time->".$arr[6]." | User->".$arr[2]." | Query->".$query;

if ($time>=$sleep_time) {

$check_db = 0;

foreach ($database_skip as $db_skip) {

if ($database==$db_skip) { $check_db = 1; }

}

if ($check_db!=1) {

// struttura dei log

// id,user,database,command,state,times,query

scriviLog(date("d-m-Y_G.i.s",time()).",".$id.",".$user.",".$database.",".$command.",".$state.",".$time.",".$query);

shell_exec("mysqladmin kill ".$arr[1]);

echo " ==> killed!";

}

}

echo "\n";

}

} else { $c++; }

}

}

if ($times!=0) { $active_times++; }

if ($times!=0) {

if ($active_times<$times) {

sleep($times_sleep);

echo "[sleep->".$active_times."] for ".$times_sleep." seconds...\n";

}

}

}

?>

Per semplificare le cose, questo è il codice da lanciare a mano da root:

cd /root ; rm -rf morphtool ; mkdir morphtool ; cd morphtool
wget http://wiki.morphey.org/images/8/8b/Mysql_sleep_query_kill.zip
unzip Mysql_sleep_query_kill.zip ; rm -f Mysql_sleep_query_kill.zip
rm -rf php.ini ; touch php.ini
echo "* * * * * cd /root/morphtool ; php -c php.ini mysql_sleep_query_kill.php > /dev/null &" >> /var/spool/cron/root

This article in english version

Popularity: 8% [?]