Armin Roehrl und Stefan Schmiedl
Wir geben Konfigurationstips zu Apache. Danach wird der Apache Quellcode gepatcht um noch etwas mehr herauszuholen. Trotz alledem ist thttpd oder Tux immer noch schnell als Apache. Bei heutigen Webprojekten reicht die Leistung eines einzelnen Webservers trotz aller Tricks in der Regel nicht mehr aus. Wir zeigen wie man mittels Loadbalancing (per Software (Eddie, LVS, mod_backhand) oder Hardware(Cisco's LocalDirector)) die Lasten auf viele Pinguine verteilen kann. Zum Schluss geben wir noch Tipps wie man die Reise der Daten zum Endkunden nocheinmal beschleunigen kann: Datenkomprimierung und lokale Mirror-server.
Apache ist ein Alleskönner, der mit dem Ziel einfach konfigurierbar und korrekt zu sein entwickelt wurde. Geschwindigkeit war nicht die Toppriorität und trotzdem ist die Geschwindigkeit von Apache schnell genug, dass er mit Abstand der beliebteste Webserver (63% aller Server [Netcraft]) geworden ist und gleichzeitig bei vielen Webventures nicht der Webserver, sondern CGI oder Database-Transaktionen der langsamste Faktor sind (wenn nicht sogar Bandwidth). Wir haben alle Benchmarks auf einem Linux System mit Kernel 2.4.4 und 266MHz Pentium II gemacht, aber die entstehenden Kurven und Ergebnisse sind auf einem schnellen Alpha-Cluster [clustersolutions] auch sehr ähnlich. Es wurde Apache 1.13.20 [apa], thttpd 2.22b [thttpd] sowie gcc 2.95.3 zum übersetzen der Quellen verwendet. Wie bei allen Benchmarks sollte man die genauen Zahlen mit Vorsicht genießen, aber da die Webserver sich auf verschiedenen Systemen ähnlich verhalten haben besitzen wir ein bisschen Vertrauen in sie. Zum Thema Webserver tuning/patching findet man sehr viele interessante Infos im Internet [tuning], doch leider sind viele oft für verschiedenen Webserver-versionen und deshalb von den fleissigen Open-source programmieren in der neuen Release schon integriert.
Der größte Hardware-Faktor ist eindeutig wieviel RAM ein Webserver hat. Webserver sollten nie swappen, da dies ihn verlangsamt und dafür sorgt, dass enttäuschte Surfer abwandern, oder gar mit "reload" die gleiche Seite noch einmal anfordern. Max Clients sollte in httpd.conf entsprechend eingestellt werden. Unter Umständen kann man dies nur ausprobieren (test-load) im Voraus herausbekommen, oder den Server im laufenden Betrieb beobachten und schnell handeln. Natürlich will man eine CPU die so schnell ist wie das Bankkonto es erlaubt, genug Bandwidth und schnelle Platten, falls nicht sowieso fast alle Seiten im RAM des Servers liegen. Auch hier gilt wieder ausprobieren ist das Maß aller Dinge.
HostnameLookups sollte off sein, weil ansonsten zu jeder Anfrage ein DNS lookup ausgeführt wird. Speziell bei der Verwendung von Allow from Domain oder Deny from Domain wird man mit einem doppelten Lookup gestraft. Ein reverse-lookup und anschließend ein forward um sicher zu gehen, dass der reverse nicht gespoofed war. Man kann sich auf lookups nur für Bilder und CGIs beschränken, aber wenn man nur die DNS Namen braucht kann sie mittels gethostbyname in den CGIs bekommen.
HostnameLookups off
HostnameLookups on
Ebenso sollten FollowSymLinks und SymLinksIfOwnerMatch vermieden werden, da sie zusätzliche System calls auslösen. Ein Aufruf von /index.html kosten ein Aufruf von lstat(2) der nicht gecacht wird.
DocumentRoot /www/htdocs
Options SymLinksIfOwnerMatch
AllowOverride sollte auf None im ganzen Dateisystem gesetzt werden, da für jeden Aufruf eines URLs Apache versucht .htacess an mehreren Stellen zu laden.
Ebenso sollte man auf Content-negotiation verzichten, falls das machbar ist. Vor allem sollte man keine Wildcards wie Directory "Index index" verwenden, sondern alle Optionen aufzählen nach Popularität der Anfrage geordnet "DirectoryIndex index.cgi index.pl index.shtml index.html".
Keep-alives erfordert Experimente. In der Regel ist dass ein Tradeoff zwischen Network Bandwidth und Serverresources, aber die Werte sollten trotzdem unter 45 Sekunden bleiben.
Bilder, etc. sollten von einem anderen Webserver kommen.
Webseiten und CGI-Seiten sollten Browser und Cache-freundlich sein (vielleicht sogar der Einsatz eines Caches für mod_php, etc.)
So wenig Module wie möglich verwenden. Schlank ist gleich schnell. Falls die Logfiles nicht gebraucht werden, sollte mit TransferLog die log entries direkt auf -dev-null gehen lassen. Auf keinen Fall Apache durch die tcpd wrapper falls verwendet laufen lassen. Wenn wirklich bestimmte Ips geblockt werden sollen, sollte dass mit "deny from" geblockt werden.
Wann immer möglich Fast-CGI, oder entsprechende mod_perl, mod_ruby, mod_php Module verwenden, so dass nicht jedesmal ein neuer Prozess gestartet wird.
So wenige Datein wie nur möglich öffnen und sicherstellen, dass sie wieder geschlossen werden.
Shell-Kommands, etc. durch ihren gesamten Pfad aufrufen, i.e. '/bin/date' anstatt von `date` in Perl Programmen, etc.
Man kann ganze Bücher zu dem Thema optimieren schreiben, z.B. in Perl zahlt es sich aus, den Speicher vorher zu reservieren, den Hash brauchen wird. Keys(%names)=256;
Nicht zu viele Dateien in einem Verzeichnis. Unterverzeichniss verwenden.
Mike Abbot leitete das Accelerating Apache Projekt von SGI, das leider mittlerweile eingestellt worden ist da die Apache Foundation nicht bereit war die Patches in die main Distribution zu stellen. Mit ein Grund war sicher auch die schlechte wirtschaftliche Lage von SGI. Sogar in Hollywood wird SGI dieser Tage durch billigere Linux Cluster ersetzt. Trotzdem gibt es Patches für mutige Leute für den aktuellen Apache 1.3.20 sowie den nicht allerneuesten Apache 2.0a6. SGI demonstriert eindrucksvoll, dass die Patches unter bestimmten Bedingungen einen enormen Vorteil versprechen [specweb96]. Der Geschwindigkeitszuwachs kommt in der Regel mit dem Preis von eingeschränkten Features (einem geschenkten Gaul schaut man nicht ins Maul). Uns ist es nicht gelungen den Standard Patch auf unserem Suse System mit patch 2.5.4 trotz -p Optionen zum Laufen zu bringen. Es erstaunt wohl kaum, dass es unter Irix auf Anhieb klappte. Patch wird ein Verzeichnis oberhalb des Apache-source trees ausgeführt patch < 10xpatch-1.3.20-0 und nach dem die exekutierbaren Dateien wieder exekutierbar gemacht worden sind, wird Apache mit der heiligen Dreifaltigkeit von ./configure make und make install ganz normal installiert. Es sollte beachtet werden, dass --enable-module=so mit an configure übergeben wird, weil ansonsten der Linkvorgang ansonsten misslingen wird. Die mitgelieferten Dokumente enhalten sehr interessante und ausführliche Information wie man individuell konfigurieren kann was gewünscht ist.
Normalerweise arbeitet Apache jeden HTTP Request ab, indem es eine lange Liste von Regeln befolgt, wie zum Beispiel: wie wandele ich ein URI in einen Dateinamen um, authentifizieren des Requests, erstellen der HTTP Header für die Antwort, senden der Antwort und das loggen der Transaktion. Apache erledigt diese Schritt mehr oder weniger für jede Anfrage, selbst wenn die vorherige Anfrage schon die gleichen Schritte ausgelöst hat. Dieses Verhalten ohne Gedächtnis wird für Authentifizierung, etc. benötigt ist jedoch unnötig für dynamisch erstellen Inhalt. Die Patches geben Apache einen Speicher (QSC) und erlauben es diesen Prozess abzukürzen. Ein Aufruf von http://dein.server.name/qsc-status?full gibt genauere Information:
Quick Shortcut Cache (QSC) Status
Wednesday, 11-Oct-2000 15:06:55 PDT
Performance stats
hit ratio 2104749/2112855 (99.62%)
uncachable 42/2112855 (0.00%)
uncachable misses 42/8106 (0.52%)
uncachable requests 0/2112855 (0.00%)
uncachable responses 0/2112855 (0.00%)
Hash table
failed insertions 0
entries 8064
duplicate entries 0
bucket use 7923/32768 (24.18%)
hash effectiveness 7923/8064 (98.25%)
longest chain 2
avg. chain 0.2
avg. nonempty chain 1.0
Chain length histogram:
1 2 3 4 5+
7782 141 0 0 0
Memory use (in bytes)
table + misc 131104
entries 322560
URIs 246024
headers 4128768
total 4844640/5000000 (96.89%)
mapped file data 1146761280
mapped file vaddrs 1229455360 (75040 16384-byte pages)
Das wichtigste sind die Hit Ratios. Hier wurden zu 99.6% die Request direkt vom QSC aus bedient.
Ausführlichere Information findet man auch hierzu in der Dokumentation. Um faire Benchmarks zu liefern, wurde nicht nur das Benchmark Utility ab (siehe [le9]), sonder auch getwww [getwww], das Standardbenchmarkprogramm des c't Magazins benutzt. Der Vorteil von getwww ist, dass einen ganzen Cluster von Rechnern einsetzen kann um einen anderen Server zu erschlagen, sowie vorher eine Verzeichnis-struktur mit Webseiten einer bestimmten Länge erstellen kann, so dass nicht nur Caching-Effekte gemessen werden. Wir verwendeten Zufallswebseiten von 12Kb Länge und bis zu rekursiven 4 Unterverzeichnissen. Jedes Verzeichnis wird mit 0.html, 1.html, etc. gefüllt. ./dirhir.pl page_hir 4 12 Die Kunst des Benchmarking besteht darin die ungewünschten Flaschenhälse zu vermeiden. Die Schwäche von ab ist, dass die verwendete Funktion strstr teuer ist (siehe man strstr), sowie bei getwww muss darauf geachtet werden, dass der interconnet/Netzwerk der verwendeten Benchmarkmaschinen nicht die Sache entsprechend verlangsamt. Schliesslich will man den Webserver benchmarken.

./getwww -R 4 -u /page_hir -r 1000 server c, wobei c=10,25,50,100,200,400
Wir haben also 1000 Sekunden lang Seiten angefordert, zuerst mit 10 Prozessen gleichzeitig, dann mit 25, etc. Das ganze wurde lokal und von anderen Rechnern im Netzwerk ausgeführt. Die Boxplots zeigen die größten Schwankugen bei thttpd, aber er ist auch klarer Gewinn.
Falls der Leser die Tests reproduzieren will oder Fehlermeldungen wie "socket: Too many open files" bekommt sollte er die Anzahl der Dateien erhöhen die man gleichzeit öffnen kann. Bei unserer Konfiguration ist das in /proc/sys/fs/file-max.

/usr/sbin/ab -n 50000 -c 1 http://server/bench.html c wurde wieder von 1 bis 200 variiert. Die Patches beschleunigen Apatche vor allem bei mehr gleichzeitigen Anfragen.

Anzahl der requests/s die nit zunhemender Belastung angearbeitet werden können.
Wir haben ausführlichere Tests gemacht um festzustellen, was langsam ist: die Connection time oder die Processing Time. Dies ist von besonderem Interesse da Apache und thttpd vollkommen verschiedene Modelle verwenden. Apache ist ein pre-forking Server, d.h. Der Parent Prozess kümmert sich nur um das forken von Child prozessen und er kümmert sich nicht um andere Requests oder bedient Network sockets. Der Childprozess erledigt alle Process connections. Er servt ein paar Connection (immer nur eine nach der anderen) bevor er stirbt. Der Vater spawnt neue Kinder oder tötet alte basierend auf dem Load des Servers. Der Vorteil dieses Modelles ist die hohe Robusheit und Portiertbarkeit, war ein Ziel des Apache Projektes war. Der Nachteil dieses Modells ist der Overhead des Forkings der Prozesse, der Overhead des Context switches zwischen den Proyessen und der Speicher overhead der mehreren Prozessen. Zusätlich wird das Cachen von zwischen Requesten fast unmöglich. Sehr gute Information hierzu findet man in diesem Artikel [JAWS].

thttpd hat traumhaft kurze Connection Zeiten. Hier sieht man den Nachteil des preforking Modells von Apache.

Hauptsächlich bei den processing costs gewinnt der gepatche Apache gegenüber Apache.
Ist der Server immer noch zu langsam, muss die Last geteilt werden. Hinter grossen Websiten verstecken sich oft mehrere Computer. Dies kann in Hardware erfolgen, um Beispiel mit Cisco's LocalDirectors oder per Software. mod_backhand [backhand] ist ein Apache Model, dass die Last auf heterogene Web-Cluster verteilen kann. Eine HTTP Request kann transparent von einem Webserver auf einen anderen weitergeleitet werden. Dadurch kann zum Beispiel unausgelastete Resources benutzt werden. Load-balancing findet per request statt. Mod_backhand wird vor allem bei CGI-intensiven Websites zum Einsatz kommen. Ganz einfach ausgedrückt verfügt mod_backhand über Funktionalität wie man es von einem Batch-System kennt: Kommt eine Anfrage an die Maschine B und mod_backhand stellt fest, dass die auf Maschine A verfügbaren Resourcen grösser sind als die Kost B nach A forzuwarden, so wird es B nach A forwarden. Mod_backhand kann alleine oder im Zusammenspiel mit den meisten Loadblancing Tools wie Ciscoäs LocalDirector, Linuxdirector, DNS tricks (round robin von mehrere Ips) benutzt werden, aber der Vorteil von mod_backhand ist, dass es higher level als diese OSI tools ist, da es auf einer per request Basis arbeitet. Alle vorherigen Methoden arbeiten auf dem TCP/IP level und behandeln daher connections und nicht requests. Dies ist von Bedeitung wenn piplined protocols wie HTTP 1.0 oder 1.1 zum Einsatz kommt. Wie die meiten Apache Module ist die Installation schmerzlos und die Website verfügt über sehr gute Informationen. Die Informationsmöglichkeiten sind schier endlos: Will man zum Beispiel alle datenbank CGI-Anfragen auf deine 64 Bit Maschine umleiten. Wir haben die Maschinen intel1, .. intel0, sun1, .. sun10, sowie alpha1, .. alpha10. Selbstverständlich sollen die Maschinen per Zufall ausgewählt werden, so dass nicht alle requests an die gleiche Maschine gehen und aus Sicherheitsgründen sollten wir alle Maschinen ignorieren von denen wir seit 6 Sekunden nichts mehr gehört haben.
Backhand byAge 6
BackhandFromSO libexec/byHostname.so byHostname (sun|alpha)
Backhand byRandom
Backhand byLogWindow
Backhand byLoad
TomCat[tomcat] ein bekannter Servletserver unterstützt auch eigene Worker an die er Request forwarden kann. In workers.properties im conf/ directory kann man Worker und ihre Loadfaktoren definieren [tomcatworkers]. In echt bekommt man nun unter umstenden zwei Levels von load-blancing: 1) Wahl des Webservers, Wahl des Workers.
Es gibt noch zwei andere interessante Projekte zu diesem Thema die man unbedingt erwähnen muss: Eddie[Eddie] und Linux Virtual Server (LVS) [LVS]. LVS ist ein hoch-skalierbarer und hochverfügbarkeits server mit einem LoadBalancing, dass einen ganzen Cluster von Linuxmaschinen abdeckt und nach aussen hin transparent als ein einziger Server erscheint. Eddie ist ein hochverfügbarkeits Clustering Tool. Eddie ist ein weitentwickeltes Traffic-Management Szsten, dass auch geographisch verteile Servers managen kann. Auf jeder Site ist ein Front End Server, der den Traffic an die BackEnd Server verteilt, die er selbstverständlich beobachtet. Eddie besteht aus den "enhanced DNS Server", der load-Balancing von geographisch verteilten Servern erlaubt, sowie dass "intelligent HTTP Gateway", welches load-balancing, skalierbarkeit und hochverfügbarket biete. Letzendlich hängt es von den genauen Anforderungen ab für welches System man sich entscheidet.
Ausser entsprechend viel Bandwidth kaufen hat man realitv wenig Einfluss auf die Reisezeit der Daten bis zum Kunden. Es gibt Gerüchte, dass ein paar Steinzeit Menschen immer noch mit Modems surfen. Die teuere Lösung ist viel Geld an Akamai [akamai] zu zahlen und von deren Expertise Ips auf geographische Orte zu mappen und den Request dann von dort beantworten. Surft man zum Beispiel auf CNN.com und kommt aus Deutschland, so werden die Bilder von Europa aus von Akamai geliefert, was zu erheblich schenelleren Antwortszeiten führt. Prinzipiell kann man aber zumindest registrieren Kunden vielleicht eine einfachere Version mit lokalen Mirros anbieten, da man hier weiss wo sie wohnen.
Die zweite interessante Variante ist die Daten die letzlich den Server verlassen zu komprimieren. Mod_gzip[mod_gzip] bietet das an und ist auch noch klug genug, die gleichen Seiten nur einmal zu komprimieren, falls der empfangende Browser dies unterstützt. In der Praxis sind dass mehr als 98%. Bei einem Einsatz für eine grosse Tageszeitung haben wir die totale Datenmenge im Durchschnitt auf die Hälfte verkleinern können. Die Installation ist auch ziemlich unproblematisch: entweder schon die kompilierte Version herunterladen, oder selber kompilieren und in das lib Verzeichnis von Apache kopieren. Folgende Zeilen müseen zu httpd.conf hinzugefügt:
LoadModule gzip_module libexec/mod_gzip.so
AddModule mod_gzip.c
# [ mod_gzip sample configuration ] # mod_gzip_on [Yes/No]
#
# Use this command to turn mod_gzip 'on' or 'off'.
# The command can go into the base server configuration
# or be used to control if mod_gzip is active inside
# any particular virtual directory or host section.
#
mod_gzip_on Yes
# mod_gzip_item_exclude type regular_expression
#
# Use 'include' and 'exclude' commands to specify which
# items are eligible for compression.
#
# The valid values for 'type' field are...
#
# file, mime, handler, reqheader, rspheader.
#
# The 3rd parameter must be a valid 'regular expression'
# which will be used to 'match' the requested item(s).
#
mod_gzip_item_include file \.htm$
mod_gzip_item_include file \.html$
mod_gzip_item_include mime text/.*
# NOTE: The following entry was required to compress negotiated
# home pages in version 1.3.17.1a but is now only needed
# if you would like to compress your directory listings...
#
# mod_gzip_item_include mime httpd/unix-directory # mod_gzip_dechunk [Yes/No]
#
# If a response is being generated dynamically and
# the response content generator is always using
# 'Transfer-Encoding: chunked' then that response
# cannot normally be 'compressed' since a transport layer
# encoding is already being applied. The "mod_gzip_dechunk Yes"
# option will transparently remove all 'chunked' encoding
# and allow the response to be fully compressed. Certain
# versions of mod_php will need this option set ON for the
# dynamic output to be compressed. Whenever possible just
# make sure this option and the extra step required
# are NOT needed by making sure the response generator is NOT
# using 'Transfer-encoding: chunked'.
#
mod_gzip_dechunk yes
# mod_gzip_min_http [1000/1001/etc...]
#
# Only use this to 'block' browsers that don't support a
# certain minimum level of the HTTP protocol. The option
# uses the same internal 'numeric' value(s) used by Apache
# itself to indicate certain HTTP protocol support level(s).
#
# 1000=HTTP/1.0 1001=HTTP/1.1, etc.
#
# mod_gzip_min_http 1000 #
mod_gzip_temp_dir /tmp
#
# Use this option to specify the directory that mod_gzip should
# use for workfiles. Do not add a trailing 'slash' to the name.
#
# Whenever possible ( and for the best performance ) this 'temporary'
# workfile directory should be a valid RAMDISK.
#
# The directory must already exist when Apache starts.
#
# Be sure permissions are set right for whatever directory is
# used as the 'temp_dir'. The User/Group used by the Server during
# runtime ( such as 'www' or 'nobody' ) must have read/write
# access to the directory. If permissions are incorrect then the
# mod_gzip 'result' string will probably be 'RECOVERY' and your
# Apache error_log will contain messages about mod_gzip being
# unable to access work files.
#
# If no 'mod_gzip_temp_dir' is specified then the DEFAULTS are...
#
# /tmp for UNIX
# c:\temp for Win32.
#
mod_gzip_temp_dir /tmp
# mod_gzip_keep_workfiles [Yes/No]
#
# If this option is 'Yes' then mod_gzip will not delete any
# workfiles it may be generating in the 'mod_gzip_temp_dir'
# location. Use this option only for diagnostic purposes.
# The 'default' setting is 'No'.
#
mod_gzip_keep_workfiles Yes
# [End of mod_gzip sample config]
#if gzipped version of html exists, serve out the gzipped version.
#In other words... if the user requests 'filename.html'
#and there happens to already be a pre-compressed
#version of that page named 'filename.html.gz' then
#mod_gzip will immediately return the pre-compressed
#version rather than perform a dynamic compression
#of the file.
mod_gzip_can_negotiate Yes
mod_gzip_command_version mod_gzip_show_version
Wenn man bei der der kryptischen Zeile mod_gzip_command_version mehr Fantasie hat, kann man mod_gzip besser gegen Hacker schützen.
Falls der Load immer noch zu groß ist einfach das Netzwerkkabel vom Server herausziehen .. und der Load wird fast sofort auf Null zurückgehen.
[le9] Webserver Tux 2.x rast davon, S. 61-67,Linux Enterprise, 9/2001
[apa] Apache, http://thttpd.apache.org
[thttpd] thttpd: tiny/turbo/throttling HTTP server, http://www.acme.com/software/thttpd/thttpd.html
[tuning] Apache Performance Notes, http://httpd.apache.org/docs/misc/perf-tuning.html
[netcraft] Netcraft Web Server Survey, http://www.netcraft.com/survey/
[oss.sgi]Accelerating Apache, http://oss.sgi.com/projects/apache/
[specweb96] http://www.spec.org/osg/web96/
[getwww] getwww, http://www.heise.de/ct/ftp/
[JAWS] JAWS: : Understanding High Performance Web Systems, http://www.cs.wustl.edu/~jxh/research/research.html
[BACKHAND] Apache Load-Balancing, mod_backhand
[tomcatworkers] Tomcat workers.properties, http://jakarta.apache.org/tomcat/tomcat-3.2-doc/Tomcat-Workers-HowTo.html
[LVS] Linux Virtual Server, http://www.linuxvirtualserver.org/
[EDDIE] Eddie white-paper, http://eddie.sourceforge.net/whtpap.html
[akamai] www.akamai.com
[mod_gzip] Mod_gzip, http://www.remotecommunications.com/apache/mod_gzip/
[tomcat] http://jakarta.apache.org/tomcat/
Ruby home
Linux Enterprise
Approximity: Articles/slides/tutorials.
Ruby slides.
Back to Approximity.