Proxy reverso NGINX HTTPS - TTFB rápido, mas baixa simultaneidade

Proxy reverso NGINX HTTPS - TTFB rápido, mas baixa simultaneidade

Eu tenho um aplicativo que roda: NGINX (SSL) => VARNISH (CACHE) => APACHE/PHP.

Correndoreferência ab, consigo atingir mais de 30 mil solicitações/segundo na camada de verniz (via HTTP) por meio de uma instância EC2 t2.small. Porém, quando executo o teste através do NGINX (HTTPS), só consigo enviar 160 solicitações/segundo (média de 43ms para TTFB da web pública).

@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;
}

e no nível http:

sendfile        on;
tcp_nopush     on;

keepalive_timeout  10;


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

@ domínio.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";
}

Aqui está o benchmark para Apache diretamente

INTERNO => @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

Aqui está o benchmark para Varnish (ele estava rodando entre 20-30k anteriormente - consumiu meus ciclos de CPU, o ATM médio é de 4-8k rps)

INTERNO => @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

Aqui está o benchmark para NGINX viaHTTP

INTERNO => @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

Aqui está o benchmark para NGINX viaHTTPS

INTERNO => @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

Responder1

Bem, com base nas informações que você forneceu (e não forneceu), só posso adivinhar. Mas, a julgar pelo tipo de instância (t2 tem desempenho baseado em tickets expansíveis e, quando sem tickets, obtém cerca de 20% de um núcleo; não é uma boa instância para fazer benchmarks) e o uso de abpara testes (aliás. quando você o escreve como 'teste AB', a primeira coisa que vem à mente éesse) Eu diria que seu desempenho está praticamente dentro do esperado.

Ao iniciar uma sessão SSL ou TLS, a tarefa que exige mais desempenho não é a criptografia/descriptografia de dados, mas a troca de chaves. Como abnão utiliza cache de sessão SSL, a troca de chaves deve ser feita em todas as conexões.

Dependendo do conjunto de cifra/kex/auth realmente usado (não sei dizer, nenhuma absaída é fornecida), isso pode ser bastante trabalhoso para a CPU. E como ambas as extremidades estão na mesma máquina, você dobra os requisitos de CPU por conexão (é uma simplificação, mas é suficiente aqui).

No uso no mundo real, keep alives pode ajudá-lo a obter melhor desempenho (depende do cliente, navegadores normais o utilizam; tente ab -k). E você obterá melhor desempenho com o cache de sessão SSL mencionado (novamente depende do cliente, navegadores normais suportam).

Existem várias outras maneiras que ajudarão você a melhorar seu desempenho. Claro que você pode obter hardware melhor. Você pode otimizar o tamanho das chaves (depende do nível de proteção necessário para o aplicativo) - chaves menores geralmente são mais baratas para trabalhar. Testar em máquinas diferentes pode ou não melhorar o desempenho aparente. E obter uma compilação OpenSSL diferente, ou uma biblioteca SSL completamente diferente, também pode fornecer melhor desempenho.

Apenas para referência, você pode dar uma olhada emeste papelpela Intel. Eles comparam o desempenho em uma máquina altamente otimizada (e em alguns softwares otimizados). Considere que você tem menos de 1/30 do poder de computação disponível (pode ser tão baixo quanto 1/150 se você estiver sem ingressos).

Porém, se você precisar de SSL de alto desempenho, pode valer a pena considerar o uso do Amazon ELB para fazer a terminação SSL para você, já que você já está no EC2.

Editar: por exemploApache JMeterusa cache de contexto SSL.httperftambém faz. Acho especialmente o JMeter bom em simular cargas semelhantes à vida real. Mas para esse modo httperf de cache de sessão poderia funcionar melhor.

Não ver nenhuma diferença -kpode ser porque ainda não foi usado. Depende das configurações de simultaneidade e (pelo menos na minha máquina) parece depender também do URL. Ele não usa keepalives se eu usar um nome de domínio que aponte para mais de um IP na URL (não me pergunte por quê).

Dependendo da sua percepção de massivo, eu não esperaria obter mais do que cerca de 500 conexões por segundo em rajadas nesta instância bastante pequena e não mais do que 250 cps sustentados.

Comparar o http de texto simples do verniz com o nginx SSL é comparar peras com maçãs. Ou melhor, comparar mirtilos com melancias em termos de requisitos de hardware.

Novamente para sua referência (observe a Keep-Alive requests: 100linha).

Sem-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

Com-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: Bem, você precisa entender que servir conteúdo diretamente da memória (é isso que o Varnish está fazendo) é o mais fácil possível. Você analisa os cabeçalhos, encontra o conteúdo na memória e cospe-o. E o verniz é excelente nisso.

Estabelecer uma conexão criptografada é um nível completamente diferente. Assim, depois de adicionar o nginx, ele terá que fazer o handshake SSL (troca de chaves, autenticação) e a criptografia, que exigem muito mais recursos. Em seguida, ele analisa os cabeçalhos. Então ele tem que criar outra conexão TCP com o Varnish.

Novamente, no mencionadoArtigo da Intel, eles têm 28 núcleos e fizeram alguns ajustes em seu OpenSSL para fazer 38k HTTPS cps (um pouco mais do que o desempenho do Varnish). Você tem cerca de 1/5 de um núcleo e é afetado por seus vizinhos virtuais.

CitandoLista de instâncias do Amazon EC2:

Por exemplo, uma instância t2.small recebe créditos continuamente a uma taxa de 12 créditos de CPU por hora. Esse recurso fornece desempenho básico equivalente a 20% de um núcleo de CPU.

E ainda outropapeldo próprio nginx:

Resumo dos resultados Um único núcleo Intel virtualizado normalmente pode executar até 350 operações completas de handshake SSL de 2.048 bits por segundo, usando cifras criptográficas modernas. Isso equivale a várias centenas de novos usuários do seu serviço por segundo, por núcleo.

informação relacionada