Wichtige Nginx-Performance-Tuning-Checkliste für stark frequentierte Websites

Eine praktische Nginx-Performance-Checkliste für Worker, Verbindungen, Puffer, Caching, Komprimierung, Protokolle, Timeouts, TLS und statische Dateien.

Wichtige Nginx-Performance-Tuning-Checkliste für stark frequentierte Websites

Nginx-Performance-Tuning ist am einfachsten, wenn Sie es wie eine Checkliste behandeln, nicht wie ein Ratespiel. Beginnen Sie mit den Grenzen, die bestimmen, wie viel Traffic Nginx akzeptieren kann, und arbeiten Sie sich dann zu Pufferung, Caching, Komprimierung, Protokollierung, Timeouts, TLS und den dahinter liegenden Backend-Diensten vor.

Fügen Sie nicht alle hier genannten Direktiven auf einmal in die Produktion ein. Eine gute Nginx-Performance-Tuning-Checkliste hilft Ihnen zu entscheiden, was Sie überprüfen sollten, warum es wichtig ist und was schiefgehen kann, wenn Sie es übertreiben. Die richtige Einstellung für eine überwiegend statische Dokumentationsseite ist nicht die richtige Einstellung für eine Long-Polling-API oder einen Datei-Upload-Dienst.

1. Worker-Prozesse und Verbindungen optimieren

Nginx nutzt ein Master-Worker-Prozessmodell. Der Master-Prozess liest die Konfiguration und verwaltet die Worker-Prozesse, die die eigentlichen Client-Anfragen bearbeiten. Eine korrekte Konfiguration kann die Parallelität und Ressourcennutzung drastisch verbessern.

worker_processes

Diese Direktive legt fest, wie viele Worker-Prozesse Nginx erzeugen wird. Im Allgemeinen ist es eine bewährte Praxis, sie auf auto zu setzen, damit Nginx die Anzahl der CPU-Kerne erkennt und eine entsprechende Anzahl von Worker-Prozessen erzeugt.

worker_connections

Definiert die maximale Anzahl gleichzeitiger Verbindungen, die ein einzelner Worker-Prozess öffnen kann. Diese Einstellung bestimmt zusammen mit worker_processes die theoretische Gesamtzahl gleichzeitiger Verbindungen, die Nginx verarbeiten kann (worker_processes * worker_connections).

multi_accept

Ermöglicht es einem Worker-Prozess, mehrere neue Verbindungen gleichzeitig anzunehmen, wodurch potenzielle Engpässe bei hoher Last vermieden werden.

# /etc/nginx/nginx.conf

worker_processes auto; # Normalerweise auf 'auto' oder die Anzahl der CPU-Kerne gesetzt

events {
    worker_connections 1024; # Anpassen basierend auf Serverkapazität und erwarteter Last
    multi_accept on;
}

Tipp: Wenn die CPU dauerhaft hoch ausgelastet ist, wird eine Erhöhung von worker_connections das Problem nicht allein lösen. Überprüfen Sie zuerst, ob die CPU-Auslastung durch TLS-Handshakes, Komprimierung, Protokollierung, regex-lastiges Routing oder die Upstream-Anwendung verursacht wird.

2. Effizientes Verbindungsmanagement

Die Optimierung der Art und Weise, wie Nginx Netzwerkverbindungen verwaltet, kann den Overhead reduzieren und die Reaktionsfähigkeit verbessern.

keepalive_timeout

Gibt an, wie lange eine Keep-Alive-Client-Verbindung offen bleibt. Die Wiederverwendung von Verbindungen reduziert den Overhead für den Aufbau neuer TCP-Verbindungen und SSL-Handshakes. Ein üblicher Wert liegt zwischen 15 und 65 Sekunden, abhängig von der Interaktivität Ihrer Anwendung.

sendfile

Ermöglicht die direkte Datenübertragung zwischen Dateideskriptoren unter Umgehung der Pufferung im Userspace. Dies verbessert die Leistung beim Ausliefern statischer Dateien erheblich.

tcp_nopush

Arbeitet mit sendfile zusammen. Nginx versucht, den HTTP-Header und den Anfang der Datei in einem Paket zu senden. Danach sendet es Daten in vollständigen Paketen. Dies reduziert die Anzahl der gesendeten Pakete.

tcp_nodelay

Weist Nginx an, Daten sofort zu senden, sobald sie verfügbar sind, ohne Pufferung. Dies ist vorteilhaft für interaktive Anwendungen, bei denen niedrige Latenz wichtiger ist als die Maximierung des Durchsatzes (z. B. Chat-Anwendungen oder Echtzeit-Updates).

http {
    keepalive_timeout 65; # Keep-Alive-Verbindungen für 65 Sekunden
    sendfile on;
    tcp_nopush on; # Erfordert sendfile on
    tcp_nodelay on; # Nützlich für das Proxying dynamischer Inhalte
}

3. Pufferoptimierung

Nginx verwendet Puffer, um Client-Anfragen und Antworten von Upstream-Servern (wie Anwendungsservern) zu verarbeiten. Die richtige Dimensionierung dieser Puffer kann unnötige Festplatten-E/A vermeiden, den Speicherverbrauch reduzieren und den Durchsatz verbessern.

Client-Puffer

  • client_body_buffer_size: Größe des Puffers für den Anforderungstext des Clients. Wenn der Text diese Größe überschreitet, wird er in eine temporäre Datei geschrieben.
  • client_header_buffer_size: Größe des Puffers für die erste Zeile und die Header einer Client-Anfrage.
  • large_client_header_buffers: Definiert die Anzahl und Größe größerer Puffer zum Lesen von Client-Anfrage-Headern. Nützlich für Anfragen mit vielen Cookies oder langen Referer-Headern.

Proxy-Puffer (für Reverse-Proxy-Setups)

  • proxy_buffers: Anzahl und Größe der Puffer zum Lesen von Antworten vom proxysierten Server.
  • proxy_buffer_size: Größe des ersten Puffers zum Lesen der Antwort. Typischerweise kleiner, da er oft nur Header enthält.
  • proxy_busy_buffers_size: Die maximale Menge an Antwortpuffern, die sich zu einem bestimmten Zeitpunkt im Status 'busy' (aktiv an den Client gesendet) befinden können.

FastCGI-Puffer (für PHP-FPM usw.)

  • fastcgi_buffers: Anzahl und Größe der Puffer zum Lesen von Antworten vom FastCGI-Server.
  • fastcgi_buffer_size: Größe des ersten Puffers zum Lesen der Antwort.
http {
    # Client-Puffer
    client_body_buffer_size 1M; # Anpassen basierend auf der erwarteten Größe des Anforderungstexts (z. B. Datei-Uploads)
    client_header_buffer_size 1k;
    large_client_header_buffers 4 8k; # 4 Puffer, jeder 8 KB groß

    # Proxy-Puffer (wenn Nginx als Reverse-Proxy fungiert)
    proxy_buffers 8 16k; # 8 Puffer, jeder 16 KB
    proxy_buffer_size 16k; # Erster Puffer 16 KB
    proxy_busy_buffers_size 16k; # Max. 16 KB an aktiven Puffern

    # FastCGI-Puffer (wenn Nginx mit PHP-FPM arbeitet)
    fastcgi_buffers 16 16k; # Ausgangspunkt für viele PHP-FPM-Apps
    fastcgi_buffer_size 16k; # Erster Puffer 16 KB
}

Warnung: Zu kleine Puffer können zu Festplatten-E/A und Leistungseinbußen führen. Zu große Puffer können übermäßig viel Speicher verbrauchen. Finden Sie durch Tests ein Gleichgewicht.

4. Robuste Caching-Strategien implementieren

Caching ist eine der effektivsten Methoden, um die Leistung zu verbessern und die Last auf Ihren Backend-Servern zu reduzieren. Nginx kann als leistungsstarker Content-Cache dienen.

proxy_cache_path

Definiert den Pfad zum Cache-Verzeichnis, seine Größe, die Anzahl der Unterverzeichnisebenen und wie lange inaktive Elemente im Cache verbleiben.

proxy_cache

Aktiviert das Caching für einen bestimmten location-Block unter Bezugnahme auf die in proxy_cache_path definierte Zone.

proxy_cache_valid

Legt die Zeit fest, für die Nginx Antworten mit bestimmten HTTP-Statuscodes zwischenspeichern soll.

proxy_cache_revalidate

Wenn aktiviert, verwendet Nginx If-Modified-Since- und If-None-Match-Header, um zwischengespeicherte Inhalte mit dem Backend zu validieren, wodurch die Bandbreitennutzung reduziert wird.

proxy_cache_use_stale

Weist Nginx an, veraltete zwischengespeicherte Inhalte auszuliefern, wenn der Backend-Server ausgefallen, nicht erreichbar ist oder Fehler meldet. Dies verbessert die Verfügbarkeit erheblich.

expires

Setzt Cache-Control- und Expires-Header für das clientseitige Caching statischer Dateien. Dies minimiert wiederholte Anfragen an Nginx.

http {
    # Definiert eine Proxy-Cache-Zone im http-Block
    proxy_cache_path /var/cache/nginx/my_cache levels=1:2 keys_zone=my_cache:10m inactive=60m max_size=10g;

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://my_upstream_backend;
            proxy_cache my_cache; # Caching für diesen Ort aktivieren
            proxy_cache_valid 200 302 10m; # Erfolgreiche Antworten 10 Minuten lang cachen
            proxy_cache_valid 404 1m; # 404er 1 Minute lang cachen
            proxy_cache_revalidate on;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
            add_header X-Cache-Status $upstream_cache_status; # Hilft beim Debuggen
        }

        # Statische Dateien für einen längeren Zeitraum im Browser cachen
        location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
            expires 30d; # 30 Tage lang cachen
            add_header Cache-Control "public, no-transform";
            # Für statische Dateien erwägen Sie, sie direkt von Nginx auszuliefern, wenn sie nicht proxysiert werden
            root /var/www/html;
        }
    }
}

5. Gzip-Komprimierung aktivieren

Das Komprimieren von Antworten vor dem Senden an Clients kann die Bandbreitennutzung erheblich reduzieren und die Seitenladezeiten verbessern, insbesondere bei textbasierten Inhalten.

gzip on

Aktiviert die Gzip-Komprimierung.

gzip_comp_level

Legt die Komprimierungsstufe fest (1-9). Stufe 1 ist am schnellsten mit geringerer Komprimierung; Stufe 9 ist am langsamsten mit maximaler Komprimierung. Stufe 6 bietet normalerweise ein gutes Gleichgewicht.

gzip_types

Gibt die MIME-Typen an, die komprimiert werden sollen. Fügen Sie gängige Text-, CSS-, JavaScript- und JSON-Typen hinzu.

gzip_min_length

Legt die Mindestlänge einer Antwort (in Bytes) fest, für die die Komprimierung aktiviert werden soll. Kleine Dateien profitieren nicht wesentlich und könnten aufgrund des Komprimierungs-Overheads sogar langsamer sein.

gzip_proxied

Weist Nginx an, Antworten auch dann zu komprimieren, wenn sie proxysiert werden. any ist ein üblicher Wert.

gzip_vary

Fügt den Vary: Accept-Encoding-Header zu Antworten hinzu, der Proxys mitteilt, dass sich die Antwort je nach Accept-Encoding-Anfrageheader unterscheiden kann.

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6; # Komprimierungsstufe 1-9 (6 ist ein guter Kompromiss)
    gzip_buffers 16 8k; # 16 Puffer, jeder 8 KB
    gzip_http_version 1.1; # Minimale HTTP-Version für Komprimierung
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
    gzip_min_length 1000; # Nur Antworten größer als 1 KB komprimieren
}

6. Protokollierung optimieren

Protokolle sind zwar für die Überwachung und Fehlerbehebung unerlässlich, aber eine übermäßige oder nicht optimierte Protokollierung kann zu erheblichen Festplatten-E/A führen, insbesondere auf stark frequentierten Websites.

access_log

  • Für statische Assets deaktivieren: Bei stark nachgefragten statischen Inhalten (Bilder, CSS, JS) kann das Deaktivieren von access_log viel E/A sparen.
  • Pufferung: Nginx kann Protokolleinträge im Speicher puffern, bevor sie auf die Festplatte geschrieben werden, wodurch die Häufigkeit der Festplattenschreibvorgänge reduziert wird. Die Parameter buffer und flush werden hier verwendet.

error_log

Legen Sie die entsprechende Protokollierungsebene fest (crit, error, warn, info, debug). Für die Produktion ist warn oder error normalerweise ausreichend, um kritische Probleme zu erfassen, ohne die Protokolle zu überfluten.

http {
    server {
        # Standard-Zugriffsprotokoll für dynamische Inhalte
        access_log /var/log/nginx/access.log main;

        location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
            access_log off; # Protokollierung für gängige statische Dateien deaktivieren
            expires 30d;
        }
    }

    # Beispiel für ein gepuffertes Zugriffsprotokoll für den Haupt-HTTP-Kontext
    # access_log /var/log/nginx/access.log main buffer=16k flush=5s;
    error_log /var/log/nginx/error.log warn; # Nur Warnungen und Fehler protokollieren
}

7. Timeouts anpassen

Angemessen konfigurierte Timeouts verhindern, dass Nginx inaktive Verbindungen zu lange hält, und geben so Ressourcen frei.

Clientseitige Timeouts

  • client_body_timeout: Wie lange Nginx darauf wartet, dass ein Client den Anforderungstext sendet.
  • client_header_timeout: Wie lange Nginx darauf wartet, dass ein Client den Anforderungsheader sendet.
  • send_timeout: Wie lange Nginx darauf wartet, dass ein Client die Antwort akzeptiert, nachdem sie gesendet wurde.

Proxy-/FastCGI-Timeouts (falls zutreffend)

  • proxy_connect_timeout: Timeout für den Aufbau einer Verbindung zu einem proxysierten Server.
  • proxy_send_timeout: Timeout für das Senden einer Anfrage an den proxysierten Server.
  • proxy_read_timeout: Timeout für das Lesen einer Antwort vom proxysierten Server.
http {
    client_body_timeout 15s; # Client hat 15 Sekunden Zeit, den Text zu senden
    client_header_timeout 15s; # Client hat 15 Sekunden Zeit, Header zu senden
    send_timeout 15s; # Nginx hat 15 Sekunden Zeit, die Antwort an den Client zu senden

    # Für Proxy-Szenarien
    proxy_connect_timeout 5s; # 5 Sekunden für die Verbindung zum Upstream
    proxy_send_timeout 15s; # 15 Sekunden zum Senden der Anfrage an den Upstream
    proxy_read_timeout 15s; # 15 Sekunden zum Lesen der Antwort vom Upstream

    # Für FastCGI-Szenarien
    fastcgi_connect_timeout 5s;
    fastcgi_send_timeout 15s;
    fastcgi_read_timeout 15s;
}

8. SSL/TLS-Optimierung

Für HTTPS-fähige Websites ist die Optimierung der SSL/TLS-Einstellungen entscheidend, um den CPU-Overhead zu reduzieren und die Handshake-Leistung zu verbessern.

ssl_session_cache und ssl_session_timeout

Aktivieren Sie das SSL-Sitzungs-Caching, um den rechenintensiven vollständigen TLS-Handshake für nachfolgende Verbindungen desselben Clients zu vermeiden.

ssl_protocols und ssl_ciphers

Verwenden Sie moderne TLS-Protokolle wie TLSv1.2 und TLSv1.3. Seien Sie vorsichtig mit kopierten Cipher-Strings: TLS 1.3-Cipher werden nicht auf die gleiche Weise gesteuert wie ältere TLS-Cipher-Suiten, und die Standardeinstellungen der Distribution sind oft sicherer als veraltete Beispiele aus alten Anleitungen.

ssl_stapling

Aktiviert OCSP-Stapling, bei dem Nginx regelmäßig die OCSP-Antwort von der CA abruft und an den SSL/TLS-Handshake "heftet". Dies reduziert die clientseitige Latenz, da eine separate OCSP-Abfrage vermieden wird.

server {
    listen 443 ssl;
    ssl_certificate /etc/nginx/ssl/your_domain.crt;
    ssl_certificate_key /etc/nginx/ssl/your_domain.key;

    ssl_session_cache shared:SSL:10m; # Gemeinsamer Cache für 10 MB Sitzungsdaten
    ssl_session_timeout 10m; # Sitzungen laufen nach 10 Minuten ab

    ssl_protocols TLSv1.2 TLSv1.3; # Moderne, sichere Protokolle verwenden
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
    ssl_prefer_server_ciphers on;

    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 8.8.8.8 valid=300s; # Verwenden Sie für Ihre Umgebung zugelassene Resolver
    resolver_timeout 5s;
}

9. Open-File-Cache

Nginx kann Dateideskriptoren für häufig aufgerufene Dateien zwischenspeichern, wodurch die Notwendigkeit wiederholter Systemaufrufe zum Öffnen und Schließen von Dateien reduziert wird.

open_file_cache

Aktiviert den Cache und gibt die maximale Anzahl von Elementen an sowie wie lange inaktive Elemente verbleiben.

open_file_cache_valid

Legt fest, wie oft der Cache die Gültigkeit seiner Elemente überprüfen soll.

open_file_cache_min_uses

Gibt an, wie oft eine Datei innerhalb der inactive-Zeit mindestens aufgerufen werden muss, um im Cache zu bleiben.

open_file_cache_errors

Bestimmt, ob Nginx Fehler beim Öffnen von Dateien zwischenspeichern soll.

http {
    open_file_cache max=100000 inactive=60s; # Bis zu 100.000 Dateideskriptoren für 60s cachen
    open_file_cache_valid 80s; # Gültigkeit alle 80 Sekunden überprüfen
    open_file_cache_min_uses 1; # Dateien cachen, die mindestens einmal verwendet wurden
    open_file_cache_errors on; # Fehler im Zusammenhang mit dem Öffnen von Dateien cachen
}

10. Mit echten Traffic-Signalen validieren

Der letzte Punkt auf der Checkliste ist die Messung. Erfassen Sie vor einer Änderung eine kleine Basislinie: Anforderungslatenz, 5xx-Rate, aktive Verbindungen, CPU, Speicher, Festplatten-E/A, Netzwerkdurchsatz und Upstream-Antwortzeit. Vergleichen Sie nach der Änderung dieselben Zahlen.

Für einen Reverse-Proxy sind $request_time und $upstream_response_time besonders nützlich. Wenn beide zusammen steigen, ist das Backend wahrscheinlich langsam. Wenn $request_time hoch ist, während die Upstream-Zeit niedrig oder leer ist, überprüfen Sie die Client-Upload-Geschwindigkeit, die Antwortübertragungszeit, die Pufferung, die Komprimierung oder die Auslieferung statischer Dateien. Wenn keine der Metriken das Problem erklärt, überprüfen Sie das Fehlerprotokoll und das Betriebssystem.

Die sicherste Tuning-Reihenfolge ist einfach: Konfiguration mit nginx -t testen, nach Möglichkeit neu laden statt neu starten, Protokolle überwachen und schnell zurückrollen, wenn sich Latenz oder Fehler in die falsche Richtung bewegen. Nginx kann viel Traffic bewältigen, aber nur, wenn seine Grenzen, der Kernel und die Upstream-Anwendung miteinander übereinstimmen.