NGINX HTTPS Reverse Proxy – Schnelle TTFB, aber geringe Parallelität

NGINX HTTPS Reverse Proxy – Schnelle TTFB, aber geringe Parallelität

Ich habe eine Anwendung, die Folgendes ausführt: NGINX (SSL) => VARNISH (CACHE) => APACHE/PHP.

Läuftab benchmark, ich kann über eine EC2 t2.small-Instanz auf Varnish-Ebene (über HTTP) über 30.000 Anfragen/Sekunde erreichen. Wenn ich den Test jedoch über NGINX (HTTPS) ausführe, kann ich nur 160 Anfragen/Sekunde senden (durchschnittlich 43 ms für TTFB aus dem öffentlichen Web).

@ nginx.conf

user  nginx;
worker_processes  auto;

worker_rlimit_nofile 65535;

error_log  /var/log/nginx/error.log;

pid        /var/run/nginx.pid;


events {
    worker_connections  16024;
        multi_accept on;
}

und auf http-Ebene:

sendfile        on;
tcp_nopush     on;

keepalive_timeout  10;


ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

@ Domäne.conf

server {
        listen 443 ssl;

        server_name xyz.com;
        ssl_certificate /home/st/ssl3/xyz.crt;
        ssl_certificate_key /home/xyz/ssl3/xyz.key;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

        ssl_session_tickets on;

        location / {

                proxy_buffers 8 8k;
                proxy_buffer_size 2k;


            proxy_pass http://127.0.0.1:79;
            proxy_set_header X-Real-IP  $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Port 443;
            proxy_set_header Host $host;

                proxy_redirect off;

        }

    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
}

Hier ist der Benchmark für Apache direkt

INTERN => @APACHE:

Concurrency Level:      10
Time taken for tests:   0.694 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1002
Keep-Alive requests:    996
Total transferred:      705122 bytes
HTML transferred:       401802 bytes
Requests per second:    1440.93 [#/sec] (mean)
Time per request:       6.940 [ms] (mean)
Time per request:       0.694 [ms] (mean, across all concurrent requests)
Transfer rate: 992.22 [Kbytes/sec] received

Hier ist der Benchmark für Varnish (vorher lief es mit 20-30.000 – das hat meine CPU-Zyklen aufgebraucht, der durchschnittliche ATM liegt bei 4-8.000 RPS)

INTERN => @VARNISH => @APACHE:

Concurrency Level:      10
Time taken for tests:   0.232 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      23439800 bytes
HTML transferred:       23039412 bytes
Requests per second:    4310.16 [#/sec] (mean)
Time per request:       2.320 [ms] (mean)
Time per request:       0.232 [ms] (mean, across all concurrent requests)
Transfer rate:          98661.39 [Kbytes/sec] received

Hier ist der Benchmark für NGINX überHTTP

INTERN => @NGINX[HTTP] => @VARNISH => @APACHE:

Concurrency Level:      10
Time taken for tests:   0.082 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1001
Keep-Alive requests:    1000
Total transferred:      382382 bytes
HTML transferred:       184184 bytes
Requests per second:    12137.98 [#/sec] (mean)
Time per request:       0.824 [ms] (mean)
Time per request:       0.082 [ms] (mean, across all concurrent requests)
Transfer rate:          4532.57 [Kbytes/sec] received

Hier ist der Benchmark für NGINX überHTTPS

INTERN => @NGINX[HTTPS=>HTTP] => @VARNISH => @APACHE:

Concurrency Level:      10
Time taken for tests:   7.029 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1000
Keep-Alive requests:    0
Total transferred:      663000 bytes
HTML transferred:       401000 bytes
Requests per second:    142.27 [#/sec] (mean)
Time per request:       70.288 [ms] (mean)
Time per request:       7.029 [ms] (mean, across all concurrent requests)
Transfer rate:          92.12 [Kbytes/sec] received

Antwort1

Nun, anhand der Informationen, die Sie bereitgestellt haben (und nicht bereitgestellt haben), kann ich nur raten. Aber wenn man den Instanztyp (t2 hat eine auf Tickets basierende Burst-Performance und wenn keine Tickets mehr vorhanden sind, erhält es etwa 20 % eines Kerns; es ist keine gute Instanz, um Benchmarks durchzuführen) und die Verwendung abfür Tests (übrigens, wenn Sie es als „AB-Test“ schreiben, fällt mir als Erstes ein:Das) Ich würde sagen, Ihre Leistung entspricht ziemlich genau Ihren Erwartungen.

Beim Starten einer SSL- oder TLS-Sitzung ist nicht die Datenverschlüsselung/-entschlüsselung die leistungsintensivste Aufgabe, sondern der Schlüsselaustausch. Da abkein SSL-Sitzungs-Caching verwendet wird, muss der Schlüsselaustausch bei jeder Verbindung durchgeführt werden.

Abhängig von der tatsächlich verwendeten Cipher/Kex/Auth-Suite (kann ich nicht sagen, es wird keine abAusgabe bereitgestellt) kann das ziemlich viel Arbeit für die CPU bedeuten. Und da sich beide Enden auf derselben Maschine befinden, verdoppeln Sie die CPU-Anforderungen pro Verbindung (das ist eine Vereinfachung, aber hier gut genug).

In der Praxis können Keep-Alives zu einer besseren Leistung führen (hängt vom Client ab, normale Browser verwenden es; versuchen Sie es ab -k). Und Sie erzielen eine bessere Leistung durch das von Ihnen erwähnte SSL-Sitzungs-Caching (hängt auch hier vom Client ab, normale Browser unterstützen es).

Es gibt noch mehrere andere Möglichkeiten, die Ihnen helfen, Ihre Leistung zu verbessern. Natürlich können Sie sich bessere Hardware zulegen. Sie können Ihre Schlüsselgrößen optimieren (hängt von der für die App erforderlichen Schutzstufe ab) – kleinere Schlüssel sind in der Regel günstiger. Tests auf unterschiedlichen Rechnern können die scheinbare Leistung verbessern, müssen es aber nicht. Und ein anderer OpenSSL-Build oder eine andere SSL-Bibliothek insgesamt könnten ebenfalls eine bessere Leistung bringen.

Nur als Referenz können Sie einen Blick werfen aufdieses Papiervon Intel. Sie vergleichen die Leistung auf einem hochoptimierten Rechner (und einiger optimierter Software). Bedenken Sie, dass Ihnen weniger als 1/30 ihrer Rechenleistung zur Verfügung steht (könnte bis zu 1/150 sein, wenn Sie keine Tickets mehr haben).

Wenn Sie jedoch leistungsstarkes SSL benötigen, lohnt es sich möglicherweise, Amazon ELB mit der SSL-Terminierung zu beauftragen, da Sie bereits EC2 verwenden.

Bearbeiten: Zum BeispielApache JMeterverwendet SSL-Kontext-Caching.httperftut das auch. Ich finde, dass JMeter besonders gut darin ist, realitätsnahe Lasten zu simulieren. Aber dafür könnte die httperf-Methode des Session-Cachings am besten funktionieren.

Wenn Sie keinen Unterschied sehen, -kliegt das vielleicht daran, dass es immer noch nicht verwendet wird. Hängt von den Parallelitätseinstellungen ab und (zumindest auf meinem Computer) scheint es auch von der URL abzuhängen. Es werden keine Keepalives verwendet, wenn ich einen Domänennamen verwende, der auf mehr als eine IP in der URL verweist (fragen Sie mich nicht, warum).

Es hängt davon ab, was Sie unter massiv verstehen, aber ich würde bei dieser eher kleinen Instanz nicht mehr als etwa 500 Verbindungen pro Sekunde in Schüben und nicht mehr als 250 cps dauerhaft erwarten.

Der Vergleich von Varnish Plaintext HTTP mit Nginx SSL ist wie ein Vergleich von Birnen mit Äpfeln. Oder eher ein Vergleich von Blaubeeren mit Wassermelonen, was die Hardwareanforderungen betrifft.

Nochmals zu Ihrer Information (beachten Sie die Keep-Alive requests: 100Zeile).

Ohne-k

Concurrency Level:      1
Time taken for tests:   0.431 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      399300 bytes
HTML transferred:       381200 bytes
Requests per second:    232.26 [#/sec] (mean)
Time per request:       4.305 [ms] (mean)
Time per request:       4.305 [ms] (mean, across all concurrent requests)
Transfer rate:          905.69 [Kbytes/sec] received

Mit-k

Concurrency Level:      1
Time taken for tests:   0.131 seconds
Complete requests:      100
Failed requests:        0
Keep-Alive requests:    100
Total transferred:      402892 bytes
HTML transferred:       381200 bytes
Requests per second:    762.11 [#/sec] (mean)
Time per request:       1.312 [ms] (mean)
Time per request:       1.312 [ms] (mean, across all concurrent requests)
Transfer rate:          2998.53 [Kbytes/sec] received

Edit2: Nun, Sie müssen verstehen, dass das Bereitstellen von Inhalten direkt aus dem Speicher (das ist, was Varnish macht) so einfach ist, wie es nur sein kann. Sie analysieren die Header, Sie finden den Inhalt im Speicher, Sie geben ihn aus. Und Varnish ist darin hervorragend.

Das Herstellen einer verschlüsselten Verbindung ist eine ganz andere Ebene. Wenn Sie also nginx hinzufügen, muss es den SSL-Handshake (Schlüsselaustausch, Authentifizierung) und die Verschlüsselung durchführen, was viel mehr Ressourcen erfordert. Dann analysiert es die Header. Dann muss es eine weitere TCP-Verbindung zu Varnish herstellen.

Nochmals in dem oben erwähntenIntel-Papier, sie haben 28 Kerne und haben einige Optimierungen an ihrem OpenSSL vorgenommen, um 38.000 HTTPS-CPS zu erreichen (etwas mehr als Ihre Varnish-Leistung). Sie haben etwa 1/5 eines Kerns und werden von Ihren virtuellen Nachbarn beeinflusst.

ZitierenAmazon EC2-Instanzliste:

Beispielsweise erhält eine t2.small-Instanz kontinuierlich Credits mit einer Rate von 12 CPU-Credits pro Stunde. Diese Funktion bietet eine Basisleistung, die 20 % eines CPU-Kerns entspricht.

Und noch ein weitererPapiervon nginx selbst:

Zusammenfassung der Ergebnisse Ein einzelner virtualisierter Intel-Kern kann unter Verwendung moderner kryptografischer Chiffren typischerweise bis zu 350 vollständige 2048-Bit-SSL-Handshake-Operationen pro Sekunde durchführen. Dies entspricht mehreren hundert neuen Benutzern Ihres Dienstes pro Sekunde und Kern.

verwandte Informationen