Apache2 Konfiguration für Leistungsoptimierung und maximale Auslastung

How-To für Einstellung einer guten prefork/worker Konfiguration

Ein Webserver wie der weitverbreitete Apache ist in der Regel öffentlich erreichbar und für jeden zugänglich. Das bringt einige Probleme mit sich, denn neben der nicht vorhersehbaren Anzahl der Zugriffe treiben böse Hacker ihr Unwesen und versuchen beispielsweise mit verteilten DOS-Attacken den Betrieb des Webservers zu beeinträchtigen bzw. ganz zu blockieren.

Die Aufgabe des Administrators ist es, eine geeignete Konfiguration für eine maximale Leistungsfähigkeit des Webservers zu finden. Vereinfacht gesagt: ab wie vielen gleichzeitigen Anfragen bzw. Apache-Prozessen ist der Webserver überlastet, so dass das System und andere Dienste nicht mehr agieren können? Oder: ab wie vielen Abfragen soll der Apache-Webserver keine weiteren Aufträge mehr annehmen, bis die anstehenden Aufträge abgearbeitet sind? Ziel ist, die Leistungsgrenzen (Prozessorleistung, Arbeitsspeicher, Festplattengeschwindigkeit) des Webservers auszuloten, um Überlastungen und demzufolge Ausfälle zu verhindern.

Doch diese Aufgabe ist gar nicht so einfach, da der Apache von Hause aus kein Systemmonitoring-Tool mit sich bringt und man die Auslastung mithilfe von Linux-Tools analysiert.

In dieser Anleitung werden für den Apache 2 Webserver folgende Punkte erläutert:

  • Auswertung der Logstatistiken: Welche Rückschlüsse kann ich aus der Anzahl der Zugriffe für die Dimensionierung der Hardware ziehen?
  • Optimale Apache Konfiguration: Wie finde ich die optimalen Einstellungen für eine möglichst gute Leistungsfähigkeit?
  • Berechnung der Arbeitsspeicher-Dimensionierung: Wie viel RAM benötigt der Webserver für eine bestimmte Anzahl von Zugriffen?
  • Schutz vor Überlastung: Wie beschränke ich den Apache-Webserver vor zu vielen gleichzeitigen Zugriffen und der daraus folgenden Überlastung?
  • Systemüberwachung des Apache-Webservers: Welche Leistungswerte sind für den Apache-Webserver von Bedeutung und wie überwache ich diese Leistungswerte? Welche Rückschlüsse kann ich daraus ziehen?

Grundlagen der Apache-Webserver-Konfiguration

Server-Ausstattung, Auslastung (Quelle Awstats)

Ein erster Anhaltspunkt ist die Auswertung der Logdateien. Anhand der Berechnung von Durchschnittswerten bekommt man ein Gefühl dafür, ob der Webserver für die aufkommenden Aufgaben grundlegend leistungsstark genug ist.

Hier ein Beispiel eines Webservers:

  • Hardware: Intel Pentium D945 3,4 GHz (DualCore), 2 GB RAM
  • Besucher pro Monat: 214.000
  • Seitenaufrufe pro Monat: 700.000
  • Zugriffe pro Monat: 1.800.000

Besucher und Seitenaufrufe sind zweitrangig. Wichtiger sind die Anzahl der Zugriffe, sprich sämtliche Anfragen (Bilder, HTML, CSS-, JavaScript-Dateien usw.), welcher der Apache beantworten muss. Letztendlich erzeugt der Aufruf einer HTML-Seite viele einzelne Aufrufe.

In diesem Beispiel erfolgen im Durchschnitt ca. 0,3 Seitenaufrufe und 0,7 Zugriffe pro Sekunde:

Zugriffe: 1.800.000 / 30 Tage / 24 Stunden / 60 Minuten / 60 Sekunden = 0,7 Zugriffe pro Sekunde
Seitenaufrufe: 700.000 / 30 Tage / 24 Stunden / 60 Minuten / 60 Sekunden = 0,3 Zugriffe pro Sekunde

Der Webserver ist auf den ersten Blick überdimensioniert, aber die Durchschnittswerte sagen nichts über die Spitzenauslastung aus. So schlummern in der Regel Webserver während der Nacht vor sich hin, während tagsüber die Zugriffe überproportional ansteigen. Die Spitzenlast wurde in dieser Rechnung komplett ausgeblendet.

Apache2: Prefork oder Worker

Die Begriffe Prefork und Worker sind einem Apache-Administrator sicherlich bekannt. Hierbei handelt es sich um so genannte Multi-Processing-Module (MPMs), welche für die Abarbeitung der Client-Anfragen und somit für die Leistungsfähigkeit des Apache-Webservers zuständig sind. Der wesentliche Grund für die MPMs war, den Apache-Webserver für die unterschiedlichen Betriebssysteme und Anforderungen optimieren zu können. So wurde beispielsweise mit Einführung von Apache 2 ein MPM für Windows implementiert, um den Apache auf Windows-Plattformen leistungsfähiger zu machen.

Die Konfiguration des MPM ist im weiteren Verlauf der zentrale Teil einer optimalen Apache-Konfiguration. Die genaue Erklärung der einzelnen MPMs würde den Rahmen dieses Artikels sprengen. Wichtig zu wissen ist:

  • Prefork und Worker sind unter Linux die meist verwendeten MPMs
  • Beide verwenden unterschiedliche Konfigurationsabschnitte: mpm_prefork_module und mpm_worker_module
  • Prefork ist prozess-orientiert: jede Client-Anfrage wird von einem Apache-Prozess bearbeitet
  • Worker ist thread-orientiert: es existieren wenige Mutter-Prozesse, welche viele Threads starten können
  • Prefork ist älter und stabiler
  • Worker ist leistungsfähiger

Dieser Artikel baut auf Verwendung des Prefork-MPM auf. Um herauszufinden, welcher MPM in der jeweiligen Apache-Installation verwendet wird, hilft folgender Befehl:

# apache2 -l
Compiled in modules:
core.c
prefork.c
http_core.c
mod_so.c

Weitere Informationen findet man auf der Apache-Webseite: Multi-Processing-Module (MPMs).

Berechnung und Begrenzung des maximalen Arbeitsspeicher-Verbrauchs

Wie bereits erwähnt startet der Apache auf Basis des Prefork-MPM pro Client-Anfrage einen Apache-Prozess. Greifen beispielsweise zehn Leser auf die Webseite zu, so werden zehn Apache-Prozesse gestartet. Zu erwähnen ist, dass pro Sitzung bzw. pro Client-Anfrage ein einziger Apache-Prozess zuständig ist, obwohl eine Webseite aus mehreren Daten (HTML, Bilder, JavaScript usw.) besteht.

Nun stellt sich die Frage, wie viele gleichzeitige Client-Anfragen verkraftet der Webserver bzw. wie viele Apache-Prozesse können gestartet werden, ohne dass das Linux-System beginnt, Daten auf die Festplatte auszulagern? Hierzu gibt es folgende Faustregel:

Max. Arbeitsspeicher-Belegung = Speicherverbrauch pro Apache-Prozess * Max. Anzahl Apache-Prozesse

Wie viel RAM verbraucht ein Apache-Prozess? Die Antwort ist von System zu System unterschiedlich und abhängig von der jeweiligen Apache-Konfiguration. Aus diesem Grund belastet man den Webserver mit typischen Anfragen. Anschließend wirft man einen Blick in das Linux-Tool top und beobachtet die Spalte RES, welche Auskunft des verwendeten Arbeitsspeicher des jeweiligen Prozess gibt. Laut der folgenden Ausgabe von top verbraucht ein Apache-Prozess ca. 17 MB.

top - 08:38:44 up 32 days, 16:15,  1 user,  load average: 0.06, 0.08, 0.07
Tasks: 103 total, 1 running, 102 sleeping, 0 stopped, 0 zombie
Cpu(s): 12.7%us, 1.0%sy, 0.0%ni, 86.2%id, 0.2%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 1993964k total, 1714668k used, 279296k free, 63976k buffers
Swap: 1003964k total, 12028k used, 991936k free, 1276376k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5091 apache 20 0 165m 17m 3052 S 13 0.9 0:00.45 apache2
9289 mysql 20 0 460m 90m 3588 S 5 4.7 347:59.95 mysqld
5079 apache 20 0 158m 7664 1412 S 3 0.4 0:00.13 apache2
5087 apache 20 0 166m 17m 3052 S 2 0.9 0:00.50 apache2
5089 apache 20 0 158m 7668 1412 S 2 0.4 0:00.13 apache2

Das hier verwendete System verfügt über 2 GB (2048 MB) Arbeitsspeicher. Zuerst legen wir fest, dass 512 MB für das System und 1536 MB für den Apache verfügbar sein sollen. Laut der oben genannten Faustregel ergibt sich demzufolge, dass das System ca. 90 gleichzeitige Apache-Prozesse verkraftet.

1536 MB = 90,35 Apache-Prozesse * 17 MB

Aber wo beschränkt man die Anzahl gleichzeitiger Apache-Prozesse?. Dazu öffnet man die Apache-Konfigurationsdatei, welche den Abschnitt mpm_prefork_module beinhaltet. Auf einem Linux Gentoo System liegt dieser Abschnitt in der Datei /etc/apache2/modules.d/00_mpm.conf.

 # Auszug aus der /etc/apache2/modules.d/00_mpm.conf 
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 90
MaxRequestsPerChild 100
</IfModule>

Die entscheidende Einstellung ist MaxClients, welche die maximale Anzahl begrenzt. Der Vollständigkeithalber hier die Erläuterung der anderen Einstellungen:

  • StartServers: Der Apache startet mit fünf Prozessen, welche sofort bereit für die Verarbeitung von Client-Anfragen sind.
  • MinSpareServers: Wie viele Prozesse sollen mindestens aktiv bleiben, wenn der Apache "gerade nichts zu tun hat"?
  • MaxSpareServers: Wie viele Prozesse sollen maximal aktiv bleiben, wenn der Apache "gerade nichts zu tun hat"?
  • MaxClients: Maximale Anzahl der gleichzeitig gestarteten Apache-Prozesse. Diese sollten in Abhängigkeit der RAM-Größe beschränkt werden.
  • MaxRequestsPerChild: Anzahl der Anfragen pro Apache-Prozess, welche (nacheinander) von dem jeweiligen Prozess abgearbeitet werden. Sollte begrenzt werden, um fehlerhafte Prozesse zu beschränken.

StartServers, MinSpareServers und MaxSpareServers sind für die Leistung des Apache zuständig, wenn plötzlich eine hohe Anzahl gleichzeitiger Anfragen auftreten. Je höher die Werte gesetzt, desto weniger Apache-Prozesse müssen gestartet werden, da diese bereits aktiv sind und auf Anfragen warten.

Um zu kontrollieren, wie viele Apache-Prozesse zur Zeit gestartet sind, gibt man folgenden Befehl ein:

# Anzahl gestarteter Apache-Prozesse 
# ps -C apache2 | wc -l
13

Leistungstest - Auslastung von CPU, RAM und HDD prüfen

Eine sehr wichtige Regel ist, dass Webserver niemals dazu genötigt werden darf, Teile des Arbeitsspeichers in den SWAP-Bereich auszulagern, weil dieser zu gering bemessen ist. Werden Anfragen erst einmal auf die Festplatte ausgelagert, wird der Webserver überproportional langsam. Kritisch wird es dann, wenn Arbeitsspeicher und der SWAP-Bereich zusammen nicht ausreichen. Dies kann beispielsweise passieren, wenn die maximale Anzahl von Apache-Prozessen nicht beschränkt wird und im Falle einer DoS-Attacke Unmengen an Anfragen auftreten. Es ist demzufolge eine Frage der Zeit, bis der Webserver zum Stillstand kommt und nicht mehr erreichbar ist.

Die Lösung ist: entweder man erweitert den Arbeitsspeicher oder man beschränkt die maximale Anzahl von Apache-Prozessen, so dass niemals mehr Anfragen verarbeitet werden wie es die Größe des Arbeitsspeichers erlaubt. Die Einstellung MaxClients sollte nicht zu gering (negative Auswirkung auf die Leistung des Apache), aber auch nicht zu hoch eingestellt werden (Überlauf der Arbeitsspeichers -> SWAP).

Wir prüfen nun die Einstellungen mit einem einfachen Trick, indem wir die entsprechende Webseite aufrufen und die F5-Taste (Aktualisieren) im Webbrowser eine Zeit lang gedrückt halten. Alternativ kann man Stresstest-Tools von Apache verwenden. Dazu hilft folgender Aufruf:

ab -n100 -c20 www.MeineDomain.de

Die Anzahl der Apache-Prozesse sollte nun kontinuierlich bis zum definierten "MaxClients" ansteigen:

# Anzahl der gestarteten Apache-Prozesse 
# watch 'ps -C apache2 | wc -l'
Every 2.0s: ps -C apache2 | wc -l
92

Beobachten wir nun die Arbeitsspeicher-Belegung mittels free als erstes Indiz für zu wenig Arbeitsspeicher im System. In diesem Beispiel ist alles im grünen Bereich, da noch 386 MB freier RAM zur Verfügung stehen und nur wenig (14 MB) im SWAP-Bereich ausgelagert wird:

watch free -m              total       used       free     shared    buffers     cached
Mem: 1947 1660 286 0 2 97
-/+ buffers/cache: 1560 386
Swap: 980 14 966

Entscheidend ist die zweite Zeile (-/+ buffers/cache:). Der Wert free darf nicht auf 0 sein und used nicht der Gesamtgröße des Arbeitsspeichers entsprechen, da in diesem Fall der Arbeitsspeichers voll ausgeschöpft ist. Steigt demnach auch die SWAP-Nutzung, beginnt das System Daten auf die Festplatte auszulagern. Demzufolge ist die Größe des Arbeitsspeichers zu gering bemessen!

Das zweite Indiz, ob ein System starken Gebrauch des SWAP-Bereichs macht, ist die CPU-Auslastung im Bezug auf die so genannte Wait Access Time. Dieser Wert misst die Zeit der CPU, welche für das Warten auf I/O-Geräte (Festplatte, optische Laufwerke usw.) in Anspruch genommen wird. Ist die Wait Access Time zu hoch, benötigt das System sehr viel Rechenzeit für den Zugriff auf die Festplatte.

Das nützliche Tool top gibt uns Auskunft über die Wait Access Time. In der Zeile CPU(s) ist dies die Spalte wa. In diesem Beispiel beträgt die Wait Access Time 0,2% und liegt ebenfalls im grünen Bereich:

top - 08:38:44 up 32 days, 16:15,  1 user,  load average: 0.06, 0.08, 0.07
Tasks: 103 total, 1 running, 102 sleeping, 0 stopped, 0 zombie
Cpu(s): 12.7%us, 1.0%sy, 0.0%ni, 86.2%id, 0.2%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 1993964k total, 1714668k used, 279296k free, 63976k buffers
Swap: 1003964k total, 12028k used, 991936k free, 1276376k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5091 apache 20 0 165m 17m 3052 S 13 0.9 0:00.45 apache2
9289 mysql 20 0 460m 90m 3588 S 5 4.7 347:59.95 mysqld
5079 apache 20 0 158m 7664 1412 S 3 0.4 0:00.13 apache2
5087 apache 20 0 166m 17m 3052 S 2 0.9 0:00.50 apache2
5089 apache 20 0 158m 7668 1412 S 2 0.4 0:00.13 apache2

Weitere Informationen zur Leistungsanalyse unter Linux findet man in diesem Artikel:
Linux - Systemauslastung analysieren

Apache Monitoring - Skript im Eigenbau mit allen wichtigen Informationen

Die hier geschilderten Informationen stellen eine Momentaufnahme dar. Um einen besseren Überblick zu bekommen kann man folgendes Skript regelmäßig mit einem Cron-Job (bsp. minütlich) ausführen lassen. Das Skript sammelt Werte über die Anzahl der Apache-Prozesse, der CPU-Auslastung inkl. der Unterteilung und der load average.

#!/bin/bash
logdatei=/tmp/tmp_x8987h_top.log

datum=$(date +"%Y-%m-%d %H:%M:%S")
top -b -n 3 -d 3 | grep Cpu | tac | head -n 1 > $logdatei

cpuUs=$(cat $logdatei | cut -c 8-12)
cpuSy=$(cat $logdatei | cut -c 17-21)
cpuNi=$(cat $logdatei | cut -c 26-30)
cpuId=$(cat $logdatei | cut -c 35-39)
cpuWa=$(cat $logdatei | cut -c 44-48)
cpuHi=$(cat $logdatei | cut -c 53-57)
cpuSi=$(cat $logdatei | cut -c 62-66)
cpuSt=$(cat $logdatei | cut -c 71-75)
loadAverage1Min=$(cat /proc/loadavg | cut -d ' ' -f1)
countApache=$(ps -C apache2 | wc -l)

# Datum;Anzahl Apache Prozesse;CPU IDLE;CPU_USED;CPU WA;$cpuSy;$cpuNi;$cpuHi;$cpuSi;$cpuSt;Load Average
echo "$datum;$countApache;$cpuId;$cpuUs;$cpuWa;$cpuSy;$cpuNi;$cpuHi;$cpuSi;$cpuSt;$loadAverage1Min" >> /var/log/apache2/countprocess.log

Die Ausgabe in der Logdatei, welche hervorragend in Excel oder OpenOffice als CSV-Datei importiert werden kann, sieht folgendermaßen aus:

# Datum;Anzahl Apache Prozesse;CPU IDLE;CPU_USED;CPU WA;$cpuSy;$cpuNi;$cpuHi;$cpuSi;$cpuSt;Load Average
2011-11-09 10:04:01;16; 95.4; 4.3; 0.0; 0.2; 0.0; 0.2; 0.0; 0.0;0.19
2011-11-09 10:05:01;30; 89.1; 9.6; 0.0; 1.3; 0.0; 0.0; 0.0; 0.0;0.35
2011-11-09 10:06:01;29; 99.3; 0.3; 0.0; 0.2; 0.0; 0.0; 0.2; 0.0;0.19
2011-11-09 10:07:01;28; 76.6; 20.9; 0.0; 2.0; 0.0; 0.2; 0.3; 0.0;0.12
2011-11-09 10:08:01;27; 85.6; 12.8; 0.0; 1.3; 0.0; 0.2; 0.2; 0.0;0.11

Anhand dieser Statistik kann man sehr gut erkennen, wie die Auslastung der einzelnen Kernbereiche (Anzahl Apache Prozesse, CPU-Auslastung und Load Average) im Tagesverlauf war. Zusätzlich hat man die Möglichkeit in Excel / OpenCalc mit den Werten zu arbeiten (Maximum, Minimum, Durchschnitt usw.) oder die Logdatei in MySQL zu importieren.