BLOG | NGINX

Presentación de HTTP/2 Server Push con NGINX 1.13.9

NGINX - Parte de F5 - horizontal, negro, tipo RGB
Miniatura de Owen Garrett
Owen Garrett
Publicado el 20 de febrero de 2018

NGINX Plus R15 también incluye soporte para push de servidor HTTP/2.

Nos complace anunciar que NGINX 1.13.9 , lanzado el 20 de febrero de 2018 , incluye soporte para push de servidor HTTP/2. Para los usuarios de NGINX Plus, la compatibilidad con servidores HTTP/2 se incluirá en la próxima versión de NGINX Plus R15 , programada para abril de 2018.

El envío de servidor, que se define en la especificación HTTP/2 , permite que un servidor envíe de manera preventiva recursos a un cliente remoto, anticipando que el cliente pueda solicitar esos recursos pronto. Al hacerlo, puede reducir potencialmente la cantidad de RTT (tiempo de ida y vuelta: el tiempo necesario para una solicitud y una respuesta) en una operación de carga de página en un RTT o más, lo que proporciona una respuesta más rápida al usuario.

El envío de archivos al servidor se puede utilizar para proporcionar a un cliente hojas de estilo, imágenes y otros recursos que necesitará para representar una página web. Debes tener cuidado de enviar únicamente los recursos que sean necesarios; no envíes recursos que un cliente probablemente ya tenga almacenados en caché.

En esta entrada del blog, describo:

Configuración de inserción del servidor HTTP/2

Para enviar recursos junto con la carga de una página, utilice la directiva http2_push de la siguiente manera:

servidor { # Asegúrese de que HTTP/2 esté habilitado para el servidor listen 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # siempre que un cliente solicite demo.html, también envíe # /style.css, /image1.jpg y /image2.jpg location = /demo.html { http2_push /style.css; http2_push /image1.jpg; http2_push /image2.jpg; } }

Verificación de inserción del servidor HTTP/2

Puede verificar fácilmente que el envío al servidor esté en vigor mediante cualquiera de dos métodos:

  • Las herramientas para desarrolladores en su navegador web
  • Un cliente HTTP/2 de línea de comandos como nghttp

Verificación con herramientas para desarrolladores (Google Chrome)

A continuación se explica cómo utilizar las herramientas para desarrolladores en su navegador web para verificar que el envío al servidor esté en vigor, utilizando Google Chrome como ejemplo. En la figura, la columna Iniciador de la pestaña Red de las Herramientas para desarrolladores de Chrome indica que se enviaron varios recursos al cliente como parte de una solicitud para /demo.html .

La columna Iniciador indica que se utilizó el servidor push para enviar recursos

Verificación con un cliente de línea de comandos ( nghttp )

Además de las herramientas del navegador web, puede utilizar el cliente de línea de comandos nghttp del proyecto nghttp2.org para verificar que el envío al servidor esté en vigor. Puede descargar el cliente de línea de comandos nghttp desde GitHub o instalar el paquete de sistema operativo apropiado cuando esté disponible. Para Ubuntu, utilice el paquete nghttp2-client .

En la salida, el asterisco (*) marca los recursos que fueron enviados por el servidor.

$ nghttp -ans https://example.com/demo.html id respuestaFin solicitudInicio proceso código tamaño solicitud ruta 13 +84.25ms +136us 84.11ms 200 492 /demo.html 2 +84.33ms * +84.09ms 246us 200 266 /style.css 4 +261.94ms * +84.12ms 177.83ms 200 40K /image2.jpg 6 +685.95ms * +84.12ms 601.82ms 200 173K /image1.jpg

Envío automático de recursos a los clientes

En muchas situaciones, resulta inconveniente (o incluso imposible) enumerar los recursos que desea incluir en el archivo de configuración de NGINX. Por este motivo, NGINX también admite la convención de interceptar los encabezados de precarga de enlace y luego enviar los recursos identificados en estos encabezados. Para habilitar la precarga, incluya la directiva http2_push_preload en la configuración:

servidor { # Asegúrese de que HTTP/2 esté habilitado para el servidor listen 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # Interceptar el encabezado del enlace e iniciar los pushes solicitados location = /myapp { proxy_pass http://upstream; http2_push_preload on; } }

Por ejemplo, cuando NGINX funciona como proxy (para HTTP, FastCGI u otros tipos de tráfico), el servidor ascendente puede agregar un encabezado de enlace como este a su respuesta:

Enlace: </style.css>; as=style; rel=preload

NGINX intercepta este encabezado y comienza a enviar al servidor /style.css . La ruta en el encabezado del enlace debe ser absoluta: no se admiten rutas relativas como ./style.css . La ruta puede incluir opcionalmente una cadena de consulta.

Para enviar varios objetos, puede proporcionar varios encabezados de enlace o, mejor aún, incluir todos los objetos en una lista separada por comas:

Enlace: </style.css>; como=estilo; rel=precarga, </favicon.ico>; como=imagen; rel=precarga

Si no desea que NGINX envíe un recurso precargado, agregue el parámetro nopush al encabezado:

# El recurso no se envía Enlace: </nginx.png>; as=image; rel=preload; nopush

Cuando http2_push_preload está habilitado, también puede iniciar el envío de precarga al servidor configurando el encabezado de respuesta en su configuración de NGINX:

add_header Enlace "</style.css>; como=estilo; rel=precarga";

Impulsar selectivamente los recursos a los clientes

La especificación HTTP/2 no aborda el desafío de determinar si se deben o no enviar recursos. Claramente, es mejor enviar recursos solo a los clientes si se sabe que es probable que necesiten el recurso y que es poco probable que ya lo tengan almacenado en caché.

Un enfoque posible es enviar recursos a los clientes solo en su primera visita al sitio. Puede probar la presencia de una cookie de sesión, por ejemplo, y configurar el encabezado de enlace de manera condicional, de modo que los recursos se precarguen solo si la cookie de sesión no está presente.

Suponiendo que los clientes se comportan bien e incluyen la cookie en solicitudes posteriores, con la siguiente configuración NGINX envía los recursos a los clientes solo una vez por sesión del navegador:

servidor {
escuchar 443 ssl http2 servidor_predeterminado;

certificado_ssl ssl/certificate.pem;
clave_certificado_ssl ssl/key.pem;

raíz /var/www/html;
http2_push_preload activado;

ubicación = /demo.html {
add_header Set-Cookie "sesión=1";
add_header Enlace $recursos;
}
}

mapa $http_cookie $recursos {
"~*sesión=1" "";
predeterminado "</style.css>; como=estilo; rel=precarga, </image1.jpg>; como=imagen; rel=precarga, </image2.jpg>; como=imagen; rel=precarga";
}

Medición del efecto del push del servidor HTTP/2

Para medir el efecto del envío al servidor, creamos una página de prueba simple, /demo.html , que hace referencia a una hoja de estilo separada, /style.css . La hoja de estilo también hace referencia a dos imágenes. Probamos los tiempos de carga de las páginas utilizando tres configuraciones diferentes:

  • GET secuenciales (sin optimización): el navegador cargó los recursos cuando descubrió que eran necesarios
  • Sugerencias de precarga : las sugerencias de precarga (encabezados de enlace ) se incluyeron en la primera respuesta para indicarle al navegador que cargue las dependencias
  • Server Push (sólo HTTP/2): las dependencias se enviaron preventivamente al navegador
Se probaron tres configuraciones para medir el impacto de HTTP/2 con el envío de mensajes al servidor.

Realizamos varias pruebas de cada configuración utilizando HTTP, HTTPS o HTTP/2. Las dos primeras configuraciones se aplican a los tres protocolos y el servidor envía únicamente a HTTP/2.

El comportamiento se midió utilizando las herramientas para desarrolladores de Chrome. Se evaluó y promedió el comportamiento más común de cada configuración y los tiempos se correlacionaron con el RTT del enlace (medido mediante ping ) para ilustrar el efecto mecánico de cada método.

Los resultados de las pruebas muestran que se produjeron numerosos viajes de ida y vuelta con cada configuración.

Algunas observaciones básicas

  • La carga del DOM es el momento de iniciar una nueva conexión y recuperar la página demo.html . La hoja de estilo es el momento de recuperar el recurso CSS.
  • Establecer una conexión a través de HTTP requiere 1 RTT; para HTTPS y HTTP/2, se necesitan 2 RTT.
  • La carga útil de los recursos HTML y CSS es menor que el tamaño de la unidad máxima de transmisión (MTU), por lo que una operación GET se completa en aproximadamente 1 RTT.

Interpretación de los resultados: Sugerencias de precarga

  • Las sugerencias de precarga tienen un efecto mínimo en el recurso CSS porque se hace referencia a él directamente dentro del recurso HTML y el recurso HTML se entrega rápidamente. El navegador inicia la solicitud CSS tan pronto como se entrega la página HTML.
  • Las sugerencias de precarga tienen el efecto de iniciar rápidamente la descarga de recursos que se declaran en el recurso CSS (aquí, las dos imágenes). Las descargas pueden comenzar 1 RTT más rápido cuando se utilizan sugerencias de precarga.
  • El ahorro neto de las sugerencias de precarga puede ser de 1 RTT o más. Al descargar recursos en paralelo, el navegador debe abrir una o más conexiones adicionales. El rendimiento depende de si las solicitudes lentas (respuestas más grandes) se programan primero o se retrasan mientras se abren nuevas conexiones. Este orden de solicitudes impredecible explica la aceleración de 1-RTT para HTTP y HTTP/2, y la aceleración de 2-RTT para HTTPS.

Interpretación de los resultados: Empuje del servidor

  • El servidor mejoró el tiempo de sugerencias de precarga en 1 RTT adicional. Las “respuestas” push se iniciaron al mismo tiempo que la respuesta a la primera solicitud, mientras que las respuestas de sugerencias de precarga incurrieron en un retraso de 1 RTT: 0,5 RTT para la respuesta a la primera solicitud más 0,5 RTT para la solicitud GET de precarga.

Notas de prueba

  • Se realizaron múltiples ejecuciones de prueba para cada configuración. Cada ejecución comenzó con un caché de navegador vacío y sin conexiones keepalive establecidas con el servidor NGINX. Las directivas NGINX keepalive_timeout y http2_idle_timeout se utilizaron para cerrar rápidamente las conexiones keepalive.
  • Actualmente no parece posible enviar recursos de fuentes a Chrome, quizás debido a una complicación conocida . Chrome realiza una solicitud explícita de un recurso de fuente incluso si ya se ha enviado.
  • Se tuvo cuidado de borrar explícitamente los cachés del navegador antes de cada prueba, y todo el contenido se sirvió con encabezados de control de caché vencidos.
  • Chrome almacena en caché recursos precargados. Estos recursos almacenados en caché no se ignoran de manera consistente cuando se deshabilita el almacenamiento en caché y no se borran de manera consistente mediante una operación explícita de “borrar la caché del navegador”. (En Chrome, una forma de deshabilitar el almacenamiento en caché es marcar la casilla de verificación Deshabilitar caché en la pestaña Red de herramientas para desarrolladores. Para borrar la memoria caché del navegador, puede hacer clic derecho en el botón de actualización del navegador con las Herramientas para desarrolladores abiertas y seleccionar Vaciar caché y recarga completa .
  • Algunos intentos de precargar contenido provocaron que Chrome revalidara sin éxito las copias en caché y luego descargara el recurso normalmente. Estos intentos no fueron contabilizados en las mediciones.
  • Chrome agrega un retraso innecesario de 2-RTT a todas las nuevas conexiones SSL que utilizan certificados autofirmados previamente aceptados. La prueba se realizó utilizando certificados Let’s Encrypt firmados por CA para evitar este retraso de 2-RTT.
  • Los retrasos de DNS se solucionaron editando el archivo /etc/hosts local.
  • Estas pruebas simples no intentaron medir el efecto del envío del servidor cuando el cliente ya tiene una copia en caché del recurso. En las pruebas, todos los cachés se borraron antes de cada prueba y la mayoría de los envíos fueron demasiado rápidos para cancelarlos.

CONCLUSIÓN

Esta prueba fue deliberadamente simple, para resaltar la mecánica de las sugerencias de precarga y el empuje del servidor. El envío de servidores proporciona una mejora de 1 RTT con respecto a las sugerencias de precarga en situaciones simples, y una mejora mayor en comparación con las solicitudes GET secuenciales no optimizadas y el descubrimiento de recursos dependientes.

Los casos de uso más realistas tienen muchas más variables: múltiples recursos dependientes, múltiples fuentes e incluso la posibilidad de desperdiciar ancho de banda al enviar recursos que ya están almacenados en caché o que no se necesitan de inmediato. Las inconsistencias del navegador también afectan el rendimiento. Los resultados que obtendrá con esta sencilla prueba seguramente variarán.

Por ejemplo, el equipo de Chrome ha publicado algunas recomendaciones detalladas sobre cuándo implementar el envío al servidor y ha tomado mediciones en sitios más complejos para comparar los efectos de la falta de optimización, las sugerencias de precarga y el envío al servidor a través de HTTP/2. Vale la pena leer su informe "Reglas generales para HTTP/2 Push" para cualquiera que esté considerando implementar HTTP/2 server push en producción.

La conclusión pragmática es que si se pueden identificar con antelación los recursos que se requieren, hay un beneficio real en que los servidores ascendentes envíen una sugerencia de precarga. El beneficio adicional de impulsar estos recursos es pequeño pero medible, pero puede posiblemente resultar en desperdicio de ancho de banda y demoras para los recursos necesarios. Debes probar y supervisar cuidadosamente cualquier configuración de empuje del servidor.

Apéndice: ¿Cómo funciona el push HTTP/2?

La siguiente información se basa en parte en la investigación publicada en el blog muy detallado de Jake Archibald: HTTP/2 push is tougher than I thought (Impulsar HTTP/2 es más difícil de lo que pensaba) .

El envío de servidores HTTP/2 se utiliza generalmente para enviar recursos dependientes de forma preventiva cuando el cliente solicita un recurso. Por ejemplo, si un cliente solicita una página web, el servidor puede enviar hojas de estilo, fuentes e imágenes dependientes al cliente.

Cuando un cliente establece una conexión HTTP/2, el servidor puede elegir iniciar una o más respuestas de inserción del servidor a través de la conexión. Estos push envían recursos que el cliente no ha solicitado explícitamente.

El cliente puede rechazar un push (enviando un marco RST_STREAM ) o aceptarlo. El cliente almacena el contenido enviado en un “caché de envío” local que está asociado con la conexión HTTP/2.

Más tarde, cuando el cliente realiza una solicitud de un recurso mediante una conexión HTTP/2 establecida, verifica el caché de inserción de la conexión para ver si hay una respuesta completada o en tránsito a la solicitud. Utiliza el recurso almacenado en caché en lugar de realizar una nueva solicitud HTTP/2 para el recurso.

Cualquier recurso enviado permanece en la caché de envío por conexión hasta que (a) se utiliza o (b) se cierra la conexión HTTP/2:

  1. Si se utiliza el recurso, el cliente toma una copia y se elimina la entrada en el caché de inserción. Si el recurso se puede almacenar en caché, el cliente puede entonces almacenar en caché su copia en su caché de páginas HTTP.
  2. Si la conexión HTTP/2 se cierra por cualquier motivo, se elimina su caché de inserción local.

Esto tiene varias implicaciones:

  • El contenido en la memoria caché de páginas HTTP en el navegador se usa con preferencia al contenido en la memoria caché de inserción, incluso si el contenido insertado es más reciente.
  • Las conexiones HTTP/2 se pueden compartir entre diferentes cargas de páginas. Un recurso que se envía como resultado de la carga de una página se puede utilizar cuando se solicita en una carga de página diferente.
  • Las solicitudes con credenciales utilizan conexiones HTTP/2 diferentes de las solicitudes sin credenciales; por ejemplo, un recurso que se envía con una solicitud de origen cruzado (con credenciales) podría no encontrarse si el navegador realiza una solicitud sin credenciales para el recurso.

Puede consultar una lista mucho más detallada de problemas en la entrada del blog de Jake Archibald: HTTP/2 push is tougher than I thought (Impulsar HTTP/2 es más difícil de lo que pensaba) .

El envío de mensajes al servidor HTTP/2 es una capacidad interesante. Asegúrese de probar exhaustivamente la configuración de push de su servidor HTTP/2 y esté preparado para recurrir a las sugerencias de precarga en los casos en que esto proporcione un comportamiento más predecible y consciente del caché.


"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.