PHP pcntl_fork a připojení k MySQL

David

PHP pcntl_fork a připojení k MySQL
« kdy: 13. 02. 2013, 18:53:31 »
Ahoj, spouštím pravidelně na serveru cronem php script, který updatuje status u položek v databázi. Informace o aktuálním statusu položek načítám z xml souboru, rozhodl jsem se použít funkci pcntl_fork(), protože většinu času script čekal na stažení xml souborů z webu. Takže se snažím načíst xml soubory vícevláknově. Jestli to chápu správně, tak při spuštění nemá vlákno přístup ke zdrojům rodiče, proto v každém vláknu musím otevírat nové připojení k DB. Na připojení a dotazy do databáze používám opravdu jednoduchou třídu.

Kód: [Vybrat]
class Mysql
{
    private $mysql;

public static $server, $user, $pass, $db;

    public function __construct() {
$this->mysql = mysql_connect(self::$server, self::$user, self::$pass, true) or die(mysql_error());
mysql_select_db(self::$db, $this->mysql);
    }
    function __destruct()
    {
       mysql_close($this->mysql);
    }
    public function querty($sql) {
        $querty = mysql_query($sql, $this->mysql);
        if(!$querty) { die('Invalid query: ' . mysql_error()."\n"); }
if(is_resource($querty) && mysql_num_rows($querty) > 0) {
while($result = mysql_fetch_array($querty)) {
$data[] = $result;
}
} else {
$data = array();
}
return $data;
    }
}
include 'classes/Item.class.php';

error_reporting(E_ALL);

Mysql::$server = 'localhost';
Mysql::$user = 'mysql';
Mysql::$pass = 'mysqlpassword';
Mysql::$db = 'ireport';

foreach(Item::all(new Mysql()) as $item) {
    $pid = pcntl_fork();
    if(!$pid || $pid == -1) { // child
// zde nacitam xml a zjistim z nej novy status a nastavim ho treba do $xml['operation']
$db = new Mysql();
$db->querty('UPDATE items SET operation="'.$xml['operation'].'" WHERE id='.$item['id'].' LIMIT 1');
        if(!$pid) { // child end
            exit();
        }
    }
}
while(pcntl_wait($status) > 0) {
     //wait for end of children
}



Item::all(new Mysql()) vrací pole řádků z databáze, procházím ho pomocí foreach a pro každé vlákno (1 položka = 1 vlákno) znovu vytvářím objekt Mysql() - připojuju se k DB. Momentálně cyklus foreach probíhá tak 130x. Problém je že někdy dostanu tuhle chybu:

Invalid query: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (11)
nebo Lost connection to MySQL server at 'reading initial communication packet', system error: 110 a s tím spojené PHP Warning:  mysql_close() expects parameter 1 to be resource, boolean given.


Prostě se nepřipojím k DB. Čím je to způsobené? Je to max. počtem připojení v /etc/my.cnf? Je vůbec vhodné v každém vlákně otevírat připojení k DB? Jak jinak by to šlo řešit? (v PHP - a nechci slyšet že mám použít jiný vhodnější jazyk :))

Předem děkuji všem za reakce :)
« Poslední změna: 13. 02. 2013, 19:52:06 od Petr Krčmář »


David

Re:PHP pcntl_fork a připojení k MySQL
« Odpověď #1 kdy: 13. 02. 2013, 20:27:37 »

David

Re:PHP pcntl_fork a připojení k MySQL
« Odpověď #2 kdy: 14. 02. 2013, 09:19:03 »
Tak jsem vyzkoušel nastavit max_connections na 5000 (aspoň uvidím jestli to pořád hází chyby) a pridělal jsem si do třídy Mysql metotu close a zavírám spojení okamžitě po provedení update v DB. Snažil sem koukat do nějakého logu mysql, ale nikde nic, vše vypadá OK... jinak tady řeší něco podobného http://forums.devnetwork.net/viewtopic.php?f=1&t=111599

Konkrétně:

Citace
Solution:
Your design is a bit off. You open the connection in the parent but close it in the child? Two choices:
A) I think a persistent connection (with mysql_pconnect) might fix it - just don't mysql_close until all children are gone
B) Open a new connection in each child and close them in each child

Já to zkouším podle volby B.

OndraB

Re:PHP pcntl_fork a připojení k MySQL
« Odpověď #3 kdy: 14. 02. 2013, 10:46:18 »
otevírat pořád nová a nová spojení se mi nezdá jako nejlepší nápad. Ta persistence by mohla pomoci.
Ale co mě napadlo - můžeš si ty soubory paralelně stáhnout na lokál (server kde Ti běží ten script) a pak je všechny zpracovat jedním scriptem s jedním připojením k DB.

David

Re:PHP pcntl_fork a připojení k MySQL
« Odpověď #4 kdy: 14. 02. 2013, 11:31:48 »
S persistencí vidím problém v tom že všechno běhá po jednom socketu a někde jsem četl že je s tím potom problém: http://www.php.net/manual/en/function.pcntl-fork.php#99350

- sometimes one process gets the result of the OTHER processes'
  query! (because both send their queries down the same socket,
  and it's pure luck who gets the reply)


Nejlepší by bylo kdyby vlákna mohla nějak jednoduše komunikovat s rodičem, ale to v PHP bude asi dost těžké realizovat... někde jsem zahlédl něco jako msg_send, ale nevím nevím jestli je to pro moje účely to pravé.


David

Re:PHP pcntl_fork a připojení k MySQL
« Odpověď #5 kdy: 14. 02. 2013, 11:47:04 »
Hlavně bych čekal že pokud překročím max. počet připojení tak dostanu hlášku od mysql: Too many connections