Apache optimieren für Spitzenzeiten

HomerS

New Member
Hallo Leute!

Ich hab einen Vserver mit openSuse 10.3, 5 GB RAM, Xeon 3,2 GHz CPU, PLESK 8.6.0 und 32 Domains. Der RAM-Verbrauch ist immer nur bei ca. 7% und die durchschnittliche Auslastung laut PLESK bei 0.05.

Die Kiste läuft super und alle Websites werden zügig aufgebaut.

Nun habe ich einen Kunden oben, der ca. 1 in der Woche einen Newsletter an ca. 12.000 Empfänger versendet. Der Versand läuft über eine externe Mailing-Software, belastet den Server also nicht. Die Bilder in diesem Mailing liegen am Server und werden von diesem nachgeladen, wenn der Newsletter-Empfänger das e-mail bekommt und dann "Grafiken laden" klickt.
Nun ist es anscheinend so, daß das viele Empfänger gleichzeitig machen (der Versand des Newsletters ist immer so zur Mittagszeit, wo anscheinend alle in ihre mails schauen ;)). Weiters gibt es in dem Newsletter auch Links auf PDFs, die man sich vom Server downloaden kann - das machen anscheinend auch alle gleichzeitig ;)

Auf jeden Fall ist zu diesem Zeitpunkt der Server schwerstens beschäftigt und reißt auch alle anderen Websites am Server mit ins Verderben: Der Seitenaufbau ist nur noch quälend langsam. Während der Zeit funktioniert aber e-mail-Empfang und -Versand und auch PLESK problemlos und schnell.
Auch der RAM-Verbrauch steigt nicht sonderlich und die durchschnittliche Auslastung geht laut PLESK auch nur auf max. 0.30

Nach ca. 40 Minuten ist der Spuk vorbei (die Stoßzeit anscheinend beendet) und alle Websites laden wieder zügig.

Also mal in die server-tunig.conf von Apache geschaut. Da staunte ich nicht schlecht, als ich folgende Werte vorfand:

Code:
# prefork MPM
<IfModule prefork.c>
        # number of server processes to start
        # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#startservers
        StartServers            1
        # minimum number of server processes which are kept spare
        # http://httpd.apache.org/docs/2.2/mod/prefork.html#minspareservers
        MinSpareServers         1
        # maximum number of server processes which are kept spare
        # http://httpd.apache.org/docs/2.2/mod/prefork.html#maxspareservers
        MaxSpareServers         5
        # highest possible MaxClients setting for the lifetime of the Apache process.
        # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#serverlimit
        ServerLimit            10
        # maximum number of server processes allowed to start
        # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxclients
        MaxClients             10
        # maximum number of requests a server process serves
        # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxrequestsperchild
        MaxRequestsPerChild   250
</IfModule>

Hmm, MaxClients 10?

Ich habe die Werte mal so geändert und Apache neu gestartet:

Code:
# prefork MPM
<IfModule prefork.c>
        # number of server processes to start
        # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#startservers
        StartServers            32
        # minimum number of server processes which are kept spare
        # http://httpd.apache.org/docs/2.2/mod/prefork.html#minspareservers
        MinSpareServers         5
        # maximum number of server processes which are kept spare
        # http://httpd.apache.org/docs/2.2/mod/prefork.html#maxspareservers
        MaxSpareServers         20
        # highest possible MaxClients setting for the lifetime of the Apache process.
        # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#serverlimit
        ServerLimit            512
        # maximum number of server processes allowed to start
        # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxclients
        MaxClients             512
        # maximum number of requests a server process serves
        # http://httpd.apache.org/docs/2.2/mod/mpm_common.html#maxrequestsperchild
        MaxRequestsPerChild   8000
</IfModule>

Jetzt hoffe ich halt, daß es daran gelegen hat und daß meine Settings was bringen. Wissen werde ich es wohl erst nächste Woche, wenn der nächste Newsletter ansteht...

Kann mir jemand Hoffnung machen, daß die Einstellungen was bringen werden? :)
Oder muß ich sonst noch wo den Hebel (oder Hobel) ansetzen?
DANKE im Voraus!
 
wieviele gleichzeitige Seitenaufrufe Apache handhaben kann ist u.a. vom verfügbaren RAM abhängig. Du hast tatsächlich 5 GB RAM?

Jede Verbindung zum Server benötigt einen httpd2 Prozess und dieser benötigt ca. 12 MB RAM. Bei 100 gleichzeitigen Verbindungen wären das 1,2 GB RAM.

Man kann für die httpd2 Prozesse aber nicht den gesamten RAM verwenden, da Linux, Apache, Mailserver, Plesk, MySQL auch noch RAM benötigen.

Von den 5GB RAM kann man übern Daumen pauschal ~100 MB abziehen. Der Rest hat man für httpd2 und MySQL zur Verfügung.

Rechnen wir mal großzügig.

Von den 5 GB ziehen wie für Linux, Apache, Plesk ect. 200 MB ab. Bleiben noch 4,8 GB RAM für httpd2 Prozesse und MySQL.

350 httpd2 Prozesse würden 4,2 GB benötigen. Für MySQL wären noch 600 MB RAM übrig.

Apache Konfiguration
Code:
Timeout 30
KeepAlive On
MaxKeepAliveRequests 150
KeepAliveTimeout 2 [COLOR="Red"]sehr wichtig![/COLOR]


<IfModule prefork.c>
StartServers       5
MinSpareServers    10
MaxSpareServers    20
ServerLimit       350
MaxClients        350
MaxRequestsPerChild  4000
</IfModule>

Und MySQL konfigurierst du so, daß MySQL sich nicht mehr als 600 MB RAM nimmt.

Hier lesen! Apache + MySQL Performance Tuning

Beispiel /etc/my.cnf
Code:
[mysqld]

key_buffer = 16M
net_buffer_length = 8K

sort_buffer_size = 128K
myisam_sort_buffer_size = 256K

read_buffer_size = 128K
read_rnd_buffer_size = 256K
join_buffer_size = 2M

query_cache_size = 16M
thread_cache = 32
table_cache = 2048
max_allowed_packet = 256K

max_connections = 100
low_priority_updates = 1
long_query_time = 2
 
Last edited by a moderator:
Anmerkung

Es könnte auch Sinn machen die MinSpare und MaxSpare zu erhöhen, damit diese httpd2 Prozesse sofort zur Verfügung stehen nachdem die Mails versandt wurden. Ansonsten muß Apache diese Prozesse erst generieren (forken).

Kannst ja mal testen.
Code:
<IfModule prefork.c>
StartServers       5
MinSpareServers    100
MaxSpareServers    150
ServerLimit       350
MaxClients        350
MaxRequestsPerChild  4000
</IfModule>

Erklärung:

Beim Start von Apache werden 5 Prozesse generiert (StartServers). Weitere Prozesse werden generiert von denen 100 (MinSpareServers) unbeschäftigt gehalten werden. Maximal werden 150 Prozesse (MaxSpareServers) unbeschäftigt gehalten.

Angenommen Apache benötigt im Tagesschnitt 20 MaxClients. Nach dem Mailversand muß diese Zahl auf 350 (RAM Limit!) erhöht werden. 100 davon sollten wegen MinSpareServers sofort zur Vefügung stehen. Die restlichen 350 - 20 - 100 = 230 muß Apache erst generieren.
 
Last edited by a moderator:
Hallo noto!

Danke für Deine ausführliche Erklärung! Werde die Settings dahingehend anpassen und hoffen, daß der nächste Newsletterversand problemlos über die Bühne gehen wird.

Zum RAM: Sorry, da habe ich mich verschaut - PLESK zeigt mir zwar die Verfügbarkeit von 5 GB an (siehe beiliegenden Screenshot), aber laut Produktbeschreibung (ist ein vServer Platinum X3 von s4y) hat man 2.560 MB DDR-RAM und 5.120 MB FlexRAM für Stoßzeiten.
Ändert das nun etwas an den von Dir vorgeschlagenen Einstellungen?

Danke für Deine Hilfe!
 

Attachments

  • screenshot.jpg
    screenshot.jpg
    61.5 KB · Views: 245
Ändert das nun etwas an den von Dir vorgeschlagenen Einstellungen?
Ja, alles! Aber dank der ausführlichen Erklärung sollte es ja jetzt kein Problem mehr darstellen, die Werte neu auszurechnen ;) -> dazu auch die im ersten Punkt verlinkten Informationen ("Hier lesen! Apache + MySQL Performance Tuning") beachten.
 
hat man 2.560 MB DDR-RAM und 5.120 MB FlexRAM für Stoßzeiten.
auf den FlexRam kann man sich nicht verlassen.

Bei mir benötigt Linux, qmail und Apache im Leerlauf ~190 MB RAM. Wenn Plesk, Spamassassin, Dr. Web und Bind dazukommen werden ~320 MB benötigt.

Von den 2560 MB RAM ziehen wir deshalb pauschal 320 MB ab. Für Apache httpd2 Prozesse und MySQL bleiben 2560 - 320 = 2240 MB RAM übrig.

MySQL kommt auch mit wenig RAM gut klar, daher setzen wir hier mal 80 MB an. Für Apache bleiben dann noch 2160 MB übrig.

2160 MB : 12 MB = 180 httpd2 Prozesse (MaxClients). Jeder httpd2 Prozess benötigt im Schnitt 12 MB.

Sollte MySQL mit den 80 MB nicht zurecht kommen und z.B. 150 MB benötigt werden, dann ergeben sich (2240 MB - 150 MB) : 12 MB = 174 httpd2 Prozesse (MaxClients).

Neue Konfiguration
Code:
Timeout 30
KeepAlive On
MaxKeepAliveRequests 150
KeepAliveTimeout 2


<IfModule prefork.c>
StartServers       5
MinSpareServers    10
MaxSpareServers    20
ServerLimit       180
MaxClients        180
MaxRequestsPerChild  4000
</IfModule>

my.cnf
Code:
[mysqld]

key_buffer = 16M
net_buffer_length = 8K

sort_buffer_size = 128K
myisam_sort_buffer_size = 256K

read_buffer_size = 128K
read_rnd_buffer_size = 256K
join_buffer_size = 2M

query_cache_size = 4M
thread_cache = 32
table_cache = 1024
max_allowed_packet = 256K

max_connections = 60
low_priority_updates = 1
long_query_time = 2
dürften um die 80 MB sein. Tatsächlicher Wert mußt du mit Tuning-Primer Script ermitteln. Wenn MySQL mehr als
Code:
Configured Max Memory Limit : 80 M
benötigt, dann mußt du die Buffers kleiner machen.
 
Last edited by a moderator:
Danke für die hilfreichen Tipps!
Die Ausgabe von tuning-primer sieht so aus:

Code:
        -- MYSQL PERFORMANCE TUNING PRIMER --
             - By: Matthew Montgomery -

MySQL Version 5.0.45 i686

Uptime = 99 days 2 hrs 37 min 13 sec
Avg. qps = 6
Total Questions = 58834905
Threads Connected = 1

Server has been running for over 48hrs.
It should be safe to follow these recommendations

To find out more information on how each of these
runtime variables effects performance visit:
http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html
Visit http://www.mysql.com/products/enterprise/advisors.html
for info about MySQL's Enterprise Monitoring and Advisory Service

SLOW QUERIES
The slow query log is NOT enabled.
Current long_query_time = 10 sec.
You have 33 out of 58834926 that take longer than 10 sec. to complete
Your long_query_time may be too high, I typically set this under 5 sec.

BINARY UPDATE LOG
The binary update log is NOT enabled.
You will not be able to do point in time recovery
See http://dev.mysql.com/doc/refman/5.0/en/point-in-time-recovery.html

WORKER THREADS
Current thread_cache_size = 0
Current threads_cached = 0
Current threads_per_sec = 1
Historic threads_per_sec = 0
Your thread_cache_size is fine

MAX CONNECTIONS
Current max_connections = 100
Current threads_connected = 1
Historic max_used_connections = 26
The number of used connections is 26% of the configured maximum.
Your max_connections variable seems to be fine.

MEMORY USAGE
Max Memory Ever Allocated : 52 M
Configured Max Per-thread Buffers : 155 M
Configured Max Global Buffers : 12 M
Configured Max Memory Limit : 167 M
Physical Memory : 5.00 G
Max memory limit seem to be within acceptable norms

KEY BUFFER
Current MyISAM index space = 11 M
Current key_buffer_size = 2 M
Key cache miss rate is 1 : 210
Key buffer fill ratio = 56.00 %
Your key_buffer_size seems to be fine

QUERY CACHE
Query cache is supported but not enabled
Perhaps you should set the query_cache_size

SORT OPERATIONS
Current sort_buffer_size = 512 K
Current read_rnd_buffer_size = 508 K
Sort buffer seems to be fine

JOINS
Current join_buffer_size = 132.00 K
You have had 562749 queries where a join could not use an index properly
You have had 118 joins without keys that check for key usage after each row
You should enable "log-queries-not-using-indexes"
Then look for non indexed joins in the slow query log.
If you are unable to optimize your queries you may want to increase your
join_buffer_size to accommodate larger joins in one pass.

Note! This script will still suggest raising the join_buffer_size when
ANY joins not using indexes are found.

OPEN FILES LIMIT
Current open_files_limit = 1024 files
The open_files_limit should typically be set to at least 2x-3x
that of table_cache if you have heavy MyISAM usage.
Your open_files_limit value seems to be fine

TABLE CACHE
Current table_cache value = 64 tables
You have a total of 2385 tables
You have 64 open tables.
Current table_cache hit rate is 0%, while 100% of your table cache is in use
You should probably increase your table_cache

TEMP TABLES
Current max_heap_table_size = 16 M
Current tmp_table_size = 32 M
Of 1962500 temp tables, 53% were created on disk
Effective in-memory tmp_table_size is limited to max_heap_table_size.
Perhaps you should increase your tmp_table_size and/or max_heap_table_size
to reduce the number of disk-based temporary tables
Note! BLOB and TEXT columns are not allow in memory tables.
If you are using these columns raising these values might not impact your
ratio of on disk temp tables.

TABLE SCANS
Current read_buffer_size = 252 K
Current table scan ratio = 71 : 1
read_buffer_size seems to be fine

TABLE LOCKING
Current Lock Wait ratio = 1 : 193646
Your table locking seems to be fine

Wie Du siehst, steht "Configured Max Memory Limit : 167 M".
Nun ist es interessant, daß ich an den Werten in der my.cnf schrauben und drehen kann wie ich will - die Ausgabe ist immer die gleiche.
Was mich auch stutzig macht, ist daß er schreibt:
Code:
QUERY CACHE
Query cache is supported but not enabled
Perhaps you should set the query_cache_size
aber in der my.cnf sehrwohl steht:
Code:
query_cache_size = 4M

Also irgendwie hat es den Anschein, als ob mySQL überhaupt nicht auf die my.cnf schaut. mySQL habe ich natürlich nach jeder Änderung an der my.cnf neu gestartet!
Ich kann die my.cnf sogar komplett löschen - die Ausgabe von tuning-primer ist immer die gleiche. :confused:
 
Apache mit prefork-MPM ist leider eine absolute "Speichersau" und für das Ausliefern großer Mengen von statischen Dateien ungeeignet. Wenn möglich (mod_php verträgt kein Threading), steig auf ein MPM um das Threading verwendet. Oder noch besser, auf einen Webserver der alles in einem Prozess abhandelt (Litespeed, Lighttpd), damit kann man auch bequem mehrere tausend gleichtzeitige Verbindungen mit ein paar MB RAM bedienen.
 
also das Phänomen mit der my.cnf habe ich nun hingekriegt. Nachdem mySQL diese Conf-Datei konsequent ignoriert hat (trotz beenden, neu starten), habe ich nun mal den ganzen Server neu gestartet. Und siehe da - mySQL startet überhaupt nicht mehr. Interessant. Hatte gleich die my.cnf in Verdacht und mal die unangepaßte Standard-my.cnf geladen. OK - mySQL startet wieder. Wieder die angepaßte my.cnf geladen - mySQL startet nicht mehr.

Durch probieren bin ich draufgekommen, daß wenn diese Zeile in der my.cnf steht
Code:
join_buffer_size = 2M
mySQL nicht mehr startet. Warum auch immer.
Habe diese Zeile also rausgenommen und ansonsten die Settings von noto übernommen. tuning-primer zeigt nun "Configured Max Memory Limit : 78 M".

Danke nochmal für die Hilfe!
Jetzt bin ich mal auf den nächsten Newsletter-Versand gepannt :rolleyes:
 
wie hast du denn versucht den MySQL Server neuzustarten ?

den laut der Ausgabe von tuning-primer lief der Server da Schon fast 100 Tage
MySQL Version 5.0.45 i686

Uptime = 99 days 2 hrs 37 min 13 sec
 
Back
Top