Solucionar problemas de latencia elevada en tu app

En muchos casos, la latencia elevada en la aplicación dará como resultado errores de servidor 5xx. Por lo tanto, tiene sentido seguir un conjunto similar de pasos para solucionar problemas para reducir la causa raíz de los aumentos repentinos de errores y latencia, dado que las causas de cada uno pueden ser las mismas.

Dimensiona el problema

Primero, define el alcance del problema de la forma más estrecha posible mediante la recopilación de información relevante. A continuación se proporcionan algunas sugerencias de información que puede ser relevante.

  • ¿Qué IDs de servicio, aplicación y versión se ven afectados?
  • ¿Qué extremos específicos de la app se ven afectados?
  • ¿Esto afectó a todos los clientes a nivel global o a un subconjunto específico de clientes?
  • ¿Cuál es la hora de inicio y de finalización del incidente? Deberías especificar la zona horaria.
  • ¿Qué errores específicos ves?
  • ¿Cuál es la delta de latencia observada, que por lo general se especifica como un aumento en un percentil específico? Por ejemplo, la latencia aumentó 2 segundos en el percentil 90.
  • ¿Cómo mediste la latencia? En particular, ¿se midió en el cliente o es visible en Cloud Logging o en los datos de latencia de Cloud Monitoring que proporciona la infraestructura de entrega de App Engine?
  • ¿Cuáles son las dependencias de tu aplicación y alguna de ellas experimentó incidentes?
  • ¿Realizaste algún cambio reciente en el código, la configuración o la carga de trabajo que podría haber activado este problema?

Una aplicación puede tener su propia supervisión y registro personalizados que puedes usar para limitar aún más el alcance del problema más allá de las sugerencias anteriores. Definir el alcance del problema te guiará hacia la causa raíz probable y determinará tus próximos pasos para solucionar problemas.

Determina qué falló

A continuación, determina qué componente de la ruta de la solicitud es más probable que cause la latencia o los errores. Los componentes principales de la ruta de solicitud son los siguientes:

Cliente -> Internet -> Google Front End (GFE) -> Infraestructura de entrega de App Engine -> Instancia de aplicación

Si la información recopilada en el paso 1 no te dirige a la fuente de la falla, por lo general, debes empezar por observar el estado y el rendimiento de las instancias de la aplicación.

Una forma de determinar si el problema se encuentra en la instancia de la aplicación es observar los registros de solicitud de App Engine: si ves errores de código de estado HTTP o latencia elevada en esos registros, por lo general, significa que el problema que se encuentra en la instancia que ejecuta tu aplicación.

Existe una situación en la que la instancia de aplicación en sí no puede generar errores ni latencia elevadas en los registros de solicitud: si la cantidad de instancias de tu aplicación no aumentó la escala para coincidir con los niveles de tráfico, tus instancias pueden sobrecargarse, lo que genera errores y latencia elevados.

Si ves errores elevados o latencia en Cloud Monitoring, puedes concluir que el problema está en sentido ascendente del balanceador de cargas, que registra las métricas de App Engine. En la mayoría de los casos, esto genera un problema en las instancias de la aplicación.

Sin embargo, si ves una latencia elevada o errores en las métricas de supervisión, pero no solicitas registros, es posible que se requiera una mayor investigación. Puede indicar una falla en la capa de balanceo de cargas o que las instancias experimentan una falla tan grave que el balanceador de cargas no puede enrutar solicitudes a ellas. Para distinguir entre estos casos, puedes ver los registros de solicitud justo antes de que empiece el incidente. Si los registros de solicitud muestran una latencia creciente antes de la falla, indica que las instancias de la aplicación estaban empezando a fallar antes de que el balanceador de cargas dejara de enrutar las solicitudes a ellas.

Situaciones que podrían causar incidentes

Estas son algunas situaciones con las que se encontraron los usuarios.

Cliente

Asigna una IP de cliente a una región geográfica

Google resuelve el nombre de host para la aplicación de App Engine en el GFE más cercano al cliente, según la dirección IP de cliente que se usa en la búsqueda de DNS. Si el agente de resolución de DNS del cliente no usa el protocolo EDNS0, es posible que las solicitudes del cliente no se enruten al GFE más cercano.

Internet

Conexión a Internet deficiente

Ejecuta el siguiente comando en tu cliente para determinar si el problema es de conectividad de Internet deficiente.

$ curl -s -o /dev/null -w '%{time_connect}\n' <hostname>

El valor de time_connect suele representar la latencia de la conexión del cliente al Google Front End más cercano. Si esta conexión es lenta, puedes solucionar problemas mediante traceroute para determinar qué salto en la red causa la demora.

Puedes ejecutar pruebas desde clientes en diferentes ubicaciones geográficas. Las solicitudes se enrutarán de forma automática al centro de datos de Google más cercano, que variará según la ubicación del cliente.

Clientes con ancho de banda bajo

Es posible que la aplicación responda con rapidez, pero la respuesta podría ralentizarse debido a los cuellos de botella en la red que hacen que la infraestructura de entrega de App Engine no envíe paquetes a través de la red con la misma rapidez que podrían enviarse.

Google Front End (GFE)

Bloque de líneas de HTTP/2

Los clientes de HTTP/2 que envían varias solicitudes en paralelo pueden ver una latencia elevada debido al bloqueo de línea en el GFE. La mejor solución es que los clientes actualicen al protocolo QUIC.

Terminación SSL para dominios personalizados

GFE finaliza la conexión SSL. Se requiere un salto adicional para la finalización de SSL si usas un dominio personalizado, en lugar de un dominio appspot.com. Esto podría agregar latencia para aplicaciones que se ejecutan en algunas regiones.

Infraestructura de entrega de App Engine

Incidente de todo el servicio

Google publicará los detalles de un servicio grave en todo el servicio en https://status.cloud.google.com/. Ten en cuenta que Google se lanza de forma gradual, por lo que es poco probable que un incidente en todo el servicio afecte a todas las instancias a la vez.

Ajuste de escala automático

Escala el tráfico demasiado rápido

Es posible que el ajuste de escala automático de App Engine no escale tus instancias tan rápido como el tráfico aumente, lo que genera una sobrecarga temporal. Por lo general, esto ocurre cuando los usuarios finales no generan tráfico de forma orgánica, sino mediante un programa informático. La mejor manera de resolver este problema es limitar el sistema que genera el tráfico.

Aumentos repentinos del tráfico

Los aumentos repentinos de tráfico pueden causar una latencia elevada en casos en los que una aplicación con ajuste de escala automático necesita escalar de forma vertical más rápido de lo posible sin afectar la latencia. El tráfico del usuario final no suele provocar aumentos repentinos frecuentes de tráfico. Si ves esto, debes investigar cuál es la causa de los aumentos repentinos del tráfico. Si un sistema por lotes se ejecuta a intervalos, tal vez puedas suavizar el tráfico o usar diferentes configuraciones de escalamiento.

Configuración del escalador automático

El escalador automático se puede configurar según las características de escalamiento de tu aplicación. Estos parámetros de escalamiento pueden volverse no óptimos durante ciertas situaciones.

Las aplicaciones del entorno flexible de App Engine escalan en función del uso de CPU. Sin embargo, la aplicación puede vincularse a E/S durante un incidente, lo que genera una sobrecarga de instancias con una gran cantidad de solicitudes, ya que el escalamiento basado en la CPU no se produce.

La configuración de escalamiento del entorno estándar de App Engine puede causar latencia si se establece demasiado agresiva. Si ves respuestas del servidor con el código de estado 500 y el mensaje Request was aborted after waiting too long to attempt to service your request en tus registros, significa que se agotó el tiempo de espera de la solicitud en la fila pendiente en la espera de una instancia inactiva.

No uses el ajuste de escala manual del entorno estándar de App Engine si tu app entrega tráfico de usuario final. El ajuste de escala manual es mejor para cargas de trabajo como las listas de tareas en cola. Es posible que notes un aumento en el tiempo pendiente con el escalamiento manual, incluso cuando aprovisionas suficientes instancias.

No uses el ajuste de escala básico del entorno estándar de App Engine para aplicaciones sensibles a la latencia. Este tipo de escalamiento está diseñado para minimizar costos a expensas de la latencia.

La configuración predeterminada del escalamiento del entorno estándar de App Engine proporciona una latencia óptima para la mayoría de las aplicaciones. Si aún ves solicitudes con un tiempo pendiente alto, puedes especificar una cantidad mínima de instancias. Si ajustas la configuración de escalamiento para reducir costos mediante la minimización de instancias inactivas, corres el riesgo de ver aumentos repentinos de latencia si la carga aumenta de forma repentina

Te recomendamos comparar el rendimiento con la configuración de escalamiento predeterminada y, luego, ejecutar una comparativa nueva después de cada cambio en esta configuración.

Objetos Deployment

La latencia elevada poco después de una implementación indica que no escalaste lo suficiente antes de migrar el tráfico. Es posible que las instancias más recientes no tengan cachés locales preparadas y, por lo tanto, puedan entregarse de manera más lenta que las instancias más antiguas.

Para evitar aumentos repentinos de latencia, no implementes una app de App Engine con el mismo nombre de versión que una versión existente de la app. Si vuelves a usar un nombre de versión existente, no podrás migrar de forma lenta el tráfico a la versión nueva. Las solicitudes pueden ser más lentas porque cada instancia se reiniciará en un período corto. También tendrás que volver a implementar si deseas volver a la versión anterior.

Instancia de aplicación

Código de la aplicación

Los problemas en el código de la aplicación pueden ser muy difíciles de depurar, en especial si son intermitentes o no se pueden reproducir con facilidad. Para ayudar a diagnosticar problemas, recomendamos que tu aplicación esté instrumentada con registro, supervisión y seguimiento. . Puedes intentar usar Cloud Profiler para diagnosticar problemas. Consulta este ejemplo sobre el diagnóstico de la latencia de las solicitudes de carga mediante Cloud Trace para subir información adicional de tiempo para cada solicitud.

También puedes intentar reproducir el problema en un entorno de desarrollo local que puede permitirte ejecutar herramientas de depuración específicas del lenguaje que no son posibles para ejecutarlas en App Engine.

Si ejecutas en el entorno de App Engine Flexible, puedes establecer una conexión SSH a una instancia y hacer un volcado de los subprocesos para ver el estado actual de tu aplicación. Puedes intentar reproducir el problema en una prueba de carga o ejecutar la app de forma local. Puedes aumentar el tamaño de la instancia para ver si esto resuelve el problema. Por ejemplo, el aumento de la RAM puede resolver problemas para las aplicaciones que experimentan retrasos debido a la recolección de elementos no usados

Para comprender mejor cómo falla la app y qué cuellos de botella ocurren, puedes probar la aplicación hasta que falle. Establece un recuento máximo de instancias y, luego, aumenta de forma gradual la carga hasta que la aplicación falle.

Si el problema de latencia se correlaciona con la implementación de una versión nueva del código de tu aplicación, puedes revertirla para determinar si la versión nueva causó el incidente. Si implementas de forma continua, es posible que tengas implementaciones lo suficientemente frecuentes que sean difíciles de determinar si la implementación causó o no el incidente en función de la hora de inicio.

Tu aplicación puede almacenar ajustes de configuración dentro de Datastore o de otro lugar. Será útil si puedes crear un cronograma de cambios de configuración para determinar si alguno de estos coincide con el inicio de la latencia elevada.

Cambio de la carga de trabajo

Un cambio de carga de trabajo puede causar una latencia elevada. Algunas métricas de supervisión que pueden indicar que se cambió la carga de trabajo incluyen qps, así como el uso de la API o la latencia. También puedes verificar si hay cambios en los tamaños de solicitud y respuesta.

Fallas de verificación de estado

El balanceador de cargas del entorno flexible de App Engine dejará de enrutar solicitudes a instancias que fallen las verificaciones de estado. Esto podría aumentar la carga en otras instancias, lo que podría provocar una falla en cascada. Los registros Nginx del entorno flexible de App Engine muestran instancias que fallan las verificaciones de estado. Analiza tus registros y supervisión para determinar por qué la instancia estaba en mal estado o configura las verificaciones de estado para que sean menos sensibles a las fallas transitorias. Ten en cuenta que habrá un retraso breve antes de que el balanceador de cargas deje de enrutar el tráfico a una instancia en mal estado Esta demora puede causar un aumento de error si el balanceador de cargas no puede reintentar las solicitudes.

El entorno estándar de App Engine no usa verificaciones de estado.

Presión de la memoria

Si la supervisión muestra un patrón de otro color en el uso de la memoria o una disminución del uso de memoria que se correlaciona con las implementaciones, los problemas de rendimiento pueden deberse a una fuga de memoria. Una fuga de memoria puede causar una recolección de elementos no usados frecuente, lo que genera una latencia más alta. Aprovisionar instancias más grandes con más memoria puede resolver el problema si no puedes rastrearlo con facilidad hasta un problema en el código.

Fuga de recursos

Si una instancia de tu aplicación muestra una latencia creciente que se correlaciona con la antigüedad de la instancia, es posible que tengas una filtración de recursos que cause problemas de rendimiento. En este tipo de problema, también verás caídas de latencia justo después de una implementación. Por ejemplo, una estructura de datos que se vuelve más lenta con el tiempo debido al mayor uso de CPU puede hacer que cualquier carga de trabajo vinculada a la CPU se vuelva más lenta.

Optimización de código

Algunas formas de optimizar el código en App Engine para reducir la latencia son las siguientes:

  • Trabajo sin conexión: Usa Cloud Tasks para que las solicitudes de los usuarios no bloqueen la espera de finalización de trabajos, como el envío de correos electrónicos.

  • Llamadas a la API asíncronas: Asegúrate de que tu código no esté bloqueado a la espera de que se complete una llamada a la API. Las bibliotecas como ndb ofrecen compatibilidad integrada para esto.

  • Llamadas a la API por lotes: La versión por lotes de las llamadas a la API suele ser más rápida que enviar llamadas individuales.

  • Desnormalizar modelos de datos: Reduce la latencia de las llamadas hechas a la capa de persistencia de los datos mediante la desnormalización de tus modelos de datos.

Dependencias

Puedes supervisar las dependencias de tu aplicación para detectar si los picos de latencia se correlacionan con una falla de la dependencia.

Un aumento en la latencia de una dependencia puede deberse a un cambio en la carga de trabajo, así como a un aumento en el tráfico.

Dependencia sin escalamiento

Si tu dependencia no escala a medida que aumenta la cantidad de instancias de App Engine, la dependencia puede sobrecargarse cuando el tráfico aumenta. Un ejemplo de una dependencia que puede no escalar es una base de datos SQL. Una mayor cantidad de instancias de la aplicación generará una mayor cantidad de conexiones de bases de datos, lo que podría causar una falla en cascada, ya que no se inicia la base de datos.

Una forma de recuperarse de esto es la siguiente:

  1. Implementa una versión predeterminada nueva que no se conecte a la base de datos,
  2. Cerrar la versión predeterminada anterior.
  3. Implementa una versión no predeterminada nueva que se conecte a la base de datos.
  4. Migra el tráfico a la versión nueva.

Una medida preventiva posible es diseñar tu aplicación para que descarte las solicitudes a la dependencia mediante la Regulación adaptable.

Falla de la capa de almacenamiento en caché

Una buena forma de acelerar las solicitudes es usar varias capas de almacenamiento en caché:

  • Almacenamiento en caché perimetral
  • Memcache
  • Memoria en la instancia

Un aumento repentino en la latencia puede deberse a un error en una de estas capas de almacenamiento en caché. Por ejemplo, una limpieza de Memcache puede hacer que más solicitudes vayan a Datastore más lento.