Header Ads Widget

Ticker

6/recent/ticker-posts

No infrautilice estas 5 increíbles funciones de rendimiento HTTP

 

No infrautilice estas 5 increíbles funciones de rendimiento HTTP

Entonces, ¿ha publicado una API web? ¡Bien hecho! Lo está sirviendo a través de HTTP (S), ¿verdad? La mayoría de los desarrolladores no ven ninguna razón para desconfiar del protocolo que ha mantenido unida a la web durante casi 30 años. HTTP es muy eficiente, escalable y confiable; de ​​hecho, tiene múltiples funciones de desempeño ingeniosas para asegurarse de que los desarrolladores puedan aprovechar al máximo las aplicaciones creadas sobre él. En este artículo exploramos algunos de ellos, porque aunque los servidores web más populares los admiten, es posible que deba habilitarlos o configurarlos, y el primer paso es comprenderlos.

Este artículo no pretende brindarle instrucciones paso a paso sobre cómo habilitar y configurar estas funciones en su servidor web en particular, sino más bien explicar por qué son necesarias, cómo funcionan y en qué situaciones debe usarlas. . ¡Aquí vamos!

1: almacenamiento en caché

El almacenamiento en caché puede ser la característica de rendimiento con mayor impacto, pero también es una de las más complejas y propensas a errores. La idea básica es que el cliente no debería tener que volver a descargar datos que ha descargado previamente; el problema es decidir qué datos ya tiene el cliente y si han cambiado desde que el cliente los descargó.

Hay algunas formas de lidiar con esto. El enfoque más común es incluir un encabezado de respuesta que le indique al cliente cómo almacenar en caché los datos, si es que lo hace. Pero dado que HTTP es un protocolo antiguo y versátil, existen varios encabezados de caché diferentes y diferentes formas de usarlos. A continuación, se ofrece una descripción general rápida de los encabezados de caché más utilizados:

  • Cache-control es el encabezado más utilizado para, bueno, el control de caché. Permite al servidor especificar durante cuánto tiempo el cliente debe almacenar en caché los datos y qué partes de la cadena entre el servidor y el cliente deben o no almacenarlos. Por ejemplo, es posible decirle a los servidores proxy y a las redes de entrega de contenido (CDN) que no almacenen una respuesta, mientras le dicen al cliente que la guarde. Sin embargo, el control de caché por sí solo está limitado porque en realidad no puede decirle al cliente que solo descargue nuevos datos, ya que la validación de caché se basa únicamente en un tiempo de espera.
cache-control: private, max-age=0, no-cache 
  • Etag es un encabezado que le da al cliente una identidad del recurso que se solicita. Las implementaciones típicas de etag implican el uso de un hash de los datos como identidad, una marca de tiempo o una combinación de ambos. Esto evita que el cliente tenga que descargar datos que no han cambiado. El servidor incluirá el valor etag actual del documento en el encabezado Etag:
ETag: "123abc"

Luego, el cliente puede, en solicitudes posteriores, decirle al servidor que solo devuelva el recurso si el etag ha cambiado, utilizando el encabezado If-None-Match:

If-None-Match: "123abc"

Si el documento no ha cambiado, el servidor simplemente puede devolver un estado HTTP 304 No modificado, en lugar de tener que enviar el documento completo. Por supuesto, esto significa que la implementación de la identidad tiene que ser buena, para que diferentes documentos no obtengan el mismo Etag y viceversa. También es importante recordar que, si bien Etag resuelve muchos problemas de caché, algunos datos pueden enviarse en vano. El cliente aún tiene que realizar solicitudes al servidor para validar sus datos almacenados en caché, ya sean válidos o no. Pero combinado con el control de caché y la selección inteligente de parámetros, puede acercarlo mucho a la meta.

  • El encabezado Vary se usa para indicar a las partes intermedias, como proxies, CDN y motores de caché, que las diferentes clases de clientes deben obtener datos diferentes. De esa manera, los clientes que solicitan datos comprimidos (utilizando el encabezado Accept-Encoding) pueden obtener datos comprimidos con gzip, y los clientes que no admiten gzip pueden obtener los datos sin procesar, todo entre la capa de caché y el cliente, sin tener que recorrer todo el camino al servidor. También es posible variar el almacenamiento en caché en otros encabezados de solicitud HTTP, por ejemplo, User-Agent, que permite que los cachés intermedios diferencien entre usuarios con diferentes navegadores.
vary: User-Agent
  • Expires es un encabezado más antiguo que le dice al cliente cuándo el recurso no debe mantenerse en la caché. No es tan versátil como el control de caché, pero es muy fácil de implementar y comprender, por lo que todavía se usa ampliamente.

Recuerde probar su aplicación extensamente (duh) cuando use el almacenamiento en caché, ya que es muy fácil equivocarse. Cuanto más compleja sea su configuración, más trampas podrá construir usted mismo. Pero también existe la posibilidad de un gran aumento de rendimiento y escalabilidad.

2: Keep-Alive

HTTP casi siempre usa TCP como protocolo subyacente, y hay una propiedad de TCP que puede causar graves problemas de rendimiento si no se maneja correctamente. Bueno, hay varios, pero hay uno específicamente que vale la pena destacar.

Si se pierde un TCP enviado por una de las partes, la parte transmitirá ese paquete nuevamente después de un período de tiempo. Las pilas de redes modernas utilizan inteligentemente los tiempos de ida y vuelta de los paquetes exitosos para determinar un tiempo de espera ideal ; por ejemplo, si los paquetes normalmente tardan 1 milisegundo en llegar, la parte puede asumir con seguridad que cualquier paquete que haya estado en tránsito durante 10 milisegundos probablemente se haya perdido. y así puede retransmitir ese paquete y dejar de esperar a que llegue el original.

Pero si su aplicación está construida de tal manera que cada solicitud HTTP usa una nueva conexión TCP (en lugar de reutilizar una existente), esos datos históricos no están disponibles. En este caso, la mayoría de las pilas de red establecen el tiempo de espera inicial en 3 segundos. Eso significa que si se pierde un paquete, ¡pasarán 3 segundos completos antes de que se vuelva a intentar! Esto puede ser un gran problema para los clientes con una conexión inestable, por ejemplo, los usuarios móviles .

Entonces, ¿qué puede hacerse? HTTP tiene una función llamada Keep-Alive , que permite al cliente y al servidor mantener su conexión TCP, incluso cuando se ha completado el primer ciclo de solicitud-respuesta HTTP. De esa forma, las solicitudes posteriores utilizarán la misma conexión TCP y cualquier paquete perdido se retransmitirá mucho antes. Por supuesto, esto solo es útil si su aplicación involucra múltiples solicitudes HTTP de cada cliente.

3: Solicitud de canalización

Puede optimizar aún más el rendimiento de las aplicaciones donde los clientes envían múltiples solicitudes canalizándolas. Cuando la canalización de solicitudes está habilitada, el cliente y el servidor aceptan que el cliente no necesita esperar una respuesta antes de enviar la siguiente solicitud. De esta forma, puede lograr un rendimiento mucho mayor Sin embargo, las respuestas seguirán apareciendo en el mismo orden que las solicitudes correspondientes, por lo que una respuesta particularmente lenta seguirá reteniendo todas las respuestas posteriores. Esto se denomina bloqueo de cabecera y se aborda en la próxima versión de HTTP denominada HTTP / 2 . Más sobre eso a continuación.

Comparación entre canalizaciones y no canalizaciones

Tenga en cuenta también que la canalización solo funcionará siempre para las solicitudes que no cambien el estado del servidor, por ejemplo, las solicitudes GET o HEAD (es una pena si cambia el estado del servidor con estas solicitudes). Las solicitudes que cambian el estado, como PUT o DELETE, se pueden canalizar, siempre que el cliente esté seguro de que las solicitudes posteriores no dependen del estado de las solicitudes anteriores. De lo contrario, el cliente verá un estado de servidor incoherente entre las respuestas que pueden o no dañar su aplicación.

Las solicitudes no idempotentes (que provocan una nueva acción única cada vez que se realizan), como POST, generalmente no son seguras para canalizar. La mayoría de las veces, estos se implementan como un bloque en la tubería, para asegurarse de no arruinar el estado para otras solicitudes que puedan depender de él.

4: Compresión

Una forma sencilla de ahorrar tiempo al transmitir datos es comprimirlos. HTTP admite múltiples formatos de compresión, pero los dos más utilizados son GZIP y deflate . En teoría son similares (usan el mismo algoritmo de compresión pero con diferentes encabezados y suma de comprobación), pero en la práctica ha habido mucha confusión con deflate. Dado que muchos navegadores lo han implementado incorrectamente, aunque desinflar puede ser más rápido que GZIP, el consenso general es evitar desinflar. El efecto ha sido que GZIP es el formato de compresión predeterminado para la mayoría del software de servidor. Sin embargo, es posible que todavía haya clientes que solo admitan deflate, por lo que lo mejor es hacer que el servidor admita ambos.

¿Entonces, cómo funciona? Normalmente, el cliente le dice al servidor (a través del encabezado Accept-Encoding ) que admite algunos tipos de compresión. A continuación, el servidor comprime la carga útil de datos (no los encabezados) de la respuesta HTTP utilizando ese esquema de compresión y lo envía al cliente. Dependiendo del tipo de contenido, los datos pueden ser hasta un 90% más pequeños cuando se comprimen.

Client:
GET /some-resource HTTP/1.1
Host: www.domain.com
Accept-Encoding: gzip, deflate
Server:
HTTP/1.1 200 OK
Content-Length: 1337
Content-Encoding: gzip

[compressed data]

Sin embargo, es importante recordar que la compresión no es gratuita . Se necesitarán algunos recursos de la CPU en el servidor para comprimir los datos y algunos recursos del cliente para descomprimirlos. Eso puede provocar problemas de rendimiento en el servidor porque consume la CPU en la compresión de datos HTTP, y si la carga útil de datos es pequeña y la red es rápida, el retraso de compresión adicional podría hacer que los datos tarden más en llegar al cliente que cuando no se utiliza compresión. Como siempre, pruébelo con su escenario y vea si funciona para usted.

5: contenido parcial

No debe enviar datos que ya se han enviado o que no deben enviarse por otros motivos (consulte la discusión sobre almacenamiento en caché anterior). HTTP le brinda herramientas para optimizar su aplicación de la manera que desee. A continuación, se muestran algunas formas en las que puede utilizar HTTP para publicar o aceptar contenido parcial :

  • A veces, el cliente no necesita leer el cuerpo de la respuesta HTTP para obtener la información que busca. Por ejemplo, es posible que solo le interese el tamaño de un recurso, que se puede ver en los encabezados. O se puede utilizar para averiguar qué funciones HTTP admite el servidor. En ese caso, el cliente puede realizar una solicitud HEAD al servidor. Una solicitud HEAD es como una solicitud GET, excepto que el servidor no envía el cuerpo del mensaje, solo los encabezados.
Client:
HEAD /some-resource HTTP/1.1
Host: www.domain.com

Server:
HTTP/1.1 200 OK
Last-Modified: Fri, 26 Aug 2016 21:31:11 GMT
ETag: "123abc"
Content-Length: 25876
  • Cuando se trata de solicitudes POST y PUT, el cliente puede tener una carga útil considerable para el servidor. Pero en algunos casos, es posible que el cliente no pueda realizar solicitudes, por ejemplo, si falta algún encabezado HTTP o no es válido (la autorización a menudo se implementa mediante encabezados). El encabezado Expect se puede usar para enviar solo los encabezados de la solicitud y decirle al servidor que regrese con un código de estado 100 Continuar si los encabezados son A-OK. De esta forma, el cliente no necesita enviar esa gran carga útil hasta que esté seguro de que el servidor la aceptará.
Client:
POST /some-resource HTTP/1.1
Host: www.domain.com
Expect: 100-continue
Content-Length: 42424242
X-Authorization: whatever

[no data]

Server:
HTTP/1.1 100 Continue


Client:
POST /some-resource HTTP/1.1
Host: www.domain.com
Expect: 100-continue
Content-Length: 42424242
X-Authorization: whatever

[all that juicy data]
  • El servidor también tiene la opción de no enviar un gran cuerpo de respuesta de una sola vez. Puede usar un estado de respuesta 206 Partial Content para decirle al cliente que hay más datos en camino y dividir el cuerpo en múltiples respuestas HTTP. Esto significa que la respuesta HTTP inicial solo contendrá la primera parte de los datos, y luego depende del cliente solicitar las siguientes partes y unir esas respuestas para formar el documento completo.

Entonces, ¿cómo sabe el servidor que el cliente espera esto? Bueno, el cliente tiene que pedirlo. Una forma de que el cliente lo haga es usar una solicitud HEAD para averiguar el tamaño del recurso y, al hacerlo, el servidor puede decirle al cliente que admite respuestas parciales devolviendo el encabezado Accept-Ranges . Luego, el cliente puede simplemente realizar múltiples solicitudes, cada una con un rango de bytes diferente en el encabezado Range .

Client:
HEAD /some-resource HTTP/1.1
Host: www.domain.com

Server:
HTTP/1.1 200 OK
Last-Modified: Fri, 26 Aug 2016 21:31:11 GMT
ETag: "123abc"
Content-Length: 25876
Accept-Ranges: bytes

Client:
GET /some-resource HTTP/1.1
Host: www.domain.com
Range: bytes=0-100

HTTP / 2

Entonces, ¿qué nos depara el futuro? Bueno, la próxima versión de HTTP (no tan sorprendentemente llamada HTTP / 2) fue lanzada el año pasado, después de haber comenzado su vida como un protocolo desarrollado por Google llamado SPDY . Una de las principales diferencias es que HTTP / 2 se basa en tramas binarias que se transmiten a través de secuencias TCP, a diferencia de los mensajes de texto basados ​​en ASCII. Este cambio habilita un montón de funciones nuevas, algunas de las cuales traerán algunas mejoras de rendimiento, que incluyen:

  • Compresión de encabezados : esto significa que no solo se puede comprimir el cuerpo de una respuesta, sino también los encabezados. En algunos casos, donde hay muchos encabezados (por ejemplo, muchos datos de cookies), puede proporcionar un aumento de velocidad significativo.
  • Mejor soporte para la canalización a través de la multiplexación de mensajes verdadera, lo que elimina el problema con el bloqueo de la cabeza de línea mencionado en la sección sobre canalización. Esto también significa que se pueden enviar varias solicitudes en paralelo a través de la misma conexión TCP, en lugar de tener que abrir varias conexiones entre el cliente y el servidor.

Resumiendo

¿Así que, qué hemos aprendido? Bueno, por un lado, HTTP es muy complejo y rico en funciones, y configurarlo correctamente y optimizar su configuración puede aumentar significativamente el rendimiento y la confiabilidad. Aunque el uso puede variar, muchas de las optimizaciones que están hechas a medida para escenarios de navegación web también se trasladan muy bien al diseño de API. Pero estas optimizaciones no son gratuitas; asegúrese de probarlas en condiciones reales para que aumenten con éxito la solidez de su servicio. ¡Feliz optimización!

Publicar un comentario

0 Comentarios