Razvoj

PHP Performance Tuning: Go Beyond Profiling, Master Your Bottlenecks

Podešavanje performansi PHP-a: Nadiđite profiliranje, savladajte svoja uska grla

Većina problema s performansama PHP-a ne počinje sporim PHP-om. Počinju nepotpunom slikom o tome kamo odlazi vrijeme.

Lako je otvoriti profiler, pronaći skupu funkciju i optimizirati je. Ponekad to uspije. Češće je vidljiva funkcija jednostavno mjesto na kojem vaša aplikacija čeka: upit baze podataka, mrežni poziv, sukob pristupa datotečnom sustavu, zaključavanje sesije, zasićeni PHP-FPM skup ili neučinkovitu konfiguraciju implementacije.

Profiliranje je i dalje ključno, ali ono je tek početak. Dobar rad na performansama znači pratiti zahtjev kroz cijeli sustav, utvrditi ograničavajući resurs i napraviti promjenu koja poboljšava ishod za korisnika bez narušavanja robusnosti baze koda.

Započnite mjerljivim simptomom vidljivim korisniku

„Aplikacija djeluje sporo” nije dijagnoza. Definirajte relevantni zahtjev, očekivano opterećenje i metriku koja ne zadovoljava. Za API to mogu biti latencija repa i stopa pogrešaka. Za skupni zadatak to mogu biti vrijeme dovršetka i upotreba memorije. Za tijek naplate to može biti vrijeme od dolaska zahtjeva do upotrebljivog odgovora.

Mjerite više od prosjeka. Prosjeci mogu sakriti bolne zahtjeve koje korisnici pamte. Odvojite brze i spore putanje, a zatim usporedite njihove tragove, broj upita, veličine podataka i vanjske ovisnosti. Ako je jedna krajnja točka spora samo pri istodobnim zahtjevima, lokalni profil jednog zahtjeva može biti savršeno zdrav, dok produkcijski sustav nije.

Klasificirajte usko grlo prije optimizacije

Svaki zahtjev troši neku kombinaciju CPU-a, memorije, kapaciteta baze podataka, mrežnog vremena i kapaciteta zajedničkih radnika. Korisno pitanje nije „koji je PHP redak spor?”, nego „koji resurs trenutno ograničava ovaj zahtjev?”

  • CPU-om ograničen rad uključuje skupe transformacije, kompresiju, kriptografiju, obradu slika i neučinkovite petlje nad velikim zbirkama.
  • Rad ograničen bazom podataka uključuje nedostajuće indekse, previše povratnih putovanja, sukobe zaključavanja, loše oblike upita i dohvaćanje znatno više podataka nego što je potrebno.
  • Rad ograničen I/O-om uključuje HTTP pozive, redove, pohranu objekata, DNS razlučivanje, spore diskove i udaljene usluge.
  • Rad ograničen kapacitetom pojavljuje se kada su PHP-FPM radnici, veze s bazom podataka, CPU jezgre ili memorija iscrpljeni pod opterećenjem.

Ta razlika mijenja rješenje. Predmemoriranje izračuna koji intenzivno koristi CPU može pomoći. Predmemoriranje oko zaključavanja baze podataka može prikriti problem ispravnosti. Povećanje broja PHP radnika može poboljšati propusnost sve dok pritisak na memoriju ili sukob baze podataka ne pretvori poboljšanje u kaskadu kvarova.

Učinite rad baze podataka vidljivim

U tipičnim PHP aplikacijama koje renderiraju na poslužitelju i intenzivno koriste API, baza podataka zaslužuje ranu pozornost. Brojite upite po zahtjevu, bilježite spore upite i pregledajte planove upita za upite koji dominiraju vremenom ili opterećenjem. Upit koji je prihvatljiv jednom može postati ozbiljan trošak kada se izvršava stotinama puta u krajnjoj točki popisa.

Uklonite slučajno umnažanje upita

Klasičan primjer je učitavanje povezanih podataka unutar petlje. Kôd može izgledati uredno, ali jedan zahtjev pretvara u jedan upit za nadređene zapise plus jedan upit po nadređenom zapisu.

$orders = $repository->findRecentOrders();

foreach ($orders as $order) {
    $customer = $repository->findCustomer($order->customerId());
    // render customer data
}

Preferirajte strategiju upita ili učitavanja podataka koja dohvaća potrebni odnos u ograničenom broju operacija. Zatim provjerite nije li rezultat pretjerano širok. Dohvaćanje svakog stupca, svakog odnosa i svakog povijesnog zapisa može zamijeniti problem N+1 problemom s memorijom.

Indeksi bi trebali podržavati stvarne obrasce pristupa: filtriranje, spajanje, sortiranje i paginaciju. Nemojte ih dodavati naslijepo. Svaki indeks ima troškove pisanja i pohrane, a indeks koji ne odgovara predikatu i redoslijedu upita možda neće riješiti problem koji ste izmjerili.

Smanjite čekanje, ne samo izračunavanje

PHP radnik koji čeka udaljenu uslugu i dalje je zauzet. Uz dovoljno istodobnog prometa, to čekanje troši skup radnika i pretvara malo usporavanje ovisnosti u široku latenciju aplikacije.

Postavite eksplicitna vremenska ograničenja za odlazne pozive. Vremensko ograničenje nije neugodnost; ono je granica koja štiti ostatak aplikacije. Namjerno odaberite vremenska ograničenja povezivanja i ukupnog trajanja, predvidljivo obrađujte neuspjehe i izbjegavajte trenutačno ponavljanje svakog neuspjeha. Ponovni pokušaji mogu pojačati opterećenje već nezdrave ovisnosti.

Kada zahtjev ne treba rezultat vanjske usluge sinkrono, premjestite rad u red i vratite odgovor koji točno odražava novo stanje. To nije univerzalan odgovor: korisnici i dalje trebaju pouzdan status, idempotentne zadatke i obradu neuspjeha. No to je često bolja arhitektura od prisiljavanja web zahtjeva da koordinira dugi lanac udaljenih operacija.

Koristite predmemoriranje kao ugovor

Predmemorirajte rezultat skupog, ponovljivog rada kada možete objasniti tri stvari: što je predmemorirano, kada postaje zastarjelo i kako se poništava ili sigurno istječe. „Dodajte Redis” nije strategija predmemoriranja.

Dobri kandidati uključuju stabilnu konfiguraciju, renderirane fragmente, referentne podatke i odgovore s mnogo čitanja i jasnim vremenskim okvirom svježine. Budite oprezni s podacima specifičnima za korisnika, odgovorima osjetljivima na autorizaciju te promjenjivim zalihama ili cijenama. Brz netočan odgovor i dalje je netočan.

Također se zaštitite od stampeda predmemorije. Ako popularan ključ istekne i mnogi ga zahtjevi istodobno ponovno generiraju, predmemorija može prenijeti opterećenje izravno na bazu podataka ili nadređenu uslugu. Ovisno o sustavu, može biti prikladno kratko nasumično vrijeme isteka, objedinjavanje zahtjeva ili kontrolirani pristup stale-while-revalidate.

Razumijte kapacitet PHP izvođenja

Postavke PHP-FPM-a dio su produkcijske arhitekture, a ne generički predložak. Broj radnika mora odgovarati memoriji dostupnoj spremniku ili hostu, uz ostavljanje rezerve za operacijski sustav, web-poslužitelj, međuspremnike klijenta baze podataka i druge procese. Postavljanje vrlo visokog ograničenja radnika može stvoriti više istodobnosti nego što nizvodni sustavi mogu podnijeti.

Mjerite zasićenost radnika, čekanje u redu, rast memorije i trajanje zahtjeva pri realističnom opterećenju. Ako su radnici zauzeti zbog sporih upita baze podataka, dodavanje radnika rijetko rješava temeljni uzrok. Ako su neaktivni, ali se zahtjevi čekaju u redu na proxyju, pregledajte ograničenja veza i konfiguraciju implementacije. Ako memorija raste među zahtjevima, istražite zadržavanje na razini aplikacije, izgradnju velikih odgovora i ponašanje ekstenzija umjesto da pretpostavite kako će skupljanje smeća to riješiti.

U spremnicima eksplicitno postavite ograničenja resursa i testirajte s ograničenjima sličnima produkcijskima. Proces koji radi na prijenosnom računalu razvojnog programera može naglo otkazati kada spremnik dosegne gornju granicu memorije.

Održavajte optimiziranu putanju održivom

Promjene performansi često povećavaju složenost: skupno učitavanje, predmemorije, asinkroni tijekovi rada i pristup podacima na nižoj razini uvode nove načine neuspjeha. Učinite te kompromise vidljivima u kôdu i operacijama. Dosljedno imenujte ključeve predmemorije, centralizirajte pravila vremenskih ograničenja, bilježite neuspjehe ovisnosti s korisnim kontekstom i dodajte testove za poništavanje predmemorije i ponašanje ponovnih pokušaja.

Referentno mjerite promjene prema reprezentativnom opterećenju, a ne prema jednom sretnom zahtjevu. Potvrdite poboljšanje metrike koja je motivirala rad, zatim pratite regresije u memoriji, opterećenju baze podataka i obradi pogrešaka. Kraće vrijeme odgovora koje udvostručuje upise u bazu podataka nije automatski dobitak.

Performanse su svojstvo sustava

Najjače PHP aplikacije nisu one s najdomišljatijim mikrooptimizacijama. To su one koje čine rad vidljivim, izbjegavaju nepotreban rad, ograničavaju čekanje koje ne mogu izbjeći i graciozno otkazuju kada se ovisnosti muče.

Koristite profiliranje za pronalaženje dokaza, ali nastavite pratiti te dokaze i izvan PHP pozivnog stoga. Najvrjednije usko grlo rijetko je ono koje donosi najdramatičniju promjenu kôda. To je ono koje poboljšava cijelu putanju od dolaznog zahtjeva do pouzdanog odgovora.

Portret autora bloga

Mihajlo

Ja sam Mihajlo — programer vođen znatiželjom, disciplinom i stalnom željom da stvorim nešto smisleno. Dijelim uvide, tutorijale i besplatne usluge kako bih pomogao drugima da pojednostave svoj rad i rastu u svijetu softvera i umjetne inteligencije koji se neprestano razvija.