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

1

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

Executando o ab benchmark , posso obter 30k + solicitações / segundo na camada de verniz (via HTTP) por meio de uma instância EC2 t2.small. No entanto, quando executo o teste por meio do NGINX (HTTPS), só posso enviar 160 solicitações / segundo (média de 43ms para o TTFB a partir 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;

@ domain.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 o 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 o Varnish (ele estava rodando a 20-30k antes - usou 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á a referência para o NGINX via HTTP

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á a referência para o NGINX via HTTPS

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
    
por MKN Web Solutions 23.06.2015 / 00:22

1 resposta

2

Bem, a partir das informações que você tem (e não tem) fornecido, só posso adivinhar. Mas, a julgar pelo tipo de instância (t2 tem desempenho baseado em ticket expansível e quando sai de tickets, obtém cerca de 20% de um core; não é uma boa instância para fazer benchmarks) e o uso de ab para testing (btw. você escreve como 'teste AB', a primeira coisa que vem à mente é isso ) Eu diria que o seu o desempenho é praticamente o esperado.

Ao iniciar a sessão SSL ou TLS, a tarefa com o desempenho mais intenso não é a criptografia / descriptografia de dados, mas a troca de chaves. Como ab não usa o cache de sessão SSL, a troca de chaves deve ser feita em todas as conexões.

Dependendo da cifra / kex / auth suite realmente usada (não é possível dizer, não há saída ab fornecida), isso pode ser bastante trabalho para a CPU. E como ambas as extremidades estão na mesma máquina, você duplica os requisitos de CPU por conexão (é uma simplificação, mas é bom o suficiente aqui).

No mundo real, manter alives pode ajudá-lo a obter melhor desempenho (depende do cliente, navegadores normais o usam; tente ab -k ). E você obterá um melhor desempenho do caching de sessão SSL mencionado (novamente depende do cliente, os navegadores normais o suportam).

Existem várias outras maneiras que ajudarão você a melhorar seu desempenho. Claro que você pode obter um hardware melhor. Você pode otimizar seus tamanhos de chave (depende do nível de proteção necessário para o aplicativo) - chaves menores geralmente são mais baratas de se trabalhar. O teste de uma máquina diferente pode ou não melhorar o desempenho aparente. E obter uma compilação OpenSSL diferente, ou uma biblioteca SSL diferente, poderia também fornecer melhor desempenho.

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

Embora, 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 exemplo, o Apache JMeter usa o cache de contexto ssl. O link também funciona. Acho especialmente bom o JMeter em simular cargas reais. Mas, para esse modo httperf de cache de sessão, pode funcionar melhor.

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

Dependendo da sua percepção de massa, mas eu não esperaria obter mais do que cerca de 500 conexões por segundo em rajadas neste pequeno exemplo e não mais de 250 cps sustentados.

Comparar o texto simples do verniz http com o nginx ssl é comparar pêras com maçãs. Ou melhor, comparar blueberries a melancias em termos de requisitos de hardware.

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

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 (é o que o Varnish está fazendo) é tão fácil quanto possível. Você analisa os cabeçalhos, encontra o conteúdo na memória, cuspiu. E o verniz se destaca nisso.

Estabelecer conexão criptografada é um nível completamente diferente. Então, quando você adiciona nginx, ele precisa fazer o handshake SSL (troca de chaves, autenticação) e criptografia, o que requer muito mais recursos. Em seguida, analisa os cabeçalhos. Então tem que criar outra conexão TCP para o Verniz.

Mais uma vez, no Intel® já mencionado , eles têm 28 núcleos e fizeram alguns ajustes no 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.

Citando lista de instâncias do Amazon EC2 :

For example, a t2.small instance receives credits continuously at a rate of 12 CPU Credits per hour. This capability provides baseline performance equivalent to 20% of a CPU core.

E ainda outro documento do próprio nginx:

Summary of Results A single virtualized Intel core can typically perform up to 350 full 2048-bit SSL handshake operations per second, using modern cryptographic ciphers. This equates to several hundred new users of your service per second per core.

    
por 23.06.2015 / 19:28