Обратный прокси-сервер NGINX HTTPS — быстрый TTFB, но низкий уровень параллелизма

Обратный прокси-сервер NGINX HTTPS — быстрый TTFB, но низкий уровень параллелизма

У меня есть приложение, которое работает: NGINX (SSL) => VARNISH (CACHE) => APACHE/PHP.

Бегab бенчмарк, я могу достичь 30k+ запросов / секунду на слое Varnish (через HTTP) через экземпляр EC2 t2.small. Однако, когда я запускаю тест через NGINX (HTTPS), я могу отправить только 160 запросов / секунду (в среднем 43 мс для TTFB из публичного веба).

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

и на уровне http:

sendfile        on;
tcp_nopush     on;

keepalive_timeout  10;


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

@ домен.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";
}

Вот бенчмарк для Apache напрямую

ВНУТРЕННИЙ => @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

Вот тест производительности Varnish (раньше он работал на скорости 20-30 тыс. об/с — израсходовал циклы моего ЦП, средняя скорость ATM составляет 4-8 тыс. об/с)

ВНУТРЕННИЙ => @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

Вот бенчмарк для NGINX черезHTTP

ВНУТРЕННИЙ => @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

Вот бенчмарк для NGINX черезHTTPS

ВНУТРЕННИЙ => @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

решение1

Ну, из информации, которую вы предоставили (и не предоставили), я могу только догадываться. Но судя по типу экземпляра (у t2 производительность на основе билетов, которая может быть увеличена, и когда билетов нет, он получает около 20% ядра; это неподходящий экземпляр для проведения бенчмарков) и использования abдля тестирования (кстати, когда вы пишете это как «AB-тестирование», первое, что приходит на ум, этоэтот) Я бы сказал, что ваше выступление вполне соответствует ожиданиям.

При запуске сеанса SSL или TLS наиболее производительной задачей является не шифрование/дешифрование данных, а обмен ключами. Поскольку abне используется кэширование сеанса SSL, обмен ключами должен выполняться при каждом подключении.

В зависимости от фактически используемого набора шифров/kex/auth (не могу сказать, abвывод не предоставлен), это может быть довольно большой работой для ЦП. И поскольку оба конца находятся на одной машине, вы удваиваете требования к ЦП на соединение (это упрощение, но здесь оно достаточно хорошее).

В реальном мире keep alive может помочь вам получить лучшую производительность (зависит от клиента, обычные браузеры используют его; попробуйте ab -k). И вы получите лучшую производительность от кэширования сеанса SSL, о котором вы упомянули (опять же зависит от клиента, обычные браузеры его поддерживают).

Есть несколько других способов, которые помогут вам улучшить производительность. Конечно, вы можете получить лучшее оборудование. Вы можете оптимизировать размеры ключей (зависит от уровня защиты, необходимого для приложения) — с меньшими ключами обычно дешевле работать. Тестирование с другой машины может улучшить или не улучшить видимую производительность. А получение другой сборки OpenSSL или другой библиотеки SSL в целом также может обеспечить лучшую производительность.

Просто для справки, вы можете взглянуть наЭта бумагаот Intel. Они сравнивают производительность на высокооптимизированной машине (и некотором оптимизированном программном обеспечении). Предположим, что у вас менее 1/30 их вычислительной мощности (может быть и 1/150, если у вас закончились билеты).

Однако если вам нужен высокопроизводительный SSL, возможно, стоит рассмотреть возможность использования Amazon ELB для выполнения терминации SSL, поскольку вы уже используете EC2.

Редактировать: НапримерApache JMeterиспользует кэширование контекста SSL.httperfделает также. Я нахожу JMeter особенно хорошим для симуляции реальных нагрузок. Но для этого httperf способ кэширования сеанса мог бы работать лучше всего.

Не вижу никакой разницы с , -kвозможно, потому что он все еще не используется. Зависит от настроек параллелизма и (по крайней мере на моей машине) похоже, что также зависит от URL. Он не использует keepalives, если я использую доменное имя, которое указывает на более чем один IP в URL (не спрашивайте меня, почему).

В зависимости от вашего восприятия масштабности, я бы не ожидал получить более 500 соединений в секунду в пакетном режиме на этом довольно маленьком экземпляре и не более 250 cps в устойчивом режиме.

Сравнивать Varnish plaintext http с nginx ssl — это сравнивать груши с яблоками. Или, скорее, сравнивать чернику с арбузами с точки зрения требований к оборудованию.

Еще раз для справки (обратите внимание на Keep-Alive requests: 100строку).

Без-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

С-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: Ну, вам нужно понять, что обслуживание контента напрямую из памяти (именно это делает Varnish) — это так просто, как только можно. Вы анализируете заголовки, находите контент в памяти, выплевываете его. И Varnish в этом преуспевает.

Установка зашифрованного соединения — это совершенно другой уровень. Поэтому после добавления nginx ему придется выполнить SSL-рукопожатие (обмен ключами, аутентификация) и шифрование, что требует гораздо больше ресурсов. Затем он анализирует заголовки. Затем ему придется создать еще одно TCP-соединение с Varnish.

Опять же, в вышеупомянутомИнтел бумага, у них 28 ядер, и они немного подправили свой OpenSSL, чтобы сделать 38k HTTPS cps (немного больше, чем производительность Varnish). У вас около 1/5 ядра, и на вас влияют ваши виртуальные соседи.

ЦитатаСписок экземпляров Amazon EC2:

Например, экземпляр t2.small получает кредиты непрерывно со скоростью 12 CPU Credits в час. Эта возможность обеспечивает базовую производительность, эквивалентную 20% ядра CPU.

И еще одинбумагаот самого nginx:

Резюме результатов Одно виртуализированное ядро ​​Intel обычно может выполнять до 350 полных 2048-битных операций SSL-рукопожатия в секунду, используя современные криптографические шифры. Это эквивалентно нескольким сотням новых пользователей вашего сервиса в секунду на ядро.

Связанный контент