Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web development, networking and server security. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

Poboljšanje Disk-a I / O u PHP Apps-u




Postavio Rodnez Rehm u utorak, 17og aprila. 2012

Za puštanje Smarty 3.1.0 refaktorisao sam većinu pristupa Smarty disku. Pošto je ovo optimizacija od septembra 2011 dovela do postavljanja pitanja o Smarty-ju po forumima, konačno sam osetio potrebu da objasnim šta sam uradio. Iako je Smarty razlog što sam otkrio ovo, ovaj post se odnosi na PHP generalno,a ne na Smarty posebno. Ovaj post je sve o postavljanju temelja I za vas da shvatite dve stvari:
  1. Vaše operacije nisu atomske
  2. Izbegavajte pristup hard disk bespotrebno
Višestruki procesi i Uslovi Trke

Verovatno se sećate da vaš računar prelazi različite procese (pokretanje aplikacije, ...) u i van CPU-a. To se radi tako da paralelno izvršavanje procesa može biti postignuto na jednom CPU jezgru . To je ono što mi zovemo Multi Tasking(višestruki zadaci) - i isti principi primenjuju se na računarima sa više od jednim CPU jezgrom .

To znači da vaš program (PHP skripta) nije izvršen redom. Neki od programa se izvršavaju ,onda ide pauza , tako da nešto drugo može da se pokrene, onda se nastavlja izvršenje, onda je opet pauza i tako dalje.

U nekim jezicima možemo reći domaćinu izvršenja za tretiranje gomile operacija kao jedne - mi to zovemo valentnost . PHP ne poznaje ovaj koncept. Ono što je sigurno je to da vaša PHP skripta može biti prekinuta u bilo kom trenutku u bilo kojoj operaciji.

Osim ako ste imali priliku da radite na prilično visoko-frekvetnim sajtovima,verovatno nikada niste videli uslove trke u akciji. Uslovi trke su ono što mi zovemo slučajem kada dva (paralelna izvršavanja) procesa rade kontradiktorne stvari. Na primer, Proces 1 piše fajl / tmp /file.txt,dok Proces 2 pokušava da obriše taj isti fajl.

Ovi procesi ne moraju da rade u istom kontekstu. Dok Proces 1 može biti PHP skripta, Proces 2 može biti shell (školjka) skripta koja se aktivira Cron-om ,ili neki priručnik rm / tmp / file.txt preko SSH-a.

Zaključavanje Fajla

Da biste sprečili ove uslove trke, mi dozvoljeno da se zaključavaju fajlovi . Kada je datoteka zaključana od strane procesa 1 i proces 2 pokušava da otključa , Proces 2 blokira izvršenje sve dok brava nije otključana od strane procesa 1.PHP obezbeđuje ovu funkcionalnost sa flock()-om.

flock() ima nekoliko problema,doduše, Prvo on radi samo sa resursima,tako da morate da imate otvoren fajl sa fopen () pre otključavanja. Takođe, flock () će pasti na određenim sistemima datoteka kao što su FAT ili NFS. Povrh toga izgleda sasvim besmisleno da otvorite datoteku, samo da otključate bravu i samo da izbrišete datoteku.

Dakle, u stvarnom životu, gde PHP skripta ne zna koji fajl sistem se koristi,flock () neće biti od pomoći.

Potencijalni uslovi trke

Na prvi pogled, sledeći kod se smatra dobrim kodom , ako smo proverili da li postoji datoteka pre nego što ga odvojimo . To je zato što unlink () izdaje E_WARNING (upozorenje) kad ne može da pronađe datoteku za odvajanje:

$filepath = "/tmp/some.file";
if (file_exists($filepath)) {
  unlink($filepath);
}

Ali setimo se da PHP nema atomskog operatera i skripta može biti prekinuta u bilo kom datom trenutku:

$filepath = "/tmp/some.file";
if (file_exists($filepath)) {
  // <- potential race condition
  unlink($filepath);
}

Imajući u vidu kod iznad da bude Proces 1 ,mogli smo naići na sledeći uslov:

*Process 1*: file_exists("/tmp/some.file") *Process 2*: unlink("/tmp/some.file") *Process 1*: unlink("/tmp/some.file") -> E_WARNING, file not found!

Između provere da li je fajl postojao i stvarnog uklanjanja , drugi proces je imao priliku da izbriše datoteku. Sada unlink () naše skripte izdaje E_WARNING jer unlink () nije uspeo.

Olakšavajući uslovi trke

Bez straha, PHP zna svemogući @ tihi-operater. Prefiksirajući funkcijski poziv sa @ čini da PHP ignoriše bilo kakve greške koje izdaje taj obim funkcijskih poziva. Taj kod će sprečiti bilo koje E_WARNING upozorenje izdato zbog uslova trke (ili bilo koje druge greške, po tom pitanju):

$filepath = "/tmp/some.file";
if (file_exists($filepath)) {
  @unlink($filepath);
}

Tim malim @ smo otvorili vrata blagom pojednostavljenju našeg koda. Pošto obavljamo file_exists() da bismo se uverili da unlink() neće izdati nikakva upozorenja, i @unlink() neće izdati upozorenja, mi jednostavno možemo ubaciti file_exists():

$filepath = "/tmp/some.file";
@unlink($filepath);

I eto, uspešno smo ublažili uslove trke. I na taj način, mi smo slučajno smanjili disk I/O za 50%.

Smanjenje diska I/O (statistika)

Pored implikacija na uslove trke, odbacivanje file_exists() ima drugu korist u smanjenju stat poziva. Kad god treba da dodirnete HDD, zamislite da Vaša Ferrari-aplikacija stiska kočnice. U odnosu na CPU bilo koji hard disk (da, čak i SSD) je kornjača okovana za stenu. Dakle, krajnji cilj je da se izbegne dodirivanje sistema datoteka kad god je to moguće.

Razmotrite sledeći dobro kodiran program za identifikovanje da li datoteka postoji i kada je izmenjena poslednji put:

$filepath = "/tmp/some.file";
$file_exists = file_exists($filepath);
$file_mtime = null;
if ($file_exists) {
  $file_mtime = filemtime($filename);
}

Da li ste znali da filemtime() vraća pogrešno (i izdaje E_WARNING) ako ne može da pronađe datoteku? Pa šta mislite o obrtanju stvari i odbacivanju file_exists():

$filepath = "/tmp/some.file";
$file_mtime = @file_mtime($filepath);
$file_exists = !!$file_mtime;

Prilagođeno rukovanje greškama

Kao što je pomenuto na početku, odbacivanje file_exists() je urađeno na Smarty 3.1.0. Uradili smo brojne testove i repere i došli do zaključka da bi bilo glupo da to ne uradimo. I u tom trenutku sam mislio da niko nikada neće primetiti. To bi moglo da bude istina, da nije bilo set_error_handler() .

set_error_handler() omogućava Vam da registrujete svoj sopstveni prilagođeni metod za rukovanje greškama. To je prilično uredno da pomerite određene greške u bazu podataka ili pošaljite mail ili nešto slično tome. To vam daje apsolutnu moć nad svakom izdatom najavim ili upozorenjem . Čak i onim koji bi bili maskirani error_reporting () ili @ operator-om.

Očigledno neki ljudi registruju rukovaoce prilagođenih grešaka da dobiju SVE GREŠKE. Čak i one maskirane. Neki programeri nisu uspeli da shvate savete u dokumentima , drugi su uradili namerno. Da stavimo nameru na stranu , ovi loše osmišljeni rukovaoci greškama razbili su put kojim očekujemo PHP da radi . Odjednom sve greške poput grešaka u 'test.php "na liniji 2: unlink (/ tmp / some.file): Nema takve datoteke ili direktorijuma (2) počele su da iskaču.

U njihovim glavama Smarty se loše ponaša.Posle svega njihov kod podiže E_WARNING-e svuda. Oni nisu znali (i nije ih briga)za poboljšanja koje smo napravili. Oni nisu hteli da "poprave" svoje rukovaoce greškama, jer ih nisu videli slomljene. Dakle, u Smarty-ju 3.1.2 uveo sam Smarty :: muteExpectedErrors () - običajni rukovaoc greškama koji će posredovati sa njihovim rukovaocima ,filtrirajući greške koje Smarty zapravo očekuje da će se desiti .




Published (Last edited): 17-12-2012 , source: http://blog.rodneyrehm.de/archives/12-improving-disk-io-in-php-apps.html