Webcachen er en frittstående executable som kjører på de fleste
POSIX-plattformer. Programmet inneholder 2 webservere, en cache og en
administrasjonserver for å monitorere cachen.
Fremover planlegger jeg å legge til features i administrasjonserveren og
lage en bra GUI for denne. I den forbindelse ber jeg deg om hjelp til
å finne ut hvilke features som er viktige og hvilke features som bare er
tull og tøys. Jeg blir takknemlig for alle forslag til features og
funksjonalitet. (Bugs og feilrapporter mottas også med takk)
All sourcen ligger på http://www.metasystems.no/meta-0.0.1.tar.gz, og
installasjon er forhåpentligvis bare
tar zxf meta-0.0.1.tar.gz
cd meta-0.0.1
./configure && make && make check
Selve webcache-programmet ligger under src/cache og kan startes derfra.
Man bør kikke på webcached.conf først og eventuelt også kjøre scriptet
create_directory_tree for å bygge litt testdata.
Bjørn
PS: Dokumentasjonen er selvsagt under enhver kritikk akkurat nå, men
bare spør om det er noe som du lurer på eller virker rart.
vil ikkje OSet klare å cache ofte brukte statiske filer uansett?
viss du brukar Linux, har du vurdert tux (HTTP-nisse i kjerna)?
--
Kjetil T.
Jo, operativsystemet gjør vanligvis en glimrende jobb i så måte.
Men HTTP-protokollen inneholder endel ting som krever at man gjør
systemkall for å implementere, eksempelvis "GET If-Modified-Since", som
returnerer en fil dersom filen er endret etter en viss dato.
For å finne ut om filen har endret seg, må man vanligvis kalle open(),
fstat() og så close()[1]. Det er 3 systemkall per request bare for å
finne datoen på filen. Om du skal serve 10.000 requester i sekundet,
blir det 30.000 systemkall. Det tar tid.
Webcached cacher denne informasjonen slik at man sparer masse
systemkall, dermed blir ytelsen bra.
>
> viss du brukar Linux, har du vurdert tux (HTTP-nisse i kjerna)?
Kjenner til tux, men har ikke vurdert å bruke den. Bruker heller
Highlander som er langt mer portabel og fleksibel. Nå er jeg kanskje
ikke helt nøytral og objektiv på det punktet... ;-)
Bjørn
[1] Man kunne kalt stat() isteden, men dersom filen faktisk er nyere må
man lese den. Dermed må man kall open() og close() igjen. Det blir en
balansegang.
| Kjetil Torgrim Homme wrote:
| >
| > vil ikkje OSet klare å cache ofte brukte statiske filer uansett?
|
| Jo, operativsystemet gjør vanligvis en glimrende jobb i så måte.
| Men HTTP-protokollen inneholder endel ting som krever at man gjør
| systemkall for å implementere, eksempelvis "GET If-Modified-Since", som
| returnerer en fil dersom filen er endret etter en viss dato.
|
| For å finne ut om filen har endret seg, må man vanligvis kalle open(),
| fstat() og så close()[1]. Det er 3 systemkall per request bare for å
| finne datoen på filen. Om du skal serve 10.000 requester i sekundet,
| blir det 30.000 systemkall. Det tar tid.
Operativsystemet cacher også resultatet av stat(), så det er like
lite nødvendig å cache dette selv som å cache innholdet av filene.
En rimelig rask PC (dvs. ikke eldre enn 5 år) bør fint klare et
par hundre tusen stat() i sekundet.
| [1] Man kunne kalt stat() isteden, men dersom filen faktisk er nyere må
| man lese den. Dermed må man kall open() og close() igjen. Det blir en
| balansegang.
Nei, det blir det ikke. Hvis du kaller stat() først, og fila ikke
har endra seg, slipper du å kalle open() og close(), og det vil du
spare merkbart på.
Hvis fila _har_ endra seg, kommer du ca. likt ut i forhold til
open()/fstat()/close(), så jeg kan ikke se annet enn at du sparer på
å kalle stat() først. Spesielt hvis du behandler 10.000 requester i
sekundet. Hvor stor prosentandel av de 10.000 requestene du behandler
hvert sekund regner du med spør etter en fil som har blitt endret
siden sist den ble lest? Det kan lønne seg å optimalisere for de
tilfellene som inntreffer oftest.
--
Per Kristian Hove
Institutt for matematiske fag
NTNU Gløshaugen, Trondheim
Hva mener du egentlig her? Sier du at det er like raskt å lese en fil
fra disk(eller OS cache) som det er å lese filen fra RAM?
> En rimelig rask PC (dvs. ikke eldre enn 5 år) bør fint klare et
> par hundre tusen stat() i sekundet.
Jeg skrev et lite testprogram som målte ytelsen på stat() og fstat().
Programmet leste inn 360.000 filnavn og plukket så random blant disse
200.000 ganger og kjørte stat()/fstat() på hver fil.
Min PC (3GHz P4 Prescott, 1MB cache og HT disabled, og 2 stk. 10K
disker, Linux 2.6.13-15.7-smp) stat()'er 200.000 filer på 1.27 sekunder.
Samme PC, samme program, klarer å fstat()'e 200.000 filer på 1.60
sekunder. En stat() basert løsning er altså, på min maskin, 20,7%
raskere. Interessant.
>
> | [1] Man kunne kalt stat() isteden, men dersom filen faktisk er nyere må
> | man lese den. Dermed må man kall open() og close() igjen. Det blir en
> | balansegang.
>
> Nei, det blir det ikke. Hvis du kaller stat() først, og fila ikke
> har endra seg, slipper du å kalle open() og close(), og det vil du
> spare merkbart på.
>
> Hvis fila _har_ endra seg, kommer du ca. likt ut i forhold til
> open()/fstat()/close(), så jeg kan ikke se annet enn at du sparer på
> å kalle stat() først. Spesielt hvis du behandler 10.000 requester i
> sekundet. Hvor stor prosentandel av de 10.000 requestene du behandler
> hvert sekund regner du med spør etter en fil som har blitt endret
> siden sist den ble lest? Det kan lønne seg å optimalisere for de
> tilfellene som inntreffer oftest.
Jeg er litt usikker på om du snakker generelt eller relatert til
webcached. For sistnevntes del er problemstillingen irrelevant da alt
caches i RAM og ingenting leses fra disk unntatt når man gjør en
eksplisitt refresh av cachen.
Generelt sett tror jeg du har rett, det vil være raskere å kalle stat()
først unntatt når en meget stor andel av filene endres mellom hver request.
Jeg modifiserte testprogrammet mitt litt slik at det målte hvor mye tid
som ble brukt på henholdsvis open(), fstat() og close(). 100% riktig er
det nok ikke, jeg bruker clock() for å måle. Tallene varierte litt, men
ordelingen ble omtrent slik:
open(): 1.38 sekunder
fstat(): 0.18 sekunder
close(): 0.20 sekunder
total : 2.11 sekunder (høyere enn før p.g.a. mer kode som måler tid)
Dette ser ut til å bekrefte det du skriver.
Bjørn
PS: Jeg testet samme program på en annen PC med XP+cygwin. Det var tregt
hinsides beskrivelse...
Filsystemcache _er_ RAM, og den har attpåtil mekanismer som sørger for
å kaste ut ugyldige data automatisk.
Geir
Jøss, det var en bombe.
Det overrasker meg stadig hvor eksplisitt man må uttrykke seg for unngå
misforståelser på news.
Bjørn
| Per Kristian Hove wrote:
| > [Bjørn Augestad]
| >
| > | Kjetil Torgrim Homme wrote:
| > | >
| > | > vil ikkje OSet klare å cache ofte brukte statiske filer uansett?
| > |
| > | Jo, operativsystemet gjør vanligvis en glimrende jobb i så måte.
| > | Men HTTP-protokollen inneholder endel ting som krever at man gjør
| > | systemkall for å implementere, eksempelvis "GET If-Modified-Since", som
| > | returnerer en fil dersom filen er endret etter en viss dato.
| >
| > Operativsystemet cacher også resultatet av stat(), så det er like
| > lite nødvendig å cache dette selv som å cache innholdet av filene.
|
| Hva mener du egentlig her?
At OSet er like flink til å cache metainformasjon om filer som
det er til å cache innholdet av filer. Det virker som du tror at
systemkallet stat() er dyrt (ressurskrevende).
Homme spør om ikke OSet er så flink til å cache filinnhold at
programmet ditt slipper å gjøre det selv, og det sier du at du er
enig i.
Du er altså enig i at det (i utgangspunktet) er bortkastet av
programmet ditt å cache innholdet i filene (siden OSet gjør dette for
deg på en utmerket måte), men sier at programmet cacher både innhold
i filene og metainformasjon om filene (sist-endret-dato) fordi
programmet er avhengig av å raskt få tilgang til metainformasjonen.
Og jeg sier at OSet cacher metainformasjon like effektivt som det
cacher filinnhold.
Skjønner du hvor jeg vil nå?
Jeg sier altså at det er en vanvittig sløsing av ressurser å cache
både filinnholdet og metainformasjonen for å unngå et par kall til
stat(), og at det ikke er nødvendig for å implementere en effektiv
"GET If-Modified-Since".
| Sier du at det er like raskt å lese en fil fra disk(eller
| OS cache) som det er å lese filen fra RAM?
Nei, jeg snakket kun om informasjonen som stat() returnerer (altså
metainformasjonen), ikke filinnholdet. Men siden du spør:
Problemstillingen er egentlig omvendt: Sier du at det er raskere å
lese filen fra RAM enn å lese den fra OS cache? (Dette er *ikke* et
retorisk spørsmål)
Hvis det du leser fra fila skal skrives til en socket, kan du bruke
sendfile(), og da unngår du den kopieringen av data fra userland
til kernel som skjer når du bruker write(). OSet har altså bedre
forutsetninger for å gjøre dette raskt enn programmet ditt har.
Per Kristian Hove wrote:
> [Bjørn Augestad]
>
> | Per Kristian Hove wrote:
> | > [Bjørn Augestad]
> | >
> | > | Kjetil Torgrim Homme wrote:
> | > | >
> | > | > vil ikkje OSet klare å cache ofte brukte statiske filer uansett?
> | > |
> | > | Jo, operativsystemet gjør vanligvis en glimrende jobb i så måte.
> | > | Men HTTP-protokollen inneholder endel ting som krever at man gjør
> | > | systemkall for å implementere, eksempelvis "GET If-Modified-Since", som
> | > | returnerer en fil dersom filen er endret etter en viss dato.
> | >
> | > Operativsystemet cacher også resultatet av stat(), så det er like
> | > lite nødvendig å cache dette selv som å cache innholdet av filene.
> |
> | Hva mener du egentlig her?
>
> At OSet er like flink til å cache metainformasjon om filer som
> det er til å cache innholdet av filer. Det virker som du tror at
> systemkallet stat() er dyrt (ressurskrevende).
>
> Homme spør om ikke OSet er så flink til å cache filinnhold at
> programmet ditt slipper å gjøre det selv, og det sier du at du er
> enig i.
Jeg sa vel bare at OS er flinke til å cache, ikke at mitt program
slipper å cache. Mulig at If-Modified-Since var et dårlig eksempel på
hvorfor.
>
> Du er altså enig i at det (i utgangspunktet) er bortkastet av
> programmet ditt å cache innholdet i filene (siden OSet gjør dette for
> deg på en utmerket måte), men sier at programmet cacher både innhold
> i filene og metainformasjon om filene (sist-endret-dato) fordi
> programmet er avhengig av å raskt få tilgang til metainformasjonen.
>
> Og jeg sier at OSet cacher metainformasjon like effektivt som det
> cacher filinnhold.
>
> Skjønner du hvor jeg vil nå?
Jupp, det var uttrykket "like lite nødvendig" som jeg hang meg opp i, da
jeg jo mener at det *er* nødvendig å cache. Se mer om dette lengre ned.
>
> Jeg sier altså at det er en vanvittig sløsing av ressurser å cache
> både filinnholdet og metainformasjonen for å unngå et par kall til
> stat(), og at det ikke er nødvendig for å implementere en effektiv
> "GET If-Modified-Since".
>
>
> | Sier du at det er like raskt å lese en fil fra disk(eller
> | OS cache) som det er å lese filen fra RAM?
>
> Nei, jeg snakket kun om informasjonen som stat() returnerer (altså
> metainformasjonen), ikke filinnholdet. Men siden du spør:
>
> Problemstillingen er egentlig omvendt: Sier du at det er raskere å
> lese filen fra RAM enn å lese den fra OS cache? (Dette er *ikke* et
> retorisk spørsmål)
Uten sendfile(), ja.
>
> Hvis det du leser fra fila skal skrives til en socket, kan du bruke
> sendfile(), og da unngår du den kopieringen av data fra userland
> til kernel som skjer når du bruker write(). OSet har altså bedre
> forutsetninger for å gjøre dette raskt enn programmet ditt har.
>
La meg begynne med en liten innledning om programmet og litt filosofi
som jeg har, så faller kanskje ting litt mer på plass?
1. Portabilitet mellom ulike POSIX-plattformer er viktig (for meg), jeg
ønsker at programmene jeg skriver skal kjøre på flest mulige plattformer
uten endring og uten å bruke plattformspesifikke løsninger. Hver
plattform(Solaris, *BSD, Unix, AIX, HP-UX, OSF, whatever) har vanligvis
god støtte for POSIX, i tillegg fins ofte ikke-portable tillegg og
utvidelser, f. eks. /dev/poll, /dev/epoll, sendfile() osv osv. Disse kan
jeg ikke bruke fordi jeg ønsker strict POSIX compliance(om det er noe
som heter det:-))
2. Ytelse er også viktig(for meg). Jeg liker at ting går fort og bruker
lite ressurser og det er grunnen til at jeg skriver ting i C fremfor
andre språk. Så max ytelse er et mål, og for å oppnå max ytelse ønsker
jeg blant annet å unngå *alle* unødige operasjoner, inklusive unødige
systemkall og context switches. Mulig det er en hangup hos meg...
Det var litt bakgrunn. Så til design av webcache og hvorfor jeg velger å
preloade filer i RAM fremfor å lese dem fra disk og stole på OS'ets cache.
a) sendfile() og lignende er glimrende funksjoner, men ikke portable.
Som det står på sendfile()s egen man page, "It should not be used in
portable programs". Så sendfile() er ut.
b) Alternativet til å preloade filer er å lese dem fra disk/OS/cache
hver gang før man sender filen til socketen. Hvordan kan det gjøres uten
sendfile()? Man kan mmap()'e og kalle write(), loope med et fixed size
buffer og kalle read() og så write(), eller allokere et buffer like
stort som filen og kalle read() og write() en gang. Det fins sikkert
flere alternativ, men man ender opp med masse buffer copy til/fra
kernel, og jeg tror det blir adskillig tregere enn å skrive data til
socket fra et minneområde i user space. Buffer copy blir det, men ikke
like mye.
Ellers tror jeg ikke det er en "vanvittig sløsing av ressurser" å laste
filer i minne, i det minste ikke på UNIX. Operativsystemet vil AFAIK
prioritere process ram og redusere egen cache tilsvarende om det er
knapphet på ressurser, så mengden RAM som går med til å lagre X MB med
data blir den samme. Jeg forutsetter her at maskinen er dedikert til
formålet, nemlig å serve statiske data så fort som mulig.
En Quick&dirty måte å finne ut av dette på, er selvsagt å prøve. ;-)
Om du laster ned koden det var linket til i første posten og bygger den,
fins det mer enn bare webcache der. Det fins også en slags HTTP-basert
FTP-server, d.v.s. et program som bruker HTTP for transport og HTML for
GUI. Dette programmet gjør mer eller mindre det samme som webcached, men
leser all info fra operativsystemet hver gang.
Om du endrer litt i konfigurasjonsfilen highftp.conf (endre rootdir til
det samme som for webcached) og bruker src/cache/create_directory_tree
til å generere litt filer, kan du kjøre 2 algoritmer mot de samme filene.
Det fins et tredje program også, stress_httpd, som genererer trafikk.
Stress_httpd er et ganske dårlig skrevet program, så det feiler
innimellom, men kommandoen
time stress_httpd -p11 -c 100 -f 100 -u /a/b/c/1.txt localhost 2000
vil bruke HTTP 1.1, starte 100 tråder(-c) som hver gjør 100 fetches for
url /a/b/c/1.txt. ftp-serveren leser filen fra disk og skriver den til
socketen på "tradisjonelt vis".
Jeg prøvde det på min maskin akkurat nå, og webcached brukte 1.061
sekunder mens highftp brukte 1.359 sekunder på 10.000 requests, en
forskjell på 28%. Da var filen /tmp/dirtree/a/b/c/1.txt endret til å ha
en størrelse på 100KB. Sikkert ikke den perfekte testen, men en
indikasjon er det jo.
For min del skjønner jeg godt hva du mener og er stort sett enig. Men
jeg har opplevd mye rart på unix(som at ls-kommandoer i ett directory
bruker 26 minutter på å fullføres og at rm -rf rusler og går i 90
minutter på ett directory tree på TOPP maskinvare), og prisen man må
betale for unødige systemkall og context switches har satt sine spor. :-)
Bjørn
AIX og Solaris er UNIX 03-sertifisert, så eg trur dei kvalifiserer, i
alle fall. sjølvsagt er POSIX mindre omfattande enn dette, men eg
trur ikkje Linux støttar POSIX 100% (det fantest ein spesialdistro ein
gong som var sertifisert, men patchane vart berre delvis akseptert).
mmap() er uansett i POSIX.
> 2. Ytelse er også viktig(for meg). Jeg liker at ting går fort og
> bruker lite ressurser og det er grunnen til at jeg skriver ting i
> C fremfor andre språk. Så max ytelse er et mål, og for å oppnå max
> ytelse ønsker jeg blant annet å unngå *alle* unødige operasjoner,
> inklusive unødige systemkall og context switches. Mulig det er en
> hangup hos meg...
eg har det på same måten :-)
> a) sendfile() og lignende er glimrende funksjoner, men ikke
> portable. Som det står på sendfile()s egen man page, "It should
> not be used in portable programs". Så sendfile() er ut.
greit.
> b) Alternativet til å preloade filer er å lese dem fra
> disk/OS/cache hver gang før man sender filen til socketen. Hvordan
> kan det gjøres uten sendfile()? Man kan mmap()'e og kalle write(),
> loope med et fixed size buffer og kalle read() og så write(),
> eller allokere et buffer like stort som filen og kalle read() og
> write() en gang. Det fins sikkert flere alternativ, men man ender
> opp med masse buffer copy til/fra kernel, og jeg tror det blir
> adskillig tregere enn å skrive data til socket fra et minneområde
> i user space. Buffer copy blir det, men ikke like mye.
for read()/write(), ja. men for mmap()/write()? korleis er det
forskjellig frå å ha data i allokert minne? du vil få ein
buffer-kopiering i det du flyttar data inn i TCP-pakkar, men det skjer
uansett (sendfile() kan unngå det i visse tilfelle).
> Ellers tror jeg ikke det er en "vanvittig sløsing av ressurser" å
> laste filer i minne, i det minste ikke på UNIX. Operativsystemet
> vil AFAIK prioritere process ram og redusere egen cache
> tilsvarende om det er knapphet på ressurser, så mengden RAM som
> går med til å lagre X MB med data blir den samme. Jeg forutsetter
> her at maskinen er dedikert til formålet, nemlig å serve statiske
> data så fort som mulig.
det er vel i grunnen det som er problemet: du gjer ei statisk
vurdering av at dette skal liggje i cache, men dette kan omfatte filer
som aldri er etterspurt. OSet vil kvie seg for å kaste ut dette
minnet til swap og bruke det til cache i staden.
> Om du endrer litt i konfigurasjonsfilen highftp.conf (endre
> rootdir til det samme som for webcached)
sorry, eg er lat. kva er highftp?
> Jeg prøvde det på min maskin akkurat nå, og webcached brukte 1.061
> sekunder mens highftp brukte 1.359 sekunder på 10.000 requests, en
> forskjell på 28%. Da var filen /tmp/dirtree/a/b/c/1.txt endret til
> å ha en størrelse på 100KB. Sikkert ikke den perfekte testen, men
> en indikasjon er det jo.
har du prøvd det opp mot Apache eller thttpd?
(sorry viss eg verkar veldig negativ, det er ikkje meininga å ta frå
deg gleda ved å programmere og skape noko. eg synest berre det er
betre å forbetre eksisterande generelle løysingar enn å innføre nye
spesialløysingar.)
> For min del skjønner jeg godt hva du mener og er stort sett enig. Men
> jeg har opplevd mye rart på unix(som at ls-kommandoer i ett directory
> bruker 26 minutter på å fullføres
hehe, har vore ute for dette såpass ofte at det ligg i ryggmargen å
køyre "/bin/ls -f" for å få optimal ytelse (utan stat() av filer eller
sortering av utskrifta) når eg veit at eg er inne i ein stooor katalog
(100k+ filer).
> og at rm -rf rusler og går i 90 minutter på ett directory tree på
> TOPP maskinvare),
ojsan. kjappare å kopiere dei bitane du vil ta vare på og gjere mkfs?
:-)
--
Kjetil T.
> mmap() er uansett i POSIX.
>
Dagens versjon av Highlander bruker ikke mmap() for å sende filer, men
den bør kanskje gjøre det. mmap() er ført opp på TODO-listen.
[snip]
>
>> b) Alternativet til å preloade filer er å lese dem fra
>> disk/OS/cache hver gang før man sender filen til socketen. Hvordan
>> kan det gjøres uten sendfile()? Man kan mmap()'e og kalle write(),
>> loope med et fixed size buffer og kalle read() og så write(),
>> eller allokere et buffer like stort som filen og kalle read() og
>> write() en gang. Det fins sikkert flere alternativ, men man ender
>> opp med masse buffer copy til/fra kernel, og jeg tror det blir
>> adskillig tregere enn å skrive data til socket fra et minneområde
>> i user space. Buffer copy blir det, men ikke like mye.
>
>
> for read()/write(), ja. men for mmap()/write()? korleis er det
> forskjellig frå å ha data i allokert minne? du vil få ein
> buffer-kopiering i det du flyttar data inn i TCP-pakkar, men det skjer
> uansett (sendfile() kan unngå det i visse tilfelle).
Vanskelig å si hvor mye tregere/raskere en mmap() basert løsning er.
Stevens regnet jo litt på det i APUE, kap. 12.9, og målte at
mmap()+memcpy() var raskere enn read()+write(). Men mmap()+memcpy() kan
ikke brukes med sockets.
La oss se på antall operasjoner som må gjøres for å flytte data til
socket i de 2 alternativene:
webcached : write()
mmap alternativ: open(), fstat(), mmap(), write(), munmap(), close().
Intuitivt ser jo alternativ 2 litt tregere ut, ikke sant?
La os si at webserver-maskinen er en Sun Fire T2000 server, med 8x4 HW
threads, og konfigurerer webserveren til å kjøre en thread pool på 64
threads i parallell (Det er vel ikke helt urimelig). Worst case blir da
at man gjør 64 samtidige mmap() operasjoner. Hvor mye locking/blocking
får man i kjernen da, og hvor mange context switches? Ikke vet jeg, men
noe må det jo bli?
>> Ellers tror jeg ikke det er en "vanvittig sløsing av ressurser" å
>> laste filer i minne, i det minste ikke på UNIX. Operativsystemet
>> vil AFAIK prioritere process ram og redusere egen cache
>> tilsvarende om det er knapphet på ressurser, så mengden RAM som
>> går med til å lagre X MB med data blir den samme. Jeg forutsetter
>> her at maskinen er dedikert til formålet, nemlig å serve statiske
>> data så fort som mulig.
>
>
> det er vel i grunnen det som er problemet: du gjer ei statisk
> vurdering av at dette skal liggje i cache, men dette kan omfatte filer
> som aldri er etterspurt. OSet vil kvie seg for å kaste ut dette
> minnet til swap og bruke det til cache i staden.
Caching av hva da?
(Husk at jeg forutsetter en dedikert maskin)
>
>
>> Om du endrer litt i konfigurasjonsfilen highftp.conf (endre
>> rootdir til det samme som for webcached)
>
>
> sorry, eg er lat. kva er highftp?
Min feil, jeg var litt uklar i forrige post. La meg prøve igjen.
1. Highlander er et bibliotek, skrevet i C, som implementerer en HTTP
server.
2. Highftp er et program, skrevet i C, som lar brukere liste filer og
directories i en browser, samt downloade filer fra en server. Highftp
bruker libhighlander for all HTTP/TCP trafikk.
3. Om du vil prøve highftp, er det bare å laste ned koden, kjøre
./configure && make, og så gå til directoriet src/ftp. Der skal du finne
en executable ved navn highftp. Om du starter programmet slik:
./highftp -c ./highftp.conf
og så browser deg til http://localhost:2000, skal du få listet ut /tmp
directoriet ditt og kan så laste ned filer derfra.
En ting som kan være litt forvirrende, er at Highlander er et web server
bibliotek man linker inn i sin egen applikasjon. Vanligvis er jo en web
server et eget program i seg selv.
>
>
>> Jeg prøvde det på min maskin akkurat nå, og webcached brukte 1.061
>> sekunder mens highftp brukte 1.359 sekunder på 10.000 requests, en
>> forskjell på 28%. Da var filen /tmp/dirtree/a/b/c/1.txt endret til
>> å ha en størrelse på 100KB. Sikkert ikke den perfekte testen, men
>> en indikasjon er det jo.
>
>
> har du prøvd det opp mot Apache eller thttpd?
Ikke i det siste. Vanskelig å måle skikkelig fordi man trenger så mye
nettverks-HW, HW jeg ikke har og ikke kommer til å kjøpe. Et 100Mbs
Ethernet blir raskt saturert og å teste på localhost blir feil det også.
BTW, apache har en en modul som heter mem_cache, som cacher "objects in
heap storage" ...
>
> (sorry viss eg verkar veldig negativ, det er ikkje meininga å ta frå
> deg gleda ved å programmere og skape noko. eg synest berre det er
> betre å forbetre eksisterande generelle løysingar enn å innføre nye
> spesialløysingar.)
Du virker ikke negativ i det hele tatt. Hvilke generelle løsninger
tenker du forresten på?
Ellers kan jeg jo nevne at Highlander ble skrevet for å kunne
implementere server side kode i C eller C++ istedenfor Java, javascript,
PHP, whatever, og det fungerer veldig bra. Highftp og webcached er
'proof of concept' program for å teste highlanderbiblioteket.
Men Highlander kan brukes til så mye mer enn det, til ting som Apache
ikke kan brukes til. Jeg har brukt Highlander til å distribuere CORBA
IOR's til klienter, da ble Highlander linket inn i en CORBA server og
startet i en egen thread som servet HTTP requests. Resten av prosessen
servet CORBA requests. I tillegg til IOR distribusjon fra http-tråden,
var det også HTML-sider for status, statistikk og dokumentasjon, alt
sammen embedded i CORBA-serveren.
Den minste prosessoren Highlander har kjørt på var en Analog Devices
Blackfin BF533 DSP som kjørte ucLinux, tviler på at Apache hadde fungert
på den. <G>
[snip]
>
>> og at rm -rf rusler og går i 90 minutter på ett directory tree på
>> TOPP maskinvare),
>
>
> ojsan. kjappare å kopiere dei bitane du vil ta vare på og gjere mkfs?
> :-)
mkfs var ikke et alternativ, diskene satt i et Hitachi 9960 kabinett og
directoriene var en del av en stor partisjon, jeg hadde ikke engang root
på maskinen. Løsningen ble å skrive et eget rm-program som halverte
tiden det tok å slette 4-5 millioner filer per kjøring. Det fungerte
bra.(mimre, mimre)
Bjørn
tips #1 er å måle hva som faktisk er viktig for ytelsen.
det er lett å svi av en masse tid på å skrive noe som ikke
nødvendigvis bidrar mye til å øke ytelsen, men som er moro å lage.
(jeg snakker av erfaring her: det er lett å bruke mye tid på å skrive
noe som resulterer i en 2% ytelsesforbedring og så oppdage at det
finnes lavthengende frukt som kan øke ytelsen med 500% :-)
| Jeg liker at ting går fort og bruker lite ressurser og det er
| grunnen til at jeg skriver ting i C fremfor andre språk.
med mindre du skal gjøre veldig systemnære ting er det egentlig ikke
veldig mye vits i å bruke C her -- annet enn fordi man har lyst (som
er en høyest legitim grunn). f.eks sier du ingenting om å låse pages
i minnet eller å programmere spesifikt for minnelokalitetsfordeler el.
[klipp]
| b) Alternativet til å preloade filer er å lese dem fra disk/OS/cache
| hver gang før man sender filen til socketen. Hvordan kan det gjøres
| uten sendfile()? Man kan mmap()'e og kalle write(), loope med et fixed
| size buffer og kalle read() og så write(), eller allokere et buffer
| like stort som filen og kalle read() og write() en gang. Det fins
| sikkert flere alternativ, men man ender opp med masse buffer copy
| til/fra kernel, og jeg tror det blir adskillig tregere enn å skrive
| data til socket fra et minneområde i user space. Buffer copy blir det,
| men ikke like mye.
ja, mmap() er ikke nødvendigvis noen effektiv måte å gjøre ting på.
| Ellers tror jeg ikke det er en "vanvittig sløsing av ressurser" å
| laste filer i minne, i det minste ikke på UNIX. Operativsystemet vil
| AFAIK prioritere process ram og redusere egen cache tilsvarende om det
| er knapphet på ressurser, så mengden RAM som går med til å lagre X MB
| med data blir den samme. Jeg forutsetter her at maskinen er dedikert
| til formålet, nemlig å serve statiske data så fort som mulig.
en tanke er om du kanskje kan ha dataene komprimert i minnet.
spesielt hvis det dreier seg om lett komprimerbare data som f.eks
tekst. hvis du er heldig kan det jo tenkes at klienten aksepterer
komprimerte data slik at du bare kan pushe dataene rett til klienten
komprimert?
(er en stund siden jeg gjorde målinger på slikt, men mener å huske at
en venn av meg nevnte noe om et lignende scenario der det lønte seg).
| En Quick&dirty måte å finne ut av dette på, er selvsagt å prøve. ;-)
det er ingenting "dirty" med å gjøre benchmarks. det er eneste måten
å finne ut av ting på. (og husk at noe som er kjapt på en
kjerneversjon kan være tregt på en annen).
[klipp]
| For min del skjønner jeg godt hva du mener og er stort sett enig. Men
| jeg har opplevd mye rart på unix(som at ls-kommandoer i ett directory
| bruker 26 minutter på å fullføres og at rm -rf rusler og går i 90
| minutter på ett directory tree på TOPP maskinvare), og prisen man må
| betale for unødige systemkall og context switches har satt sine
| spor. :-)
det er snarere filsystemimplementasjon og -designvalg enn systemkall-
overhead og scheduling som er problemet i avsnittet ovenfor.
-Bjørn
--
There had better be cheese at the end of this maze!
jeg tror ikke mmap() til denne bruken er det du ønsker å bruke. les
heller filene inn i minnet. du er i alle fall ikke interessert i å
mmap()'e inn én og én fil.
gjør det enkelt. les ting inn i minnet, sørg evt for å låse de
page'ene som dataene dine er i, skriv rett fra bufferne uten kopiering
(ha heller multiple versjoner av filer som blir modifisert i minnet
samtidig og lag en primitiv GC eller noe i den duren). eksperimenter
litt med komprimering evt minnelokalitet.
> De siste dagene har jeg brukt på å skrive en web cache, d.v.s. et
> program som leser inn et sett med filer i RAM og så server HTTP requests
> for disse filene. Formålet med programmet er å kunne avlaste webservere
> ved å flytte statiske sider, bilder og lignende til en egen maskin.
Hmm, hvorfor ikke bare bruke en av de løsningene som allerede finnes
for den slags, slik som f.eks. squid?
Bjørn
--
I can't believe how pedantic you are.
Har alltid sett på squid som en caching proxy og ikke som en web server
cache. Kan kanskje brukes som begge deler?
Uansett, formålet med Highlander-biblioteket har alltid vært å kunne
implementere dynamiske websider i C istedenfor
Java/Javascript/PHP/latest fad.
Å implementere en webcache ved hjelp av Highlander er en såpass smal sak
at å vurdere alternativer var egentlig ikke tema. I tillegg er det greit
å ha et sett med applikasjoner basert på Highlander-biblioteket for å
prøve ut funksjonalitet, API og ytelse.
Bjørn
> Har alltid sett på squid som en caching proxy og ikke som en web server
> cache. Kan kanskje brukes som begge deler?
Jepp. Se http://www.squid-cache.org/Doc/FAQ/FAQ-20.html
Dette er brukt av flere store webtjenester. F.eks. VG (legg merke til
X-Cache-feltet, som er typisk squid):
bjorn@canardo:~$ telnet www.vg.no 80
Trying 193.69.165.21...
Connected to www.vg.no.
Escape character is '^]'.
HEAD / HTTP/1.0
HTTP/1.0 200 OK
Date: Fri, 23 Dec 2005 14:34:57 GMT
Server: Apache/1.3.27 (Unix)
Cache-Control: max-age=900
Expires: Fri, 23 Dec 2005 14:49:57 GMT
Last-Modified: Fri, 23 Dec 2005 14:30:01 GMT
ETag: "2b400e-22640-43ac09e9"
Accept-Ranges: bytes
Content-Length: 140864
Content-Type: text/html; charset=iso-8859-1
Age: 92
X-Cache: HIT from www.vg.no
Connection: close
Connection closed by foreign host.
Bjørn
--
The more shopping malls you have, the better, huh? So, Italian people
are felonious?
Det var interessant, takk for linken.
Bjørn
> a) sendfile() og lignende er glimrende funksjoner, men ikke
> portable. Som det står på sendfile()s egen man page, "It should not
> be used in portable programs". Så sendfile() er ut.
Hva med å bruke sendfile() der denne finnes, bytte til andre metoder
når den ikke er tilgjengelig (via autoconf og #ifdef, for eksempel),
og skjule hvilken ikke-portabel metode du bruker bak en portabel
abstraksjon?
--
,------------------- Markus Bjartveit Krüger ---------------------.
' `
` E-mail: mar...@pvv.org WWW: http://www.pvv.org/~markusk/ '
)-------------------------------------------------------------------(
Det er selvsagt mulig. Problemet er, slik jeg ser det, at andre unixer
implementerer sendfile() med "different semantics and prototypes"(fra
sendfile(2) man page). Jeg ønsker ikke å sette meg inn i alle
implementasjoner av sendfile() for å finne forskjeller mellom dem og så
kode meg rundt forskjellene. Bedre å holde seg til POSIX, IMO.
Bjørn
Farvel til ytelse...
DES
--
Dag-Erling Smørgrav - d...@des.no
hvor effektiv er egentlig sendfile(2) på ulike OS nå om dagen?
svært effektivt, i forhold til de portable alternativene.
hvis man antar at filen man skal sende allerede ligger i buffer cache:
read() / write():
gjenta
partial context switch inn i kjernen
copyout() fra buffer cache til applikasjonsminne
partial context switch ut av kjernen
partial context switch inn i kjernen
copyin() fra applikasjonsminne til mbuf
DMA fra mbuf til nettverkskort
partial context switch ut av kjernen
inntil hele filen er sendt.
mmap() / write():
gjenta
partial context switch inn i kjernen
copyin() fra applikasjonsminne til mbuf
DMA fra mbuf til nettverkskort
partial context switch ut av kjernen
inntil hele filen er sendt.
sendfile() i Linux (hvis jeg forstår den riktig):
partial context switch inn i kjernen
gjenta
kopier fra buffer cache til mbuf
DMA fra mbuf til nettverkskort
inntil hele filen er sendt
partial context switch ut av kjernen
sendfile() i FreeBSD:
partial context switch inn i kjernen
gjenta
DMA fra buffer cache til nettverkskort
inntil hele filen er sendt
partial context switch ut av kjernen
vet du om noen har gjort noen benchmarks? (helst med koden publisert)
-Bjørn
netperf støtter sendfile().
Bra oversikt, men ikke helt komplett. Både mmap() og sendfile() ønsker
"antall bytes" som parameter. Man må derfor også kalle fstat(). I
tillegg kommer selvsagt kall til open() og close().
Boa
Siden vi snakker om en HTTP-cache her, kan vi anta at dette er gjort
på forhånd, om ikke annet så for å kunne sende korrekt Content-Length.
Jeg har lagt til support for sendfile() i Highlander og vil komme
tilbake med en sammenligning mellom sendfile()-basert overføring og
algoritmen som brukes i webcached. Det vil ta litt tid p.g.a. omskriving
av diverse sentrale moduler.
Bjørn
Nå har jeg skrevet et program som tester ytelse på de to alternativene
som er relevante for webcached. Programmet sender en fil 2*x ganger til
en server(som bare leser og kaster data), en gang med x ganger med
sendfile() og x ganger med write().
Alternativ 1 er å bruke sendfile(). For å sende en fil med sendfile(),
kalles funksjonene open(), fstat(), sendfile() og close() en gang for
hver overføring.
Alternativ 2 er å cache filens innhold ved oppstart og så kun kalle
write() en gang for hver overføring.
Helt sammenlignbart er ikke testprogrammet, da man i en HTTP server
antakeligvis ville kalt setsockopt() 2 ganger for å sette TCP_CORK på og
av. Noe mer tid må altså brukes for sendfile() i real life løsninger.
Uansett, her er resultatene fra kjøring på en 3GHz Prescott HT. Testen
benyttet 12 ulike filstørrelser, fra 1k til 2048k. Hver fil ble sendt
25000 ganger med sendfile() og 25000 ganger med write().
Så er en portabel løsning "farvel til ytelse"? Testen indikerer ikke det.
Diverse:
- I testprogrammet ligger filen alltid i OS cache, i real life kan ikke
dette garanteres. Man risikerer altså at sendfile() må lese fra disk.
- CPU var ca. 23% idle under testen.
- Header tekster: dur = wall clock duration, utime er user time, stime =
system time, volsw er voluntary context switches og involsw er
involuntary context switches. Ting er målt med getrusage() og
gettimeofday().
- Om noen ønsker kildekoden til programmene, send en email. Trøbbel hos
active24 gjorde at jeg ikke fikk lagt ut sourcen :-(
Bjørn
Det er ikke en realistisk test (men selv denne urealistiske testen
viser at senfile er ca 20% raskere).
20% raskere, hvor fikk du det fra? Tror du at gjennomsnittlig
filstørrelse er 2MB?
Kanskje du kan komme opp med det du mener er en realistisk test eller i
det minste påpeke hva som gjør testen urealistisk?
Bjørn
Ingen paralellitet, ingen variasjon i belastning og datasett, osv.
Jeg har allerede nevnt netperf i denne tråden.
Dette er bare noe svada du lirer av deg i farta. Kom med noe konkret.
Hvorfor snippet du forresten dette med filstørrelse og ytelse? Passet
ikke tallene din virkelighet?
Uansett, denne tråden er over for min del. Makan til waste of time :-(
Bjørn