/ Forside / Teknologi / Udvikling / PHP / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
PHP
#NavnPoint
rfh 3959
natmaden 3372
poul_from 3310
funbreak 2700
stone47 2230
Jin2k 1960
Angband 1743
Bjerner 1249
refi 1185
10  Interkril.. 1146
Problemer med simultan afvikling af PHP sc~
Fra : JD


Dato : 13-07-06 16:19

Jeg har et problem med, at mit PHP script tager den samme MySQL database
entry, selvom den ikke burde.
Jeg afvikler nedenstående PHP script i 5-10 samtidige scripts der køre via
et BASH shell script. Det giver en masse load på serveren og derfor tror
jeg, at MySQL serveren til tider kan have problemer med at returnere hurtigt
nok. Jeg har prøvet at forhindre, at PHP scriptet tager samme ID ved, at
sætte en masse random delay ind men det hjælper ikke nok.

Mit PHP script (kaldt fra en evig BASH løkke):

function make_seed()
{
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
srand(make_seed());

$delay = rand(2500000,10000000); // 2,5 - 10 seconds delay
echo "DELAY: $delay microseconds\n\r";
usleep($delay);
$delay = rand(500000,2000000); // 0,5 - 2 seconds delay
echo "DELAY: $delay microseconds\n\r";
usleep($delay);
// jeg kunne sikkert bare have 3 - 12 sekunders delay istedet.

$qres = mysql_query(" \
SELECT id_host,id_child,child,port,ddate,ldate,cby,uptime,id_ip,id_sw \
FROM child \
WHERE active=0 \
ORDER BY active DESC, pri_scan DESC, ldate ASC, cdate ASC \
LIMIT 1 \
") or die(mysql_error());

list($id_host,$id_child,$hostname,$port,$ddate,$ldate,$cby,$uptime_db,$id_ip_db,$id_sw_db)
= mysql_fetch_row($qres);
{
mysql_query("UPDATE child SET active=1 WHERE id_child=$id_child LIMIT 1")
or die(mysql_error());
.... script fortsætter ...

Som man kan se, så er det første jeg gør, efter at ID'en er valgt, at sætte
den som værende aktiv = den skal ikke tages af andre scripts. Databasen
indeholder ikke så mange rows - under 20.000.

Er der nogen gode idéer til hvordan man evt. generelt kan sikre sig, at DB
entry kun bliver valgt af ét script, selvom man har 5-10 scripts kørende
samtidigt!? Hastigheden for afviklingen af scriptet er ikke vigtig, da jeg
bare kan sætte flere simultane scripts til at køre.



 
 
Peter Brodersen (13-07-2006)
Kommentar
Fra : Peter Brodersen


Dato : 13-07-06 16:31

On Thu, 13 Jul 2006 17:18:44 +0200, "JD" <jonh@doe.xyz> wrote:

>Er der nogen gode idéer til hvordan man evt. generelt kan sikre sig, at DB
>entry kun bliver valgt af ét script, selvom man har 5-10 scripts kørende
>samtidigt!? Hastigheden for afviklingen af scriptet er ikke vigtig, da jeg
>bare kan sætte flere simultane scripts til at køre.

Du kan have en hovedproces, der hiver data ud, og så fork'er og lader
et child behandle dataen. Derefter kan hovedprocessen fortsætte med at
fork'e, og så løbende holde styr på hvor mange childs, der kører.

Kig på process control functions her:
http://dk.php.net/pcntl

Du kan eventuelt starte med første eksempel her:
http://www.php-mag.net/itr/online_artikel/psecom,id,484,nodeid,114.html

--
- Peter Brodersen
Ugens^WMånedens^WSommerens værktøj - Find vej: www.findvej.dk
Nu med link direkte til en adresse, fx: www.findvej.dk/Nybrogade2,1203

JD (13-07-2006)
Kommentar
Fra : JD


Dato : 13-07-06 19:33

>>Er der nogen gode idéer til hvordan man evt. generelt kan sikre sig, at DB
>>entry kun bliver valgt af ét script, selvom man har 5-10 scripts kørende
>>samtidigt!? Hastigheden for afviklingen af scriptet er ikke vigtig, da jeg
>>bare kan sætte flere simultane scripts til at køre.
>
> Du kan have en hovedproces, der hiver data ud, og så fork'er og lader
> et child behandle dataen. Derefter kan hovedprocessen fortsætte med at
> fork'e, og så løbende holde styr på hvor mange childs, der kører.
> Kig på process control functions her:
> http://dk.php.net/pcntl
> Du kan eventuelt starte med første eksempel her:
> http://www.php-mag.net/itr/online_artikel/psecom,id,484,nodeid,114.html

Du svare jo på alle mine spørgsmål?

Anyway, jeg forstår ikke helt denne. Jeg har læst siderne og så vidt som jeg
kan forstå på dem, så bliver éns PHP script daemonized men de spawner ikke
nye processer? Jeg kunne måske se det smarte i det, hvis man havde én master
daemonized PHP script som spawnede nye "childs" PHP scripts, hvor hvert
child script requestede efter en specifik database ID. Jeg mener noget a'la
dette:

Master PHP:

while(1==1)
{
sleep(1)
mysql_query("SELECT id_next FROM blaaa")
list($id_next) = blaa....
spawn_php_child($id_next)
}

På den måde er man sikker på at master PHP scriptet styre begivenhederne men
man kan samtidigt have flere simultane PHP scripts kørende.

Måske kan POSIX også dét, men så har jeg misforstået det?



JD (13-07-2006)
Kommentar
Fra : JD


Dato : 13-07-06 20:03

> Anyway, jeg forstår ikke helt denne. Jeg har læst siderne og så vidt som
> jeg kan forstå på dem, så bliver éns PHP script daemonized men de spawner
> ikke nye processer? Jeg kunne måske se det smarte i det, hvis man havde én
> master daemonized PHP script som spawnede nye "childs" PHP scripts, hvor
> hvert child script requestede efter en specifik database ID. Jeg mener
> noget a'la dette:
>
> Master PHP:
> while(1==1)
> {
> sleep(1)
> mysql_query("SELECT id_next FROM blaaa")
> list($id_next) = blaa....
> spawn_php_child($id_next)
> }

Jeg var lidt irriteret over, at jeg ikke kunne få det til at fungere, så
efter lidt mere læsning og lidt test, fandt jeg frem til denne PHP kode, som
virker glimrende:
(taget fra og klippet i fra
http://www.php-mag.net/itr/online_artikel/psecom,id,484,nodeid,114.html)

<?PHP
set_time_limit(0);
while(1==1)
{
$a = "1234"; // just to see if parent var is visible in spawned child
sleep(5);

/* Fork our process */
$pid = pcntl_fork();

if($pid == -1)
{
// Something went wrong
echo "An Error Occured trying to fork..<br></br> Exiting\n";
exit;
}

elseif($pid == 0)

{
/* We're in the child process, here is where <br></br> we can affect the
flow of our child process */
echo "[$a]";
sleep(30);
echo "Hi, I'm the child process! I will exit ... now\n";
exit();
}

else

{
/* We're in the parent process, we can now <br></br> carry on without
affecting the child in any <br></br> way whatsoever */
echo "Hi, I'm the parent process! I hope you.<br></br> enjoyed my child with
the PID $pid I.<br></br> will exit now!\n";
}

}
?>

Dette eksempel vil netop gøre lige det jeg har brug for. Nu skal det bare
indskrives i mit nuværende script.
Mange tak Peter



JD (13-07-2006)
Kommentar
Fra : JD


Dato : 13-07-06 23:17

[CUT]
> Dette eksempel vil netop gøre lige det jeg har brug for. Nu skal det bare
> indskrives i mit nuværende script.

Så fungere det men jeg har et par tillægsspørgsmål.

1)
Tidligere, hvor jeg manuelt startede X antal scripts op, kunne jeg selv
vælge hvilken logfil det skulle appendes til. Hvordan gør jeg det nu, hvor
der kommer et ukendt antal PID's? F.eks. vil jeg gerne kunne appende til
logs i en fortløbende rækkefølge:

log_1.log
log_2.log
m.v.

Som det er lige nu, appendes alle linier ind i én stor pærevælling og det er
ubrugeligt til at finde tilbage til en given scanning. Jeg havde tænkt på en
måde, hvor man kunne definere en logfil fra master og videregive den til
child, men jeg ved ikke hvordan jeg frigiver den fra child således at master
kan se det? Lidt mere pseudo kode:

Master:

if(logfile1 is NOT opened)
set logfile = /var/log/file_1.log
elseif(logfile2 is NOT opened)
set logfile = /var/log/file_2.log
else
set logfile = /var/log/catch_the_rest.log
Child:
logfile = logfile from master
code... blaa....
logfile = finished (ready for another usage)
exit()

Jeg har prøvet med global logfile; i child, men det virker ikke. Hvilke
andre idéer kan I komme på?

2)
Hvordan styre man antallet af PID's der må startes op? Lige p.t. tæller jeg
antallet af PID's vha.:
$cmd = intval(trim(shell_exec("/bin/ps -ax | /usr/bin/grep my_script |
/usr/bin/grep -v grep | /usr/bin/wc -l")));
Jeg styre det så vha:

$APROX_PIDS = 3; // aproximately have this number of simult. PID's active

// Get number of active PID's
$cmd = intval(trim(shell_exec("/bin/ps -ax | /usr/bin/grep my_script |
/usr/bin/grep -v grep | /usr/bin/wc -l")));
echo "Number of PID's................: $cmd\n\r";

// Delay
if($cmd <= $APROX_PIDS)
$millisecs = 1.0;
else
$millisecs = 20.0;
$microsecs = $millisecs * 1000000;
usleep($microsecs);

Det er vel nok ikke det smarteste, men hvordan ellers? Det skal jo ikke bare
gå amok og scanne konstant men kun et vist cirka antal per time/dag.

3)
Hvordan slår jeg PID'erne ihjel på en pæn måde således, at child-script
delen bliver kørt færdigt? Normaldrift af scriptet er, at det bliver startet
op fra crontab ved reboot. Det er lidt grimt bare at tage en "kill pidnr.",
da det efterlader en masse rod.



Bertel Lund Hansen (14-07-2006)
Kommentar
Fra : Bertel Lund Hansen


Dato : 14-07-06 08:32

JD skrev:

> Tidligere, hvor jeg manuelt startede X antal scripts op, kunne jeg selv
> vælge hvilken logfil det skulle appendes til. Hvordan gør jeg det nu, hvor
> der kommer et ukendt antal PID's? F.eks. vil jeg gerne kunne appende til
> logs i en fortløbende rækkefølge:

Kan du ikke starte en global variabel, $lognr, som tælles 1 op i
hver childproces? Så skal du bare bruge

   $loghandle=fopen('log_'.$lognr,'a');

--
Bertel
http://bertel.lundhansen.dk/      http://fiduso.dk/

JD (14-07-2006)
Kommentar
Fra : JD


Dato : 14-07-06 09:10

>> Tidligere, hvor jeg manuelt startede X antal scripts op, kunne jeg selv
>> vælge hvilken logfil det skulle appendes til. Hvordan gør jeg det nu,
>> hvor
>> der kommer et ukendt antal PID's? F.eks. vil jeg gerne kunne appende til
>> logs i en fortløbende rækkefølge:
>
> Kan du ikke starte en global variabel, $lognr, som tælles 1 op i
> hver childproces? Så skal du bare bruge
> $loghandle=fopen('log_'.$lognr,'a');

Det er ikke noget problem, at få variabler fra master processen og ned til
child men jeg kan ikke få variabel værdier fra child og til master
processen? Jeg kan ikke se, fra master processen, hvornår mine childs
exit'er og derfor kan jeg ikke finde ud af, hvornår en given logfil er
blevet ledig til en ny child.



Michael Rasmussen (14-07-2006)
Kommentar
Fra : Michael Rasmussen


Dato : 14-07-06 10:34

On Fri, 14 Jul 2006 10:09:41 +0200, JD wrote:

>
> Det er ikke noget problem, at få variabler fra master processen og ned
> til child men jeg kan ikke få variabel værdier fra child og til master
> processen? Jeg kan ikke se, fra master processen, hvornår mine childs
> exit'er og derfor kan jeg ikke finde ud af, hvornår en given logfil er
> blevet ledig til en ny child.
Har du undersøgt anvendelse af pcntl til bunds?
http://www.php.net/manual/en/function.pcntl-waitpid.php

Har du overvejet shared memory?
http://www.php.net/manual/en/ref.shmop.php

--
Hilsen/Regards
Michael Rasmussen
http://keyserver.veridis.com:11371/pks/lookup?op=get&search=0xE3E80917


JD (14-07-2006)
Kommentar
Fra : JD


Dato : 14-07-06 13:55

>> Det er ikke noget problem, at få variabler fra master processen og ned
>> til child men jeg kan ikke få variabel værdier fra child og til master
>> processen? Jeg kan ikke se, fra master processen, hvornår mine childs
>> exit'er og derfor kan jeg ikke finde ud af, hvornår en given logfil er
>> blevet ledig til en ny child.
>
> Har du undersøgt anvendelse af pcntl til bunds?
> http://www.php.net/manual/en/function.pcntl-waitpid.php

Naah, det vil jeg ikke sige, at jeg har for der er så meget nyt i det for
mig, at det er bedre (for mig) at blive dirigeret i den rigtige retning. Jeg
har fået det til at fungere og det løser jo flere af mine problemer, så
mange tak for linket Det er efterhånden ved at blive tilpas komplekst.



Søg
Reklame
Statistik
Spørgsmål : 177559
Tips : 31968
Nyheder : 719565
Indlæg : 6408938
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste