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

Включение HTTP / 2 значительно замедляет работу сайта в nginx

После включения HTTP / 2 на моем веб-сайте я обнаружил, что производительность резко упала. Скорость загрузки становится намного ниже, а запросы больших изображений блокируют другие вызовы API.

Вот пример веб-страницы, иллюстрирующий эту проблему:

<img src="img.jpg">
<script>
for(var i=0;i<50;i++)
    setTimeout(()=>{
        fetch('foo.txt');
    },i*100);
</script>

(img.jpg это изображение размером ~ 700 КБ и foo.txt это небольшой текстовый файл. Все обслуживается прямо из nginx.)

Вот график временной шкалы, когда HTTP / 2 НЕ включен (listen 443 ssl):

... и когда HTTP / 2 включен (listen 443 ssl http2):

Вы можете видеть, что HTTP / 2 вызывает большее время загрузки обоих img.jpg и foo.txt.

Вот конфигурация сайта:

server {
    listen 443 ssl http2; # when performing http2 example
    # listen 443 ssl; # when performing http1 example
    server_name h2.test.**********;
    root /home/******/h2-test/;
}

Я использую nginx 1.14.2 в Ubuntu 16.04.6 LTS. У вас есть предложения по устранению этой проблемы?

Ниже приводится в основном «теоретический» ответ:

Я полагаю, что вы наблюдаете двойную проблему: характер вашего теста (запрос особенно небольших файлов) и поведение / реализация HTTP / 2 в Chrome.

Если вы посмотрите на свое изображение HTTP / 2, вы увидите, что довольно много (18) запросов завершаются одновременно. Это может сказать вам, что даже если они не запускаются одновременно, они работают параллельно.

Посредством природа мультиплексирования HTTP / 2:

можно даже смешивать части одного сообщения с другим по сети

Таким образом, похоже, что это то, что делает Chrome - видит незавершенный запрос к серверу и пытается параллельно сделать другой запрос через то же мультиплексное соединение.

По какой-то причине у вашего сервера есть своего рода проблема "масштабирования" с параллельными запросами.

Вы сказали, что foo.txt это небольшой файл, но насколько он маленький?

Там есть http2_chunk_size директива (значение по умолчанию 8k), что означало бы, что ответ HTTP / 2 разбивается на куски такого размера, и если запросы действительно выполняются параллельно, и foo.txt меньше чем 8k, то это приведет к "ожиданию" одного запроса на foo.txt выполнить еще один запрос на foo.txt, пока в общей сложности 8k chunk накапливается для вывода в браузер.

Я бы предложил поиграть с этой директивой и уменьшить ее до меньшего размера, чем запрошенный размер файла, и / или повторить тесты с текстовым файлом, размер которого превышает 8k.

Наконец, если соединение ненадежно, вы можете столкнуться с проблемой блокировки TCP HOL, которая хуже для HTTP / 2. Цитировать Вот:

Но есть ли сценарии, когда это может ухудшить ситуацию? Да. Причина в том, что приложения, использующие HTTP / 2, могут отправлять гораздо больше запросов по одному TCP-соединению из-за функций конвейерной обработки / мультиплексирования. Неожиданно большие различия в задержке или потеря, влияющая на сегмент в начале линии TCP, повышают вероятность попадания HTTP / 2 в HOLB, и его влияние также больше. По сути, получатель простаивает, пока голова не будет восстановлена, а все последующие сегменты удерживаются стеком TCP. Это означает, что изображение может быть успешно загружено и по-прежнему не отображаться из-за HOLB.