Назад | Перейти на главную страницу

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

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

Бег тест ab, Я могу выполнить 30 тыс. Запросов в секунду на слое лака (через 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;

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

Вот тест для 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-30k - израсходовали циклы моего процессора, средний ATM составляет 4-8k rps)

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

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

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

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

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

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

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

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

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

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

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

Сравнение лака открытого текста 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.

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

Цитирование Список инстансов Amazon EC2:

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

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

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