PDA

Pogčedajte punu verziju : gremlini na serveru


ivanhoe
05. 05. 2006., 04:25
Odrzavam jedan server koji je postao prilicno popularan u poslednje vreme i zbog toga na momente vrlo (pre)opterecen, i verovatno zbog toga, krenule su da mi se desavaju neke jako cudne stvari.

$sql = "SELECT * FROM members WHERE (email='$email' OR username='$email')";
$db->query($sql);
if($db->next_record()) {
$processed = $db->f("processed");
$member_id = $db->f("id");
}

if ($processed=='y') {
$error = USER_EXISTS;
} else {

if($member_id) {// just update existing record
$sql = "UPDATE members SET first_name='$first_name', last_name='$last_name', pword='$password', source=".HUB_SOURCE_ID." WHERE id='$member_id'";
$db->query ($sql);
$last_id = $member_id;

}else {// insert a new one
$sql = "INSERT INTO members (email, first_name, last_name, pword, active, processed, source, first_contact) VALUES ('$email', '$first_name', '$last_name', '$password', 'n', 'n', ".HUB_SOURCE_ID.", NOW())";
$db->query ($sql);
$sql = "SELECT * FROM members WHERE email='$email' AND pword='$password'";
$db->query ($sql);
$db->next_record();
$last_id = $db->f('id');
}
Ovaj komad koda koji sluzi da kreira usera i onda se dalje korisnik salje na paypal. Bitna stvar ovde je $last_id, tj. id pod kojim je user upisan u bazu, jer se to koristi da se kad uplata prodje aktivira taj nalog. I ovo je sve normalno radilo godinama, ali kad se mysql server (i ceo server) nadje pod opterecenjem, pocelo je da se desava da se paypalu prosledi pogresna vrednost za $last_id...

Proveravao sam u bazi i postoji samo jedan user record sa tim emailom, ali poslednji upit na neku foru vrati pogresan ID ??? Jel ima neko ideju kako je to moguce da se desi???

Ovaj $db objekat je iz phplib, i da je bilo neke mysql greske desio bi se die() odmah, tako je namesteno. Znaci nije bilo greske, ali je vracen pogresan podatak (npr. 487522 umesto 487556, pri cemu record sa ID=487522 ima skroz drugaciji email i pass znaci nikako nije smeo da se nadje u rezultatu)

Da li postoji neki nacin da se zastitim od ovakvih stvari? Uradicu uskoro load-balancing, cim klijenta ubedim da da kintu za dodatni server, ali ipak bih voleo i da ovo predupredim za ubuduce, ako je moguce..

Gruja
05. 05. 2006., 09:44
Verovatno ovo nema veze sa mozgom posto nemam pojma sa php-om:

Kakva vrsta promenljive je taj $db? Ako je to neka deljena globalna promenljiva koju dele sve strane onda moze da ti se desi da je jedna stranica poslala upit, a druga da cita rezultate.

ivanhoe
05. 05. 2006., 17:03
ne, nema toga kod php-a..
$db je lokalni objekat koji kreira phplib, pre ovoga nema drugih upita u skripti, i ne koriste se perzistentne konekcije, tako da nikako ne bi smelo da dodje do "mesanja" podataka, AFAIK...

misk0
27. 07. 2006., 20:12
I sta si uradio sa ovim Ivane?

ivanhoe
27. 07. 2006., 20:48
nesto se bilo zeznulo interno u apache-u, pojavljivale su se jos neke chudne stvari u log fajlovima....rebildovao sam apache i php, i onda je sve magicno proradilo... kazem vam ja gremlini..:D

zextra
28. 07. 2006., 03:50
kontam da si to vec izmenio, ali ako nisi, zameni tu proceduru za trazenje poslednjeg id-a funkcijom mysql_insert_id().

ivanhoe
29. 07. 2006., 02:22
da u pravu si, nisam ni primetio.... nije ovo moj kod, pisan je jos za php3, verovatno zato ni nema te mysql fore...

Dušan Dželebdžić
29. 07. 2006., 10:52
U MySQL-u (3.23 pa na dalje) postoji jako korisna funkcija LAST_INSERT_ID() (http://dev.mysql.com/doc/refman/4.1/en/getting-unique-id.html), nezavisna od implementacije mysqla u nekom programskom jeziku.

godza
29. 07. 2006., 13:19
jel moguce da imas dve niti procesa koji pokusavaju da insertuju 2 korisnika paralelno?

MorenoArdohain
29. 07. 2006., 14:20
Godza, bas bih voleo da znam kako je to izvodljivo u PHP? :)

Inace, mysql_insert_id() bi trebalo da radi bez problema ako se ne koriste persistant konekcije..

dinke
29. 07. 2006., 16:21
Godza, bas bih voleo da znam kako je to izvodljivo u PHP? :)
man pcntl (http://www.php.net/pcntl) :)

MorenoArdohain
29. 07. 2006., 18:05
Dinke: da li svaki proces nasledjuje sve iz parent procesa? Konkretno ciljam na mysql konekciju. Ja mislim da ne, zbog toga nije ni moguce paralelno insertovanje u okviru jedne konekcije.

Neka me neko ispravi ako gresim., ipak je moje znanje o procesima iz Perla :)

ivanhoe
29. 07. 2006., 19:04
kad se forkuje u perlu nasledjuju se i FD, tako da bi trebalo i konekcije da se naslede... ali mislim da su takve stvari opasne da se rade, cisto sumnjam da je mysql konekcija thread-safe, ko zna sta bi se desilo kad bi krenuo paraleno da pises iz vise procesa u istu konekciju...

Uzgred mislim da je Godza mislio na situaciju kad dva korisnika istovremeno pokrenu dve skripte (odvojene procese) koji su konkurentni, a ne da jedna skripta kreira 2 procesa... a to nije problem, eventualno treba odradti lockovanje ako se proveravaju neki uslovi pre akcije (tipa da li postoji neki record, mora prvo da se lokuje, proveri, pa doda novi record, inace bi moglo da se desi da se paralelno urade 2 provere, obe ne nadju nista i onda obe dodaju record... imao sam taj problem sa PayPalom posto on posalje ponekad u periodu od par sekundi po 5-6 IPN notifikacija za istu transakciju... imao sam stalno dupikate u bazi zbog toga, dok nisam shvatio sta se desava...)

MorenoArdohain
29. 07. 2006., 19:34
Nope, mysql konekcije se ne nasledjuju u perlu

godza
29. 07. 2006., 19:50
kad se forkuje u perlu nasledjuju se i FD, tako da bi trebalo i konekcije da se naslede... ali mislim da su takve stvari opasne da se rade, cisto sumnjam da je mysql konekcija thread-safe, ko zna sta bi se desilo kad bi krenuo paraleno da pises iz vise procesa u istu konekciju...

Uzgred mislim da je Godza mislio na situaciju kad dva korisnika istovremeno pokrenu dve skripte (odvojene procese) koji su konkurentni, a ne da jedna skripta kreira 2 procesa... a to nije problem, eventualno treba odradti lockovanje ako se proveravaju neki uslovi pre akcije (tipa da li postoji neki record, mora prvo da se lokuje, proveri, pa doda novi record, inace bi moglo da se desi da se paralelno urade 2 provere, obe ne nadju nista i onda obe dodaju record... imao sam taj problem sa PayPalom posto on posalje ponekad u periodu od par sekundi po 5-6 IPN notifikacija za istu transakciju... imao sam stalno dupikate u bazi zbog toga, dok nisam shvatio sta se desava...)

Da mislio sam na 2 apache thread-a (srpski receno 2 lika insertuju korisnika u isto vreme)