Das rasante Wachstum des Internets verlangt Webservern immer mehr ab. Kann Apaches altgedienter HTTP-Server hier noch mithalten? Er kann – wenn der Admin den Bogen raus hat.
Apaches HTTP-Server bleibt der meistgenutzte Webserver im Internet [1], auch wenn die erste Version bereits vor zwei Jahrzehnten erschien – im April 1995. Das liegt auch daran, dass ihn das Projekt ständig weiterentwickelt. Er punktet im Wettbewerb zudem durch seinen modularen Aufbau und die damit einhergehende große Funktionsvielfalt.
Doch die Konkurrenz schläft nicht, und so sind seit ein paar Jahren alternative Webserver auf dem Vormarsch, allen voran Nginx. Das entging auch der Apache Software Foundation nicht, weshalb sie sich für Version 2.4 das Ziel setzte, in puncto Performance wieder den Anschluss an Nginx zu finden.
Ob das gelungen ist, darüber streiten die Fachleute. Fakt ist, dass die neue Version die alte in Sachen Performance überflügelt. Das belegt unter anderem ein Vergleich der Webserver-Versionen von Debian Wheezy (2.2.22) und Debian Jessie (2.4.10). Wie Abbildung 1 zeigt, arbeitet der Server in Version 2.4 eine Million Zugriffe etwa 20 Sekunden schneller ab als die Vorgängerversion 2.2.
Unter Jessie haben die Tester dazu anstelle des Multi Processing Module Event (MPM) das MPM Worker aktiviert, um das gleiche Modul zu verwenden. Getestet haben sie den direkten Zugriff auf »localhost« in einer Virtualbox-VM mit 512 MByte RAM. Beim Vergleich kam Apaches Benchmarktool »ab« [2] zum Einsatz, das jeweils auf eine Textdatei mit dem Inhalt »hello world« zugriff.
Wie performant der Server eine Webseite ausliefert, hängt allerdings noch von anderen Faktoren ab. So verwenden die Webapplikationen meist Skriptsprachen wie PHP und Perl, hinzu kommen Datenbankabfragen (etwa über MySQL). Ein Admin sollte im Hinterkopf behalten, dass auch sie nicht selten die Performance ausbremsen.
Wer den Apachen tunen möchte, sollte jedoch ein paar Dinge beachten. Um sich beispielsweise auf einem Produktivsystem beim Experimentieren nicht die bestehende Konfiguration zu zerschießen, versioniert der Admin diese am besten mit »etckeeper« [3]. Außerdem testet er neue Konfigurationen noch vor einem Neustart oder Reload des Dienstes besser über »apache2ctl -t« auf syntaktische Korrektheit.
RAM, RAM, nochmals RAM
Jeder HTTP-Prozess auf dem Webserver benötigt einige MByte RAM. Daher ist es für viele Zugriffe essenziell, dass ausreichend Arbeitsspeicher verfügbar ist. Reicht der nicht aus, beginnt der Server zu swappen, er lagert den Arbeitsspeicher auf die Festplatte aus. Weil der Datendurchsatz von Festplatten selbst in Zeiten von SSDs noch immer um ein Vielfaches langsamer ist als der des RAM, sollte der Admin das nach Kräften verhindern.
Unter Linux bedeutet mehr RAM zugleich, dass der Kernel einen größeren Pagecache halten kann, was I/O-Abfragen massiv beschleunigt. Auch dies sollte der Admin bei der RAM-Dimensionierung berücksichtigen. Des Weiteren muss er die Apache-Konfiguration auf den verfügbaren Arbeitsspeicher abstimmen. Erlaubt er zu viele Prozesse, ist der verfügbare Speicher schnell aufgebraucht. Für das MPM Prefork bietet sich die Formel aus Abbildung 2 an.
Die einzelnen Werte kann der Admin zum Beispiel über »top« ermitteln (Abbildung 3). Indem er [Shift]+[M] drückt, zeigt »top« die Prozesse sortiert nach Speicherbedarf an. In der Spalte »RES« erscheint der tatsächliche Arbeitsspeicherbedarf der Prozesse.
Im Beispielsetup standen insgesamt 16 GByte RAM zur Verfügung. MySQL benötigte 39 MByte, der größte Apache-HTTP-Prozess gerade mal 22 MByte. Den Nameserver Bind kann der Admin vernachlässigen, er beansprucht nicht einmal 1 MByte RAM.
Zieht der Administrator hier also die in der Abbildung 2 vorgestellte Formel heran und für das Betriebssystem 100 MByte sowie für MySQL noch mal 50 MByte ab und sieht zugleich für den Pagecache 2 GByte vor, kommt er am Ende auf einen Wert von 644 für »MaxRequestWorkers« . Diese Variable legt fest, wie viele Anfragen der Server im Ernstfall zeitgleich abarbeiten kann.
Um dem Server im Ernstfall etwas Luft zu verschaffen, wäre im konkreten Fall ein Maximum von 400 Zugriffen eine gute Wahl. Alternativ kann der Serverbetreiber auch kleine Helfer einsetzen, welche die Kalkulation übernehmen (siehe Kasten “Apachebuddy.pl”).
Apachebuddy.pl
Das Perl-Skript »apachebuddy.pl« gibt automatisiert Tipps, die einem Admin dabei helfen, den Apachen in Bezug auf den Arbeitsspeicher zu konfigurieren. Listing 1 zeigt einen Auszug von einem Webserver, der noch unter Debian Squeeze LTS läuft.
Listing 1
apachebuddy.pl
01 root@testserver:~# wget apachebuddy.pl -O apachebuddy.pl 02 root@testserver:~# perl apachebuddy.pl 03 ###################################################################### 04 05 # Apache Buddy v 0.3 ################################################# 06 07 ###################################################################### 08 09 Gathering information... 10 We are checking the service running on port 80 11 The process listening on port 80 is /usr/sbin/apache2 12 The process running on port 80 is Apache/2.2.16 (Debian) 13 Apache has been running 7d 01h 39m 11s 14 The full path to the Apache config file is: /etc/apache2/apache2.conf 15 Apache is using prefork model 16 17 Examining your Apache configuration... 18 Apache runs as apache 19 Your max clients setting is 150 20 21 Analyzing memory use... 22 Your server has 16024 MB of memory 23 The largest apache process is using 30.59 MB of memory 24 The smallest apache process is using 15.01 MB of memory 25 The average apache process is using 20.53 MB of memory 26 Going by the average Apache process, Apache can potentially use 3079.51 MB RAM (19.22 % of available RAM) 27 Going by the largest Apache process, Apache can potentially use 4588.51 MB RAM (28.64 % of available RAM) 28 29 Generating reports... 30 ### GENERAL REPORT ### 31 32 Settings considered for this report: 33 34 Your server's physical RAM: 16024MB 35 Apache's MaxClients directive: 150 36 Apache MPM Model: prefork 37 Largest Apache process (by memory): 30.59MB 38 [ OK ] Your MaxClients setting is within an acceptable range. 39 Max potential memory usage: 4588.5 MB 40 41 Percentage of RAM allocated to Apache 28.64 % 42 43 ----------------------------------------------------------------------- 44
Multiprocessing-Module
Apache HTTP unterstützt in Version 2.4 unter Linux drei verschiedene Multiprocessing-Module (MPM):
- Prefork
- Worker
- Event
Seit Version 2.4 kann der Server MPMs zudem zur Laufzeit laden.
Das MPM Prefork (Modulname: »mod_mpm_prefork.so« ) kommt ohne Threads aus. Für jeden Zugriff existiert ein eigener Prozess im System. Beim Einsatz von PHP als Apache-Modul ist dies im Normalfall die einzige Option für den Betrieb, denn in PHP gibt es zu viele Bibliotheken von Drittanbietern, die noch nicht Thread-safe sind [4].
Wer ein Threaded MPM zusammen mit PHP verwenden möchte, kann dies mit Fast CGI und PHP-FPM realisieren. Ob sich der Umstieg lohnt, ist aus Performancesicht jedoch fraglich. Die Vorteile durch das Threaded MPM verlieren sich aufgrund der Performance-Nachteile, die eine PHP-Integration über Fast CGI nach sich zieht, teilweise wieder [5].
Die folgenden Optionen sind beim MPM Prefork relevant:
- »StartServers«
- »MinSpareServers« , »MaxSpareServers«
- »MaxRequestWorkers«
- »ServerLimit«
- »MaxConnectionsPerChild«
»StartServers« legt fest, wie viele Prozesse der Webserver nach einem Neustart vorweg starten soll. »MinSpareServer« und »MaxSpareServers« bestimmen, wie viele unbenutzte Prozesse Apache mindestens vorhalten soll beziehungsweise maximal vorhalten darf. »MaxRequestWorkers« (bis 2.3.13 »MaxClients« ) limitiert die maximale Prozessanzahl und somit die Anzahl der gleichzeitigen Zugriffe. Beachtenswert ist auch die Direktive »ServerLimit« , die eine Obergrenze für »MaxRequestWorkers« festlegt, der Standardwert liegt bei »256« .
Wer für »MaxRequestWorkers« einen größeren Wert erwartet, muss die Direktive »ServerLimit« parallel dazu erhöhen. »MaxConnectionsPerChild« legt fest, wie viele Verbindungen ein einzelner Prozess abarbeiten darf. In einer perfekten Welt ist der Wert 0, was bedeutet, dass der Server Prozesse für alle folgende Requests nie neu startet. Bei umfangreichen Applikationen kann es jedoch sinnvoll sein, Prozesse nach ein paar Hundert Verbindungen wieder zu erneuern. Das gibt den vom Prozess verwendeten RAM-Bereich wieder frei, was Memory Leaks vorbeugt. Reichen die konfigurierten »MaxRequestWorkers« nicht aus, erscheint im Logfile die Meldung aus Listing 2.
Listing 2
Logfile-Meldung
01 [Fri Jun 05 13:15:24.760818 2015] [mpm_prefork:error] [pid 1649] AH00161: server reached MaxRequestWorkers setting, consider raising the MaxRequestWorkers setting
Ohne PHP-Modul kann der Admin ein Threaded MPM ohne Bedenken einsetzen. Dadurch arbeitet der Server einen Zugriff durch einen einzelnen Thread ab statt durch einen einzelnen Prozess. Da ein Thread weniger Overhead erzeugt als ein Prozess, erreicht der Server so eine bessere Performance.
Unter Apache stehen zwei Threaded MPMs bereit. Mit Version 2.0 haben die Entwickler MPM Worker (Modulname: »mod_mpm_worker.so« ) eingeführt, seit Version 2.2 gibt es ein zusätzliches Threaded MPM namens Event (Modulname: »mod_mpm_event.so« ), das seit Apache 2.4 als stabil gilt.
Die wichtigsten Optionen für MPM Worker und Event sind identisch:
- »ThreadsPerChild«
- »MinSpareThreads« , »MaxSpareThreads«
- »MaxRequestWorkers«
- »ServerLimit«
»ThreadsPerChild« legt fest, wie viele Threads ein einzelner Prozess erstellen darf. »MinSpareThreads« und »MaxSpareThreads« funktionieren analog zu den oben erwähnten Direktiven »MinSpareServers« und »MaxSpareServers« .
»MaxRequestWorkers« limitiert die gesamte Anzahl an Threads. Der Standardwert von »ServerLimit« liegt im Falle von Threaded MPMs bei 16. Multipliziert der Admin »ThreadsPerChild« (Standard: 25) mit »ServerLimit« (Standard: 16), erhält er das obere Limit für die Anzahl an Threads. Die Default-Einstellung erlaubt somit einen Wert von maximal 400 Threads für »MaxRequestWorkers« .
Module entschlacken
Apache HTTP liefert etwa 120 Module mit und integriert auf Wunsch noch viele weitere von Drittanbietern [6]. Die Serverbetreiber sollten stets im Hinterkopf behalten, dass zusätzliche Module meist auch mehr RAM benötigen. Es ergibt sowohl aus Performance- als auch aus Sicherheitssicht Sinn, aktivierte Module zu prüfen (Listing 3) und nicht benötigte zu deaktivieren.
Listing 3
Geladene Module auflisten
01 root@debian:~# apache2ctl -M 02 Loaded Modules: 03 core_module (static) 04 so_module (static) 05 watchdog_module (static) 06 http_module (static) 07 log_config_module (static) 08 logio_module (static) 09 version_module (static) 10 unixd_module (static) 11 access_compat_module (shared) 12 alias_module (shared) 13 auth_basic_module (shared) 14 authn_core_module (shared) 15 authn_file_module (shared) 16 authz_core_module (shared) 17 authz_host_module (shared) 18 authz_user_module (shared) 19 autoindex_module (shared) 20 deflate_module (shared) 21 dir_module (shared) 22 env_module (shared) 23 filter_module (shared) 24 mime_module (shared) 25 mpm_prefork_module (shared) 26 negotiation_module (shared) 27 php5_module (shared) 28 setenvif_module (shared)
Debianer und Ubuntu-User aktivieren und deaktivieren Module ganz einfach über die Kommandos »a2enmod« beziehungsweise »a2dismod« . In der Standardkonfiguration ist Apache 2.4 aber bereits ausreichend aufgeräumt. Es hilft zudem, dass »a2dismod« warnt (Listing 4), falls der Admin ein essenzielles Modul abschalten möchte. Unter Centos und RHEL verwaltet er die Module in der Regel über die Datei »/etc/httpd/conf.d/« .
Listing 4
Modulwarnung
01 root@debian:~# a2dismod mime 02 WARNING: The following essential module will be disabled. 03 This might result in unexpected behavior and should NOT be done 04 unless you know exactly what you are doing! 05 mime 06 07 To continue type in the phrase 'Yes, do as I say!' or retry by passing '-f':
DNS-Lookups und Keepalive
Die Direktive »HostnameLookups« sollte ein Admin unbedingt auf »No« stellen, was Apache seit Version 1.3 ohnehin standardmäßig tut. Ist sie aktiviert, startet Apache für jede Webserververbindung einen zusätzlichen DNS Reverse Lookup, was ihn unnötig ausbremst. Alternativ übernehmen eine eigene Log-Analysesoftware oder das Apache-Tool »logresolve« die DNS-Auflösung.
Ähnlich verhält es sich auch mit der Direktive »Allow/Deny from example.org« beziehungsweise der seit Version 2.4 empfohlenen Syntax »Require host example.org« . Auch sie führt zu unnötigen DNS-Lookups, weshalb Apache-Betreiber besser eine IP-Adresse verwenden: »Allow/Deny from 192.0.2.0« und »Require ip 192.0.2.100« .
Wer nicht auf die Hostname-Lookups verzichten möchte, kann diese Möglichkeit auch explizit für bestimmte Dateien oder Verzeichnisse aktivieren:
HostnameLookups off <Files ~ "\.(cgi)$"> HostnameLookups on </Files>
Die Direktive »KeepAlive« aktiviert Keepalive-Verbindungen per Default. Dadurch verarbeitet eine einzige TCP-Verbindung mehrere Anfragen. Ein Problem dabei ist, dass ein zu hoher Wert für »KeepAliveTimeout« zu viele wartende Prozesse oder Threads generiert.
Unnötigen Verwaltungs-IO vermeiden
Häufig verwenden Admins ».htaccess« -Dateien, die den Apache-Server direkt aus dem »DocumentRoot« heraus steuern und sich zum Beispiel um IP-Limitierungen, Passwortabfragen oder Rewrites kümmern. Hierbei kommt die Direktive »AllowOverride« zum Zuge. Der Nachteil: Bei jedem Zugriff prüft der Webserver, ob eine ».htaccess« -Datei im jeweiligen Verzeichnis liegt, die er verarbeiten muss. Der Admin sollte die Direktive »AllowOverride« daher global so weit wie möglich auf »None« setzen und sie nur explizit für jene Verzeichnisse erlauben, wo er sie einsetzt.
Prinzipiell kann er jede Konfiguration einer ».htaccess« -Datei auch direkt in der Apache-Konfiguration vornehmen, doch hat er im Shared-Hosting-Umfeld oft keinen direkten Zugriff auf die Config-Dateien, obwohl die Webapplikationen bestimmte Apache-Features benötigen.
Ähnlich verhält es sich auch mit der Option »SymLinksIfOwnerMatch« der »Options« -Direktive. Aus Sicherheitsgründen ergibt es im Shared Hosting Sinn, wenn sie aktiviert ist. Aus Performancesicht weniger, weil der Server bei Zugriffen zusätzlich den Besitzer von Symlinks prüfen muss.
Wer alles aus seinem Webserver herausholen möchte, der verwendet die Direktive »DirectoryIndex« besser ohne Wildcard (»index« ). Ebenso sollte er die Option »MultiViews« deaktivieren und stattdessen Type-Maps verwenden. Nicht zuletzt empfiehlt es sich, den Sendfile-Support auf »EnableSendfile On« zu stellen, wobei sich hieraus unter Umständen Probleme mit Netzwerkmounts ergeben.
Browser-Caching
Das Modul »mod_expires« kann Browser anweisen, bestimmte statische Inhalte für längere Zeit zu cachen. Dies reduziert die Anzahl der Anfragen an den Apache-Webserver. Das Modul aktiviert der Admin unter Debian und Ubuntu über:
a2enmod expires
Danach legt er fest, für welche Dateitypen er das wünscht (Listing 5).
Listing 5
Verfallsdaten für Dateitypen
01 ExpiresActive on 02 ExpiresByType image/gif "access plus 1 months" 03 ExpiresByType image/jpeg "access plus 1 months" 04 ExpiresByType image/png "access plus 1 months 05 ExpiresByType application/x-font-woff "access plus 1 months" 06 ExpiresByType application/javascript "access plus 1 months" 07 ExpiresByType text/css "access plus 1 months"
Ebenfalls relevant ist es, Inhalte komprimiert auszuliefern. Das übernimmt das Modul »mod_deflate« . Unter Debian existiert auch schon eine Standardkonfiguration für dieses Modul (Listing 6). Seit Apache 2.4 komprimiert »mod_deflate« Dateien nur dann, wenn der Overhead aufgrund der Kompression kleiner ist als die zu komprimierenden Daten.
Listing 6
Standardkonfiguration für mod_deflate
01 AddOutputFilterByType DEFLATE text/html text/plain text/xml 02 AddOutputFilterByType DEFLATE text/css 03 AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript 04 AddOutputFilterByType DEFLATE application/rss+xml 05 AddOutputFilterByType DEFLATE application/xml
Ganz kleine Dateien tastet er also mitunter nicht an. Listing 7 zeigt, wie der Admin anhand des Serverheaders die Verfallsdaten und Kompression überprüft.
Listing 7
Serverheader-Check
01 root@debian:~# wget --server-response --header="accept-encoding: gzip" http://localhost/test.css 02 --2015-06-07 06:06:57-- http://localhost/test.css 03 Resolving localhost (localhost)... ::1, 127.0.0.1 04 Connecting to localhost (localhost)|::1|:80... connected. 05 HTTP request sent, awaiting response... 06 HTTP/1.1 200 OK 07 Date: Sun, 07 Jun 2015 04:06:57 GMT 08 Server: Apache/2.4.10 (Debian) 09 Last-Modified: Fri, 05 Jun 2015 13:02:45 GMT 10 ETag: "aa0-517c4e8861a8a-gzip" 11 Accept-Ranges: bytes 12 Vary: Accept-Encoding 13 Content-Encoding: gzip 14 Cache-Control: max-age=2592000 15 Expires: Tue, 07 Jul 2015 04:06:57 GMT 16 Content-Length: 102 17 Keep-Alive: timeout=5, max=100 18 Connection: Keep-Alive 19 Content-Type: text/css 20 Length: 102 [text/css] 21 Saving to: 'test.css'
Statischen und dynamischen Content trennen
Benötigen einzelne Apache-Prozesse viel RAM (etwa wegen einer umfangreichen PHP-Applikation), kann es vorteilhaft sein, dass nicht gerade diese überbeschäftigten Prozesse die statischen Inhalte ausliefern. Den Job sollte vielmehr ein zusätzlicher Apache-Server mit möglichst schlanker Konfiguration und minimalem Speicher-Footprint übernehmen. Diesen macht der Admin dann zum Frontend-Server, der PHP-Anfragen an den zusätzlichen Apache-Webserver via »mod_proxy« weiterleitet. Alternativ verwendet er eigene (Sub-)Domains für statische Inhalte wie etwa »static.linux-magazin.de« , oder, wie bei Youtube, gleich eine eigene Domain (»i.ytimg.com« ).
Monitoring
Das Modul »mod_status« erlaubt Interessierten, Aktivität und Performance des Apache-Servers abzufragen. Per Default ist das Modul inaktiv. Der Admin schaltet es unter Debian oder Ubuntu einfach über
a2enmod status
ein. Die URL für den Zugriff lautet normalerweise »/server-status« . Den Zugriff darauf muss der Admin meist noch explizit erlauben:
<Location /server-status>
SetHandler server-status
Require ip 192.0.2.0/24
</Location>
Startet er anschließend noch den Webserver neu, sollte der Zugriff auf die Statusseite funktionieren – jedoch hoffentlich nur aus dem LAN heraus (siehe Kasten “Zu gut erreichbar”)
Zu gut erreichbar
Die Server-Statusseite des offiziellen Apache-Webservers (Abbildung 4) ist öffentlich zugänglich. Ist der eigene Server über das Internet erreichbar, ist eine Veröffentlichung also nicht zu empfehlen.
Die Statusseite kommt bei der manuellen Analyse zum Einsatz, um zum Beispiel spezielle Lastspitzen zu messen. Daneben bildet diese Seite die Grundlage für automatisiertes Monitoring, das etwa über ein Nagios- oder Icinga-Plugin ([7], [8]) oder über das Percona Apache Monitoring Template für Cacti (Abbildung 5, [9]) erfolgen kann. Damit überwacht der Admin den Apache-Webserver systematisch und wertet die Daten aus.
Logischerweise verursacht »mod_status« einen gewissen Overhead. Wer jedoch sein System sinnvoll überwachen möchte, sollte die zwei zusätzlichen Systemcalls pro Zugriff in Kauf nehmen.
Benchmarks
Um die Tuning-Maßnahmen auf ihre Sinnhaftigkeit zu überprüfen, sollte der Admin konkrete Zahlen zum Webserver ermitteln. Der bringt dafür sein eigenes Benchmarktool namens »ab« mit, das direkt über HTTP/HTTPS arbeitet und sich für beliebige Webserver einsetzen lässt. Der Tester konfigurierte die Anzahl der Requests (»-n Requests« ) und die Anzahl gleichzeitiger Zugriffe (»-c Concurrency« ). Abbildung 1 zu Beginn des Artikels zeigt einen Aufruf.
Ein komplexeres Benchmarktool, das auch von der Apache Software Foundation stammt, ist das Java-basierte Jmeter (siehe Artikel im Schwerpunkt), weitere Tools heißen »curl-loader« und »httperf« . Vorsicht ist bei produktiven Systemen geboten, um sie nicht ungewollt selbst mit einem Denial-of-Service auszuknocken. Betreiber einer PHP-Applikation sollten sich einen PHP-Profiler anschauen, zum Beispiel Xhprof [10]. Erst dadurch lässt sich erkennen, wie viele Ressourcen PHP und die zugehörigen Datenbankabfragen benötigen.
Resümee
Bevor der Admin seinen Apachen gegen einen anderen Webserver eintauscht, sollte er zunächst nach Bottlenecks in den Webapplikationen schauen. Häufig bremst nicht der HTTP-Server selbst, sondern eine umfangreiche PHP-Anwendung, die zu viele Datenbankabfragen generiert. Erst danach sollte sich der Blick auf die Performance des Webservers selbst richten. Die lässt sich über zahlreiche Direktiven an verschiedenen Ecken optimieren. Versehen mit ausreichend RAM genügt Apaches Server dann auch noch den heutigen Performance-Ansprüchen des Admin.
Infos
- Netcraft Webserver Survey May 2015: http://news.netcraft.com/archives/2015/05/19/may-2015-web-server-survey.html
- Apaches Benchmarktool »ab« : http://httpd.apache.org/docs/2.4/programs/ab.html
- Versionierung von »/etc/« mit »etckeeper« : https://www.thomas-krenn.com/de/wiki/Etc-Verzeichnis_mit_etckeeper_versionieren
- PHP-FAQ zu Threaded MPM: http://php.net/manual/en/faq.installation.php#faq.installation.apache2
- Apache versus Nginx: http://www.eschrade.com/page/why-is-fastcgi-w-nginx-so-much-faster-than-apache-w-mod_php/
- Apaches Drittanbieter-Module: https://modules.apache.org
- Nagios-Plugins für den HTTP-Server: https://exchange.nagios.org/directory/Plugins/Web-Servers/Apache
- Icinga und der Apache-Webserver: https://exchange.icinga.org
- Percona Apache Monitoring Template für Cacti: https://www.percona.com/doc/percona-monitoring-plugins/1.1/cacti/apache-templates.html
- Xhprof: http://xhprof.io










