HTTP2 с node.js за прокси-сервером nginx

У меня есть сервер node.js, работающий за прокси-сервером nginx. node.js использует сервер HTTP 1.1 (без SSL) на порту 3000. Оба они работают на одном сервере.

Недавно я настроил nginx для использования HTTP2 с SSL (h2). Похоже, что HTTP2 действительно включен и работает.

Однако, я хочу знать, влияет ли использование прокси-соединения (nginx ↔ node.js) на HTTP 1.1. То есть, я пропускаю преимущества HTTP2 с точки зрения скорости, потому что мое внутреннее соединение - HTTP 1.1?

Ответ 1

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

Для внутренних соединений (например, между веб-сервером, действующим в качестве обратного прокси-сервера и внутренними серверами приложений) задержка, как правило, очень, очень мала, поэтому преимущества HTTP/2 в скорости незначительны. Кроме того, каждый сервер приложений, как правило, уже будет отдельным соединением, поэтому опять-таки никакой выгоды здесь нет.

Таким образом, вы получите большую часть выигрыша в производительности от поддержки HTTP/2 на самом краю. Это довольно распространенная установка - аналогично тому, как HTTPS часто завершается на обратном прокси-сервере/балансировщике нагрузки, а не проходит весь путь до конца.

Однако есть потенциальные преимущества для поддержки HTTP/2 на всем пути. Например, это может позволить серверу протолкнуть весь путь из приложения. Также потенциальные выгоды от уменьшенного размера пакета для этого последнего прыжка из-за двоичной природы HTTP/2 и сжатия заголовка. Хотя, как и задержка, пропускная способность, как правило, менее важна для внутренних соединений, поэтому важность этого спорна. Наконец, некоторые утверждают, что обратный прокси-сервер работает меньше при подключении соединения HTTP/2 к соединению HTTP/2, чем при соединении HTTP/1.1, поскольку нет необходимости преобразовывать один протокол в другой, хотя я скептически отношусь к этому, даже если это заметно, поскольку они являются отдельными соединениями (если только они не действуют как проход TCP через прокси). Итак, для меня главная причина сквозного HTTP/2 состоит в том, чтобы разрешить сквозной серверный Push, но даже это, вероятно, лучше обрабатывать с помощью заголовков HTTP-ссылок и 103-ранних подсказок из-за сложностей в управлении push-сообщениями между несколькими соединениями.,

На данный момент, хотя серверы все еще добавляют поддержку, а использование проталкивания серверов низкое (и все еще экспериментируют, чтобы определить лучшие практики), я бы рекомендовал использовать только HTTP/2 в конечной точке. На момент написания этой статьи Nginx также не поддерживает HTTP/2 для соединений ProxyPass (хотя Apache делает это) и не планирует добавлять это, и они представляют интересный вопрос о том, может ли одно соединение HTTP/2 создавать медлительность. (выделение мое):

Планируется ли поддержка HTTP/2 прокси на ближайшее будущее?

Короткий ответ:

Нет, планов нет.

Длинный ответ:

Практически нет смысла его реализовывать, поскольку основное преимущество HTTP/2 заключается в том, что он позволяет мультиплексировать множество запросов в одном соединении, тем самым [почти] снимая ограничение на количество simalteneous-запросов - и при разговоре с ним такого ограничения нет ваши собственные бэкэнды. Более того, при использовании HTTP/2 для бэкэндов дела могут ухудшиться из-за использования одного соединения TCP вместо нескольких.

С другой стороны, реализация протокола HTTP/2 и мультиплексирования запросов в одном соединении в вышестоящем модуле потребует серьезных изменений в вышестоящем модуле.

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

Наконец, следует также отметить, что, хотя браузеры требуют HTTPS для HTTP/2 (h2), большинство серверов не поддерживают и могут поддерживать этот последний переход по HTTP (h2c). Таким образом, не будет необходимости в сквозном шифровании, если оно отсутствует в части узла (как это часто бывает). Хотя, в зависимости от того, где внутренний сервер находится по отношению к внешнему серверу, использование HTTPS даже для этого соединения, возможно, следует учитывать, если трафик будет передаваться через незащищенную сеть (например, CDN на исходный сервер через Интернет).

Ответ 2

NGINX не поддерживает HTTP/2 в качестве клиента. Поскольку они работают на одном сервере и не имеют задержек или ограниченной пропускной способности, я не думаю, что это сильно изменило бы в любом случае. Я хотел бы убедиться, что вы используете keepalive между nginx и node.js.

https://www.nginx.com/blog/tuning-nginx/#keepalive

Ответ 3

NGINX теперь поддерживает HTTP2/Push, и это здорово...

Здесь я также выталкиваю favicon.ico, minified.css, minified.js, register.svg, purchase_litecoin.svg из моего статического поддоменов. Мне потребовалось некоторое время, чтобы понять, что я могу вытолкнуть из субдомена.

location / {
            http2_push_preload              on;
            add_header                      Link "<//static.yourdomain.io/css/minified.css>; as=style; rel=preload";
            add_header                      Link "<//static.yourdomain.io/js/minified.js>; as=script; rel=preload";
            add_header                      Link "<//static.yourdomain.io/favicon.ico>; as=image; rel=preload";
            add_header                      Link "<//static.yourdomain.io/images/register.svg>; as=image; rel=preload";
            add_header                      Link "<//static.yourdomain.io/images/purchase_litecoin.svg>; as=image; rel=preload";
            proxy_hide_header               X-Frame-Options;
            proxy_http_version              1.1;
            proxy_redirect                  off;
            proxy_set_header                Upgrade $http_upgrade;
            proxy_set_header                Connection "upgrade";
            proxy_set_header                X-Real-IP $remote_addr;
            proxy_set_header                Host $http_host;
            proxy_set_header                X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header                X-Forwarded-Proto $scheme;
            proxy_pass                      http://app_service;
        }

Ответ 4

Вы вообще не теряете производительность, потому что nginx соответствует мультиплексированию запроса, которое браузер выполняет через HTTP/2, создавая несколько одновременных запросов к вашему серверу node. (Одно из основных улучшений производительности HTTP/2 позволяет браузеру выполнять несколько одновременных запросов по одному и тому же соединению, тогда как в HTTP 1.1 возможен только один одновременный запрос на одно соединение, а браузеры также ограничивают количество подключений.)

Ответ 5

В случае, если кто-то ищет решение по этому вопросу, когда неудобно делать ваши службы совместимыми с HTTP2. Вот базовая конфигурация NGINX, которую вы можете использовать для преобразования службы HTTP1 в службу HTTP2.

server {
  listen [::]:443 ssl http2;
  listen 443 ssl http2;

  server_name localhost;
  ssl on;
  ssl_certificate /Users/xxx/ssl/myssl.crt;
  ssl_certificate_key /Users/xxx/ssl/myssl.key;

  location / {
    proxy_pass http://localhost:3001;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
  }
}