Webserver-Tuning ist entscheidend für die Performance bei hohen Besucherzahlen. Die richtige Konfiguration von Worker-Prozessen, Connections und Caching macht den Unterschied.
Grundlagen
Performance-Faktoren
| Faktor | Einfluss | |--------|----------| | Worker/Connections | Gleichzeitige Anfragen | | Keep-Alive | Verbindungswiederverwendung | | Caching | Reduktion von Berechnungen | | Kompression | Bandbreitenersparnis | | Timeouts | Ressourcenfreigabe |
System-Limits prüfen
# Offene Dateien
ulimit -n
# Max User Processes
ulimit -u
# Kernel-Limits
cat /proc/sys/fs/file-max
cat /proc/sys/net/core/somaxconnNginx-Tuning
Worker-Konfiguration
# /etc/nginx/nginx.conf
# Worker-Prozesse (= CPU-Kerne)
worker_processes auto;
# Worker-Connections
events {
worker_connections 4096;
use epoll;
multi_accept on;
}Berechnung
Max Clients = worker_processes × worker_connections
Beispiel: 4 × 4096 = 16.384 gleichzeitige VerbindungenAllgemeine Optimierungen
# /etc/nginx/nginx.conf
worker_processes auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
# Basics
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# Timeouts
keepalive_timeout 30;
keepalive_requests 1000;
send_timeout 30;
client_body_timeout 30;
client_header_timeout 30;
# Buffer
client_body_buffer_size 16k;
client_header_buffer_size 1k;
client_max_body_size 16m;
large_client_header_buffers 4 16k;
# Hash Tables
types_hash_max_size 2048;
server_names_hash_bucket_size 64;
# Logging
access_log off;
# Oder: nur Fehler loggen
# access_log /var/log/nginx/access.log combined buffer=512k flush=1m;
error_log /var/log/nginx/error.log warn;
# Gzip
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}Statische Dateien optimieren
server {
listen 80;
server_name example.com;
root /var/www/html;
# Statische Dateien cachen
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# Open File Cache
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}Proxy-Optimierung
upstream backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
location / {
proxy_pass http://backend;
# Connection Reuse
proxy_http_version 1.1;
proxy_set_header Connection "";
# Buffering
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 32k;
proxy_busy_buffers_size 64k;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Cache
proxy_cache_valid 200 10m;
}
}FastCGI-Optimierung (PHP)
upstream php-fpm {
server unix:/run/php/php8.2-fpm.sock;
}
server {
location ~ \.php$ {
fastcgi_pass php-fpm;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Buffering
fastcgi_buffering on;
fastcgi_buffer_size 16k;
fastcgi_buffers 16 16k;
# Timeouts
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 180s;
fastcgi_read_timeout 180s;
# Cache
fastcgi_cache_valid 200 60m;
}
}Apache-Tuning
MPM-Auswahl
# Aktives MPM prüfen
apachectl -V | grep MPM
# MPM wechseln
a2dismod mpm_prefork
a2enmod mpm_event
systemctl restart apache2MPM Event (empfohlen)
# /etc/apache2/mods-available/mpm_event.conf
<IfModule mpm_event_module>
StartServers 4
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 64
MaxRequestWorkers 400
MaxConnectionsPerChild 10000
</IfModule>MPM Worker
# /etc/apache2/mods-available/mpm_worker.conf
<IfModule mpm_worker_module>
StartServers 4
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 10000
</IfModule>MPM Prefork (für mod_php)
# /etc/apache2/mods-available/mpm_prefork.conf
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 150
MaxConnectionsPerChild 3000
</IfModule>Berechnung MaxRequestWorkers
MaxRequestWorkers = (Verfügbarer RAM - System-RAM) / RAM pro Worker
Beispiel:
- 8 GB RAM gesamt
- 2 GB für System
- ~50 MB pro Apache-Worker
MaxRequestWorkers = (8000 - 2000) / 50 = 120Keep-Alive-Konfiguration
# /etc/apache2/apache2.conf
KeepAlive On
MaxKeepAliveRequests 500
KeepAliveTimeout 5Allgemeine Optimierungen
# /etc/apache2/conf-available/performance.conf
# Hostname Lookups deaktivieren
HostnameLookups Off
# Timeout reduzieren
Timeout 60
# Keine Signaturen
ServerSignature Off
ServerTokens Prod
# ETags
FileETag None
# Symlinks
Options +FollowSymLinks -SymLinksIfOwnerMatchmod_deflate (Kompression)
# /etc/apache2/mods-available/deflate.conf
<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
# Komprimierbare Typen
AddOutputFilterByType DEFLATE text/html text/plain text/xml
AddOutputFilterByType DEFLATE text/css text/javascript
AddOutputFilterByType DEFLATE application/javascript application/json
AddOutputFilterByType DEFLATE application/xml application/xhtml+xml
AddOutputFilterByType DEFLATE font/opentype font/otf font/ttf
# Bereits komprimierte Dateien ausschließen
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|zip|gz|bz2|rar)$ no-gzip
# Problematische Browser
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
</IfModule>mod_expires (Caching)
# /etc/apache2/mods-available/expires.conf
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 month"
# HTML
ExpiresByType text/html "access plus 1 hour"
# CSS/JavaScript
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
# Bilder
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
# Fonts
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
</IfModule>PHP-FPM-Tuning
Pool-Konfiguration
; /etc/php/8.2/fpm/pool.d/www.conf
[www]
user = www-data
group = www-data
; Socket-Verbindung (schneller)
listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Process Manager
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 1000
; Timeouts
request_terminate_timeout = 180Process Manager Modi
| Modus | Beschreibung | Verwendung | |-------|--------------|------------| | static | Feste Anzahl Worker | Konstante Last | | dynamic | Skaliert nach Bedarf | Standard | | ondemand | Nur bei Bedarf | Wenig Traffic |
Berechnung pm.max_children
# Durchschnittlichen RAM pro PHP-Prozess ermitteln
ps -ylC php-fpm8.2 --sort:rss | awk '{sum+=$8; count++} END {print sum/count/1024 " MB"}'
# max_children = (Verfügbarer RAM - System) / RAM pro Prozess
# Beispiel: (4000 MB - 1000 MB) / 50 MB = 60OPcache konfigurieren
; /etc/php/8.2/fpm/conf.d/10-opcache.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.validate_timestamps=1
opcache.save_comments=1
opcache.fast_shutdown=1
; Preloading (PHP 7.4+)
; opcache.preload=/var/www/html/preload.php
; opcache.preload_user=www-dataSystem-Tuning
Kernel-Parameter
# /etc/sysctl.d/99-webserver.conf
# Netzwerk-Buffer
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
# TCP-Optimierungen
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
# Lokale Ports
net.ipv4.ip_local_port_range = 1024 65535
# Memory
vm.swappiness = 10
# File Descriptors
fs.file-max = 2097152sysctl -p /etc/sysctl.d/99-webserver.confLimits für Webserver
# /etc/security/limits.d/webserver.conf
www-data soft nofile 65535
www-data hard nofile 65535
www-data soft nproc 65535
www-data hard nproc 65535Systemd Service-Limits
# /etc/systemd/system/nginx.service.d/limits.conf
# oder /etc/systemd/system/apache2.service.d/limits.conf
[Service]
LimitNOFILE=65535
LimitNPROC=65535systemctl daemon-reload
systemctl restart nginxBenchmarking
Apache Bench (ab)
# 1000 Requests, 100 gleichzeitig
ab -n 1000 -c 100 http://localhost/
# Mit Keep-Alive
ab -n 1000 -c 100 -k http://localhost/
# POST-Request
ab -n 1000 -c 50 -p data.json -T application/json http://localhost/apiwrk
# Installation
apt install wrk
# Benchmark
wrk -t4 -c100 -d30s http://localhost/
# Mit Skript
wrk -t4 -c100 -d30s -s post.lua http://localhost/apisiege
# Installation
apt install siege
# Benchmark
siege -c 100 -t 30S http://localhost/
# URLs aus Datei
siege -c 100 -t 30S -f urls.txtMonitoring
Nginx Status
# /etc/nginx/conf.d/status.conf
server {
listen 127.0.0.1:8080;
location /nginx_status {
stub_status on;
access_log off;
}
}curl http://127.0.0.1:8080/nginx_statusApache Status
# /etc/apache2/mods-available/status.conf
<IfModule mod_status.c>
<Location /server-status>
SetHandler server-status
Require ip 127.0.0.1
</Location>
ExtendedStatus On
</IfModule>a2enmod status
systemctl restart apache2
curl http://127.0.0.1/server-status?autoPHP-FPM Status
; /etc/php/8.2/fpm/pool.d/www.conf
pm.status_path = /fpm-status
ping.path = /fpm-pinglocation ~ ^/(fpm-status|fpm-ping)$ {
access_log off;
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
}Zusammenfassung
| Nginx | Empfehlung | |-------|------------| | worker_processes | auto (= CPU-Kerne) | | worker_connections | 2048-4096 | | keepalive_timeout | 30s | | gzip | on |
| Apache MPM | Empfehlung | |------------|------------| | MPM Event | Bevorzugt | | MaxRequestWorkers | RAM-basiert berechnen | | KeepAliveTimeout | 5s | | MaxKeepAliveRequests | 500 |
| PHP-FPM | Empfehlung | |---------|------------| | pm | dynamic | | pm.max_children | RAM-basiert | | OPcache | Aktiviert |
| System | Einstellung | |--------|-------------| | somaxconn | 65535 | | file-max | 2097152 | | swappiness | 10 |
Fazit
Webserver-Tuning erfordert eine ganzheitliche Betrachtung von Webserver, PHP und Betriebssystem. Die wichtigsten Stellschrauben sind Worker-Konfiguration, Keep-Alive-Einstellungen und Caching. Benchmarks helfen, Optimierungen zu validieren. Die Konfiguration muss an die verfügbare Hardware und das Traffic-Muster angepasst werden. Regelmäßiges Monitoring deckt Engpässe frühzeitig auf.