WN

WN (https://www.wn.se/forum/index.php)
-   Serversidans teknologier (https://www.wn.se/forum/forumdisplay.php?f=4)
-   -   Performance (https://www.wn.se/forum/showthread.php?t=4265)

netflax 2004-11-02 10:30

Hej,

Jag funderar lite över performance vid hantering av bilder. Jag har två metoder att välja på:

1. Alla bilder går via image.php
image.php öppnar filen och läser filen från en katalog på disk och spottar därefter ut bilden till webbläsaren.

2. Bilder länkas som vanligt
Alltså en <img>-tagg pekar direkt på bildens position.

Min fråga är; är alternativ 1 mycket långsammare än alternativ 2? Jag trodde först att så var fallet, men sedan började jag tänka i banor som att "Någon måste ju ändå läsa filen från disk, om det är ett PHP-script (image.php) eller Apache som gör detta borde väl inte spela någon stor roll?"

Vad tror ni?

Anledningen till att jag helst vill gå via image.php är för att jag vill kunna styra vilka som skall få tillgång till bilderna genom att kontrollera deras SESSION.

Tacksam för svar från performance-gurus!

Robert 2004-11-02 11:18

En webläsare kan göra flera simultana anrop mot exempelvis en img. Hur php filer exekveras vet jag inte, men då en webläsare förväntar ett svar ifrån ett php skript så vet jag inte om de läggs på "kö" eller dylikt. Du har ju en php som i sitt htmlsvar anropar en php. En php i sig bör ju ta något längre tid att exekvera även fast den är mycket simpel. Frågan är om det är så pass mycket tid så du behöver bry dig om det.

Någon?

netflax 2004-11-02 11:25

Jag har bilder och vanliga dokument också. Låt säga att någon laddat upp en TIFF-bild på 10MB.. om PHP-scriptet skall läsa in filen och spotta ut den till webbläsaren kommer detta att ta lite tid. Men filen måste ju ändå spottas ut till läsaren av något... PHP eller via direkt länk och då av Apache?

Vad tror ni?

nomicon 2004-11-02 16:32

Citat:

Originally posted by netflax@Nov 2 2004, 12:25
Jag har bilder och vanliga dokument också. Låt säga att någon laddat upp en TIFF-bild på 10MB.. om PHP-scriptet skall läsa in filen och spotta ut den till webbläsaren kommer detta att ta lite tid. Men filen måste ju ändå spottas ut till läsaren av något... PHP eller via direkt länk och då av Apache?

Vad tror ni?

Enklast är väl att helt enkelt kolla.

I början av php-dokumentet så spottar du ut klockslaget/sekunder, och samma sak nederst i dokumentet, så ser du juh
hur snabbt sidan laddas?

netflax 2004-11-02 16:36

Citat:


Enklast är väl att helt enkelt kolla.

I början av php-dokumentet så spottar du ut klockslaget/sekunder, och samma sak nederst i dokumentet, så ser du juh
hur snabbt sidan laddas?

OK, en sida går självklart mkt fortare att exekvera eftersom det inte är PHP-sidan som tar hand om bilden utan IMG-taggen... men frågan är om servern får jobba mkt hårdare eller inte. Servern måste ju jobba i båda fallen... men det är svårt att mäta vilket som är snabbare.

Robert 2004-11-02 17:23

Citat:

Originally posted by netflax@Nov 2 2004, 17:36
Citat:


Enklast är väl att helt enkelt kolla.

I början av php-dokumentet så spottar du ut klockslaget/sekunder, och samma sak nederst i dokumentet, så ser du juh
hur snabbt sidan laddas?

OK, en sida går självklart mkt fortare att exekvera eftersom det inte är PHP-sidan som tar hand om bilden utan IMG-taggen... men frågan är om servern får jobba mkt hårdare eller inte. Servern måste ju jobba i båda fallen... men det är svårt att mäta vilket som är snabbare.

Logiskt sett så borde den få jobba mer, men frågan är hur mycket?

Du kanske hittar svaret redan i apache servern (som jag vet 0 om). Finns det "trådar" den kör anrop i eller ställs allt på kö, eller är det bara anrop till php som går i en kö och bilder/html whatever i egen etc etc.

Anders 2004-11-02 18:06

Gör som nomicon sa, testa. Det blir ju en viss overhead jämfört med en img-tag i HTML, men det verkar ju funka för Lunar...

heyday 2004-11-02 22:36

Min syn på saken:
Har du alternativet att generera en korrekt bildurl i htmlen, gör det.

Att köra script som läser och skickar filen är overkill i de fall bilden är en statisk bild. (genererar du en bild är det en annan sak.)

http 1.1 tillåter att man (webläsaren) kan återanvända en koppling mot servern för flera requests, vilket ger ett "kösystem" i sig. Men ie tillåter i sin tur (som standard) 4 kopplingar mot servern samtidigt, vilket gör att du har 4 köer som hämtar html/bilder/css/javascript/whatever. Har du stora bilder så är det en sak. Men har du många små bilder så blir det en anhopning förfrågningar på scriptet och då kommer scriptet vara avsevärt långsamare är httpd. Jag har inga siffror, men vi gjorde en dylik lösning för ett antal år sedan, och det är skillnad. (för besökaren that is). Det var iofs en äldre cgi installation av php.

httpd har långt mer erfarenhet av att spotta ut filer. Så är det det den ska göra så rekomenderar jag att köra på "statiska" bilder.

Anders 2004-11-03 09:57

Som jag förstod det ska användaren kunna ladda ner bilder om vissa parametrar i hans/hennes session stämmer, inte på alla bilder som hör till designen. Om det rör alla bilder (även små) som ligger på sidan och ingår i designen bör man inte köra dem genom ett script. Men om du vill räkna antal nerladdningar mm så borde det gå bra att köra genom ett script.

Mikael Simonsson 2004-11-03 11:31

Ett snabbt test med ApacheBench visar att det går ungefär 3 gånger snabbare att anropa bilden direkt.

Direkt:
Citat:

./ab -n 1000 -c 10 http://localhost/dev/image.jpg
...
Requests per second: 128.14 [#/sec]

Med PHP:
Citat:

./ab -n 1000 -c 10 http://localhost/dev/image.php
...
Requests per second: 37.41 [#/sec]

Förklaring av parametrarna till ab:
Citat:

-n requests Number of requests to perform
-c concurrency Number of multiple requests to make

image.php:
Kod:

$sFilename = "./image.jpg";
$f = fopen($sFilename, 'rb');

header('Content-Type: image/jpeg');
header('Content-Length: ' . filesize($sFilename));

fpassthru($f);
exit();

/ mikael

Mikael Simonsson 2004-11-03 12:07

Jag glömde ange storlek på bilden, jag testade med en JPEG på 2.2 MiB.

/ mikael

netflax 2004-11-03 14:54

Tack Mikael, mycket bra redovisning!

3 ggr är ganska mkt... dock är mitt problem att jag vill kunna begränsa access till vissa bilder / filer vilket avgörs i PHP-filen. Får nog ta och överväga det hela och se om det verkligen är värt det.

Mikael Simonsson 2004-11-05 15:39

Personligen tycker jag att du ska köra med PHP om du behöver begränsa tillgången som du säger. 3 gånger är INTE mycket om man tänker på vad som sker på servern när PHP används instället för att anropa bilden direkt.

Citat:

Requests per second: 37.41 [#/sec]
För att ha något att jämföra med så brukar sidor som den du just nu tittar på ligga runt 5-10 #/sec.

/ mikael

eg0master 2004-11-05 16:28

Citat:

Originally posted by Mikael Simonsson@Nov 5 2004, 16:39
Personligen tycker jag att du ska köra med PHP om du behöver begränsa tillgången som du säger. 3 gånger är INTE mycket om man tänker på vad som sker på servern när PHP används instället för att anropa bilden direkt.

Citat:

Requests per second: 37.41 [#/sec]
För att ha något att jämföra med så brukar sidor som den du just nu tittar på ligga runt 5-10 #/sec.

/ mikael

Jag håller med. Dessutom gjordes ju testen med en stor bild (2.2 MB) och med 10 samtidiga hämtningar. Det tolkar jag som om bilden kunde överföras 3.741 gånger per sekund requesttråd. Nedladdningstiden borde vara begränsande i det testet. Det kan ju vara overheaden i fpassthru som gör större skillnad än att PHP i övrigt anropas.

Testet borde göras om med en mindre fil (om det är mindre filer du vill accesskolla), men i det stora hela tycker jag du ska köra på en PHP lösning för att sfå den funktionalitet du vill ha.

I slutänden vill du ju göra så mkt mer än att bara hämta filen. Din accesskontroll (mot DB förmodar jag) kommer sannolikt stå för större del av tiden än vad fpassthru komemr göra.

kullervo 2004-11-05 20:37

Citat:

Originally posted by Mikael Simonsson@Nov 3 2004, 12:31
image.php:
Kod:

$sFilename = "./image.jpg";
$f = fopen($sFilename, 'rb');

header('Content-Type: image/jpeg');
header('Content-Length: ' . filesize($sFilename));

fpassthru($f);
exit();


Man kan göra koden något snabbare med readfile() istället för att öppna filen manuelt. Om PHP ska använda sig av mySQL för att beräkna behörigheten, kan en anslutning mot databasen som aldrig stängs öppnas. Då slipper man upprätthålla en anslutning samt logga in på mySQL för varje bild.

Mikael Simonsson 2004-11-06 11:08

Citat:

Originally posted by kullervo@Nov 5 2004, 21:37
Man kan göra koden något snabbare med readfile() istället för att öppna filen manuelt.
I det här fallet är det ingen skillnad i prestanda eftersom PHP måste göra samma sak internt, d.v.s. få ett handle till filen och sen anropa en annan funktion för att läsa innehållet. Istället skulle man kunna tänka sig att byta ut filesize() mot fstat(), men samma sak där, det gör ingen skillnad i prestanda.

Däremot kanske readfile() är enklare att använda här och ger lite snyggare kod.

zoran 2004-11-07 10:05

Citat:

Ursprungligen postat av kullervo
Citat:

Ursprungligen postat av Mikael Simonsson
image.php:
Kod:

$sFilename = "./image.jpg";
$f = fopen($sFilename, 'rb');

header('Content-Type: image/jpeg');
header('Content-Length: ' . filesize($sFilename));

fpassthru($f);
exit();


Man kan göra koden något snabbare med readfile() istället för att öppna filen manuelt. Om PHP ska använda sig av mySQL för att beräkna behörigheten, kan en anslutning mot databasen som aldrig stängs öppnas. Då slipper man upprätthålla en anslutning samt logga in på mySQL för varje bild.

Man kan dessutom använda sig av mysqli_prepare om man har blivit välsignad med PHP5. Det är något jag saknat i PHP sen länge. Många likadana querys där bara enstaka villkor ändras snabbas upp betydligt med detta. Perfekt för autenticeringssystem.

Sen det där med bilden, hur snabbt det blir beror lite hur PHP är implementerat på servern. Att bara göra en bench utan att tala om något om konfigurationen säger i princip inte ett dyft.

Den överheaden som tillkommer gentemot en "statisk" bild är ju först och främst att sidan måste parsas av PHP-tolken. Om det är CGI-installerad PHP så får man enorm overhead jämfört om man kör FastCGI eller som apachemodul.

Den andra överheaden som tillkommer är hur optimerad din kod är. Det exempel vi såg är den enklaste och som ger minimal overhead. Sen kan det ju vara så att man vill fippla med bilden i sig och då får man använda sig av andra imagefunktioner som säkert ger ännu mer överhead.

/Zoran

Mikael Simonsson 2004-11-07 16:30

Citat:

Originally posted by zoran@Nov 7 2004, 11:05
Sen det där med bilden, hur snabbt det blir beror lite hur PHP är implementerat på servern. Att bara göra en bench utan att tala om något om konfigurationen säger i princip inte ett dyft.

Den överheaden som tillkommer gentemot en "statisk" bild är ju först och främst att sidan måste parsas av PHP-tolken. Om det är CGI-installerad PHP så får man enorm overhead jämfört om man kör FastCGI eller som apachemodul.

Den andra överheaden som tillkommer är hur optimerad din kod är. Det exempel vi såg är den enklaste och som ger minimal overhead. Sen kan det ju vara så att man vill fippla med bilden i sig och då får man använda sig av andra imagefunktioner som säkert ger ännu mer överhead.

Jag ville bara visa ett så enkelt exempel som möjligt, jag tror att alla här är medvetna om att det blir skillnad om man blandar in databasanrop och liknande. Men som jag skrev tidigare så är detta ändå en bra bit ifrån vad normala "tunga" sidor tar att generera.

Givetvis kör jag PHP som en Apachemodul, ledsen att det inte framgick i mitt exempel.

/ mikael

WizKid 2004-11-07 17:29

Vet inte hur ApacheBench funkar men är det möjligt att den cachar bilderna och därför bara får ett 304 svar? För isåfall bör man lägga in samma sak i PHP skriptet vilket är rätt enkelt gjort.

FredrikMH 2004-11-07 19:09

Jag tror inte du ska bli så förskräckt av att php tar 3 gånger längre tid på sig att läsa filen än om apache skulle göra det. Jag vet inte vilken typ av sida du driver men du tvingar användaren att bli medlem (ha seession) för att se bilden och hotlinking slipper du. Har du otur kan hotlinking göra din servern mer beslastad än vad du kan tänka dig.

Mikael Simonsson 2004-11-07 19:16

Citat:

Originally posted by WizKid@Nov 7 2004, 18:29
Vet inte hur ApacheBench funkar men är det möjligt att den cachar bilderna och därför bara får ett 304 svar? För isåfall bör man lägga in samma sak i PHP skriptet vilket är rätt enkelt gjort.
En sån funktion skulle förstöra hela funktionen med programmet. Du kan läsa mer om ApacheBench här:
httpd.apache.org/docs/programs/ab.html

kullervo 2005-08-18 21:17

Drar upp den här gamla tråden eftersom jag sitter i samma sits nu.

Jag vill alltså gärna låta PHP sköta berhörighetskontroll för bilder. Jag har kört benchmark och kommit fram till att det är hälften så snabbt att göra detta med PHP. Nu är frågan om det har hänt något på den här fronten och alltså om det finns några bra metoder att snabba upp PHP. Jag har testat olika inställningar för output buffer utan nämnvärt resultat. Kan det vara så att PHP 5 av någon anledning är snabbare på detta? Andra tips på trim uppskattas (allt från kompileringsflaggor till inställningar).

Mjukvara:
Linux
Apache 2 (prefork MPM)
PHP 4

Testkörd kod:
Citat:

<?php
readfile('testfil');
?>


Micke04 2005-08-19 14:39

Jag använder eAccelerator som cachar phpfilerna färdigkompilerade. Detta hjälper mig en hel del. Jag vet inte hur mycket det hjälper vid bildvisning, men det är jag nyfiken på.

eAccelerator är en vidareutveckling av turckmmcache.

kullervo 2005-08-19 16:25

Med eAccelerator tjänar jag ca. 5-7% i tid. Det medgör att det bara tar 60% mer tid med PHP. Hur jag kunde få det till att det tog dubbelt så lång tid med PHP igår vet jag inte för det är samma kod jag kört testet på. Men men, 60% är inte så farligt mycket.

WizKid 2005-08-19 17:21

Hittade denna kommentar på php.net "readfile and fpassthru are about 55% slower than doing a loop with "feof/echo fread"." Vet inte om det stämmer men du skulle ju alltid kunna testa.

Tvartom 2005-08-23 12:09

Kul att denna gamla tråden kom upp igen.
Jag håller på med ett system där jag har stått inför precis
samma övervägande.

För att undvika att databasen behöver tillkallas vid var bild som ska skickas till webläsaren,
så funderar jag på följande.

Sidan som generarar alla [img]image.php?id...[/img]-tagar
kontrollerar ju även att bilden är godkänd för användarn
(Annars skulle inte tagen-skrivas)
Således behöver inte detta test göras fler gånger så en cache med
denna information lägges i en session-variabel.

Så image.php kontrollerar enbart mot databasen om bilden saknas i session-variabeln.
image.php rensar även i session-variabeln när bilden visasts, för att sessions-datamängden inte
ska växa ohämat.

Jag har inte haft tid att testa systemets prestanda än, men jag hoppas det ska snabba upp det hela!

/ Lasse

eg0master 2005-08-23 13:44

Tvartom: Jag tror inte din egen hemmagjorda cachning ger något nämnvärt i performance vinst.

För image.php måste ju läsa filen (readfile, read eller passthru) oavsett och det är där flaskhalsen ligger tror jag. Inte i hur effektivt du kollar om bilden är ok eller inte mot databasen.

Weaver 2007-08-28 14:23

Halkade in på denna gamla tråden.

Varför inte kombinera det bästa av två världar. Låt php kontrollera om användaren får ladda ned bilden och låt apache skicka den.

Jag tänker mig nått i stil med detta:
Kod:

image.php
Kontrollera om användaren får ladda ned bilden
  Ja användaren har rättighet
    header('Location: <bildens url>');
  Nej användaren har inte rättigheter att se bilden
    header('<sänd forbidden header>');

Någon kanske har lust att benchmarka

Dock så kan tekniska användare hotlinka till denna bilden om de tittar på headrarna som servern skickar tillbaka. Men i slutändan är väl allt en avvägning.

Edit: Formattering av pseudokod

WizKid 2007-08-28 14:39

Men om du gör header('Location: <bildens url>'); vad hindrar då någon att gå direkt till bilden?

Däremot om man använder lighttpd kan man göra det. Då kan man göra auth-kollen i php och sen sätta headern x-sendfile vilket gör att Lighttpd kommer outputa bilden åt en. Mer info finns på http://blog.lighttpd.net/articles/2006/07/...7/02/x-sendfile.

Weaver 2007-08-28 14:56

Citat:

Men om du gör header(Location: bildens url); vad hindrar då någon att gå direkt till bilden?

Läs min postning igen...

Citat:


Däremot om man använder lighttpd kan man göra det. Då kan man göra auth-kollen i php och sen sätta headern x-sendfile vilket gör att Lighttpd kommer outputa bilden åt en. Mer info finns på http://blog.lighttpd.net/articles/2006/07/02/x-sendfile.

Intressant, gjorde lite mer research på X-Sendfile. Finns en mod så att också Apache användare kan få tillgång till denna utmärkta funktion: http://tn123.ath.cx/mod_xsendfile/

Så då är det bara att ta mitt exempel och byta ut Location mot x-sendfile och se till att modden är installerad på din Apache server.

Nu är det verkligen det bästa av två världar ;)

Spirre 2007-08-28 15:12

Testa annars xcache till php.. vilket jag tyckte gjorde mer än apc/eacc..

Ulitmat lösning - Lighttpd - php - xcache har funkar perfekt för mig..

WizKid 2007-08-28 15:21

Citat:

Originally posted by Weaver@Aug 28 2007, 13:56
Läs min postning igen...
Läste lite för snabbt :)

Däremot så kommer ju även prestandan bli lidande i ditt fall. Eftersom först görs anropet till PHP skriptet som kommer skicka tillbaka till besökaren att bilden finns på plats x. Och sen gör användaren ett anrop till bilden. Det gör att det kommer göras 2 anrop per bild.

Weaver 2007-08-28 16:09

Citat:

Originally posted by WizKid@Aug 28 2007, 15:21

Däremot så kommer ju även prestandan bli lidande i ditt fall. Eftersom först görs anropet till PHP skriptet som kommer skicka tillbaka till besökaren att bilden finns på plats x. Och sen gör användaren ett anrop till bilden. Det gör att det kommer göras 2 anrop per bild.

Jag är inte så säker på det. Apache/Lighttpd är mycket effektivare på att skicka statiska filer än vad PHP är. De kan använda tekniker som sendfile och mmap som inte PHP har tillgång till med tex fread. Visst det kommer två anrop istället för ett, men varje request är i detta fallet mer effektiv.
I slutändan är ju inte PHP gjort för att skicka ut statisk data.

Nu är jag inte så insatt i Keep-Alives, men säg att man sätter keep-alives till 2 sekunder. Då borde requesten för själva bilden komma i samma socket-session så att man undviker teardown och setup för en ny anslutning till servern.

Hade varit väldigt skoj att bencha detta :)


Alla tider är GMT +2. Klockan är nu 12:11.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson