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

Nginx request_time медленнее с HTTP / 2

Мы запускаем nginx / 1.9.10 в качестве внешнего сервера с несколькими серверами приложений в качестве восходящего. Мы используем простой http, в основном https, и перешли на http / 2 в последнем слабом.

Мы ведем журнал так:

 log_format custom '$host $server_port $request_time '
                   '$upstream_response_time $remote_addr '
                   '"$http2" $upstream_addr $time_iso8601 '
                   '"$request" $status $body_bytes_sent '
                   '"$http_referer" "$http_user_agent"';

Мы внезапно видим большую разницу между $ request_time и $ upstream_response_time. Разница здесь вполне естественна, так как $ request_time зависит от сети пользователя, а upstream_response_time - нет.

Поэтому обычно вам не следует слишком заботиться о $ request_time, если $ upstream_response_time стабильно.

Но я все еще хотел проверить, что происходит, потому что с http / 2 ситуация ухудшалась, поэтому я сравнил среднее время ответа для https / 1.1 и https / 2.0.

Сначала я обработал все запросы http / 1.1 и вычислил среднее время ответа и среднее время восходящего потока:

grep ' 443 ' access.log|grep 'HTTP/1.1'|\ 
cut -d ' ' -f 3,4 | awk '{r+=$1; u+=$2} END {print r/NR; print u/NR}'

0.0139158  # average response time for https/1.1
0.00691421 # average upstream time for https/1.1

Теперь я сделал то же самое с https / 2.0:

grep ' 443 ' access.log|grep 'HTTP/2.0'| \
cut -d ' ' -f 3,4 | awk '{r+=$1; u+=$2} END {print r/NR; print u/NR}'
0.0828755  # average response time for https/1.1
0.00606643 # average upstream time for https/2.0

Как видите, время восходящего потока почти идентично, но время запроса для http / 2 медленнее в 7 раз! Вот Это Да! Разве http / 2 не будет быстрее?

Теперь я проверил все запросы, которые имеют огромную разницу между этими двумя значениями, и почти все из топ-500 имеют код состояния 302.

grep ' 443 ' access.log | grep 'HTTP/1.1' | \
awk '{ if ( $3 != $4 && $4 != "-" ) { \
  gsub(/\./,"",$3);gsub(/\./,"",$4); \
  print $3-$4,$4,$6,$9,$11,$12 }}' | \
sort -n | tail -n 10000 | grep 'POST HTTP/1.1" 302' | wc -l

9008 
# of 10000 (or 90%) request ordered by difference between 
# response and request time have status code 302  

Таким образом, 90% всех запросов с наибольшей разницей между временем ответа и временем восходящего потока имеют код состояния 302. Это странно.

На http / 2 еще хуже:

grep ' 443 ' access.log | grep 'HTTP/2.0' | \
awk '{ if ( $3 != $4 && $4 != "-" ) { \
  gsub(/\./,"",$3);gsub(/\./,"",$4); \
  print $3-$4,$4,$6,$9,$11,$12 }}' | \
sort -n | tail -n 10000 | grep 'POST HTTP/2.0" 302' | wc -l

9790
# of 10000 (or 98%) request ordered by difference between 
# response and request time have status code 302  

Итак, 98% этих запросов имеют статус 302.

Почему http / 2 работает медленнее, чем http / 1.1? Почему так много кодов состояния 302, участвующих в запросах, были в восходящем направлении, а время ответа сильно различается (в HTTP / 1.1 и HTTP / 2.0)?

Квест мне очень понравился, я его проанализировал.

В основном я использовал эти ресурсы: [https://www.nginx.com/blog/nginx-1-9-5/ ] [https://www.nginx.com/blog/http2-module-nginx/ ] [https://blog.cloudflare.com/introduction-http2/ ] [https://http2.github.io/faq/ ] и этот PDF

Вероятно, вы скачали nginx / 1.9.10 с Nginx.org http://nginx.org/en/download.html. Пожалуйста подтвердите. Вы построили это из исходников? Вы пробовали nginx / 1.9.12?

Как вы можете видеть в статье CloudFlare при измерении Average Page Load time HTTP / 2 явно победитель (по крайней мере, для их веб-сайта).

Access via HTTP Protocol Version    Average Page Load time
HTTP 1.x                            9.07 sec.
SPDY/3.1                            7.06 sec.
HTTP/2                              4.27 sec. 

Однако при отслеживании среднего времени ответа ознакомьтесь со второй статьей с Nginx.org, которую я установил в качестве справочной, где она гласит:

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

Недостатком здесь является то, что, поскольку каждый блок данных имеет свою собственную идентификацию, свои собственные поля, есть некоторые метаданные, которые передаются в дополнение к фактическим данным. Итак, у него есть накладные расходы.

Другие проблемы могут быть связаны с настройкой nginx, например, внутри серверного блока.