Solucionar problemas de latencia elevada en aplicaciones de App Engine

En muchos casos, la latencia elevada en tu aplicación acaba provocando errores de servidor 5xx. Como la causa principal del error y de los picos de latencia puede ser la misma, aplica las siguientes estrategias para solucionar los problemas de latencia:

  1. Determinar el alcance del problema de latencia
  2. Identifica la causa
  3. Solucionar problemas

Definir el alcance del problema de latencia

Define el alcance del problema haciendo las siguientes preguntas:

  • ¿A qué aplicaciones, servicios y versiones afecta este problema?
  • ¿A qué endpoints específicos del servicio afecta este problema?
  • ¿Afecta a todos los clientes del mundo o a un subconjunto específico?
  • ¿Cuál es la hora de inicio y de finalización del incidente? Te recomendamos que especifiques la zona horaria.
  • ¿Cuáles son los errores específicos?
  • ¿Cuál es el delta de latencia observado, que suele especificarse como un aumento en un percentil concreto? Por ejemplo, la latencia ha aumentado en 2 segundos en el percentil 90.
  • ¿Cómo has medido la latencia? En concreto, ¿lo has medido en el cliente o se puede ver en Cloud Logging o en los datos de latencia de Cloud Monitoring que proporciona la infraestructura de servicio de App Engine?
  • ¿Cuáles son las dependencias de tu servicio? ¿Alguna de ellas ha sufrido incidentes?
  • ¿Ha hecho algún cambio reciente en el código, la configuración o la carga de trabajo que haya provocado este problema?

Un servicio puede tener su propia monitorización y registro personalizados que puedes usar para acotar aún más el ámbito del problema. Definir el alcance del problema te ayudará a identificar la causa probable y a determinar los siguientes pasos para solucionarlo.

Identificar la causa

Determina qué componente de la ruta de la solicitud es más probable que esté provocando la latencia o los errores. Los componentes principales de la ruta de solicitud son los siguientes:

Cliente --> Internet --> Google Front End (GFE) --> Infraestructura de servicio de App Engine --> Instancia de servicio

Si la información anterior no te indica la fuente del fallo, aplica las siguientes estrategias mientras revisas el estado y el rendimiento de tu instancia de servicio:

  1. Monitoriza los registros de solicitudes de App Engine. Si ve errores de código de estado HTTP o una latencia elevada en esos registros, es probable que el problema se deba a la instancia que ejecuta su servicio.

  2. Si el número de instancias de servicio no se ha escalado para adaptarse a los niveles de tráfico, es posible que las instancias estén sobrecargadas, lo que provocaría un aumento de los errores y la latencia.

  3. Si observa un aumento de errores o de latencia en Cloud Monitoring, puede que el problema se deba a la parte anterior del balanceador de carga, que registra las métricas de App Engine. En la mayoría de los casos, esto indica que hay un problema en las instancias del servicio.

  4. Si observa una latencia elevada o errores en las métricas de monitorización, pero no en los registros de solicitudes, significa que se ha producido un error en el balanceo de carga o un error grave en la instancia que impide que el balanceador de carga enrute las solicitudes. Para distinguir entre estos casos, consulta los registros de solicitudes antes de que empiece el incidente. Si los registros de solicitudes muestran una latencia cada vez mayor antes del fallo, significa que las instancias de la aplicación empezaron a fallar antes de que el balanceador de carga dejara de enrutar solicitudes a ellas.

Solucionar problemas

En esta sección se describen estrategias para solucionar problemas de latencia elevada de los siguientes componentes de la ruta de solicitud:

  1. Internet
  2. Google Front End (GFE)
  3. Infraestructura de servicio de App Engine
  4. Instancia de la aplicación
  5. Dependencias de la aplicación

Internet

Es posible que tu aplicación tenga problemas de latencia debido a una mala conectividad o a un ancho de banda inferior.

Mala conectividad a Internet

Para determinar si el problema se debe a una mala conectividad a Internet, ejecuta el siguiente comando en tu cliente:

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

El valor de time_connect representa la latencia de la conexión del cliente con el Google Front End más cercano. Si la conexión es lenta, soluciona el problema con traceroute para determinar qué salto de la red provoca el retraso.

Realiza pruebas desde clientes de diferentes ubicaciones geográficas. App Engine encamina automáticamente las solicitudes al centro de datos de Google más cercano, que varía en función de la ubicación del cliente.

Ancho de banda bajo

Puede que la aplicación responda rápidamente, pero los cuellos de botella de la red impiden que la infraestructura de servicio de App Engine envíe paquetes a través de la red rápidamente, lo que ralentiza las respuestas.

Google Front End (GFE)

Es posible que tu aplicación tenga problemas de latencia debido a un enrutamiento incorrecto, a solicitudes paralelas enviadas desde clientes HTTP/2 o a la finalización de conexiones SSL.

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

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

Bloqueo de inicio de línea de HTTP/2

Los clientes HTTP/2 que envían varias solicitudes en paralelo pueden experimentar una latencia elevada debido al bloqueo de inicio de línea en GFE. Para solucionar este problema, los clientes deben usar el protocolo QUIC.

Terminación SSL para dominios personalizados

Es posible que GFE finalice la conexión SSL. Si usas un dominio personalizado en lugar de un dominio appspot.com domain, la terminación SSL requiere un salto adicional. Esto puede añadir latencia a las aplicaciones que se ejecutan en algunas regiones. Para obtener más información, consulta Asignar dominios personalizados.

Infraestructura de servicio de App Engine

Es posible que observes una latencia elevada en tu aplicación debido a incidentes en todo el servicio o al escalado automático.

Incidentes en todo el servicio

Google publica los detalles de una interrupción grave en todo el servicio en el panel de control Estado del servicio. Sin embargo, Google lanza las actualizaciones de forma gradual, por lo que es poco probable que un incidente en todo el servicio afecte a todas tus instancias a la vez.

Autoescalado

La latencia elevada o los errores pueden deberse a los siguientes casos de autoescalado:

  • Escalar el tráfico demasiado rápido: es posible que el escalado automático de App Engine no escale tus instancias tan rápido como aumenta el tráfico, lo que puede provocar una sobrecarga temporal. Normalmente, la sobrecarga se produce cuando el tráfico lo genera un programa informático en lugar de los usuarios finales. Para solucionar este problema, limita el sistema que genera el tráfico.

  • Picos de tráfico: los picos de tráfico pueden provocar una latencia elevada en los casos en los que un servicio con autoescalado necesite aumentar la escala más rápido de lo posible, sin que esto afecte a la latencia. El tráfico de usuarios finales no suele provocar picos de tráfico frecuentes. Si detecta picos de tráfico, debe investigar la causa. Si un sistema por lotes se ejecuta a intervalos, puede que puedas suavizar el tráfico o usar ajustes de escalado diferentes.

  • Ajustes de la herramienta de adaptación dinámica: la herramienta de adaptación dinámica se puede configurar en función de las características de escalado de tu servicio. Los parámetros de escalado pueden dejar de ser óptimos en los siguientes casos:

    • Los servicios del entorno flexible de App Engine se escalan en función del uso de la CPU. Es posible que tu aplicación se vea limitada por las operaciones de E/S durante un incidente, lo que provocaría que las instancias se sobrecargaran con un gran número de solicitudes, ya que no se produce un escalado basado en la CPU.

Te recomendamos que compares el rendimiento con los ajustes de escalado predeterminados y, a continuación, realices una nueva prueba comparativa después de cada cambio en estos ajustes.

Despliegues

Una latencia elevada poco después de una implementación indica que no has aumentado la escala lo suficiente antes de migrar el tráfico. Es posible que las instancias más recientes no hayan calentado las cachés locales y que se sirvan más lentamente que las instancias más antiguas.

Para evitar picos de latencia, no despliegues un servicio de App Engine con el mismo nombre de versión que una versión ya existente del servicio. Si reutilizas un nombre de versión que ya existe, no podrás migrar el tráfico lentamente a la nueva versión. Las solicitudes pueden ser más lentas porque App Engine reinicia todas las instancias en un breve periodo. También debes volver a implementar la versión anterior.

Instancia de aplicación

En esta sección se describen las estrategias habituales que puedes aplicar a las instancias de tu aplicación y al código fuente para optimizar el rendimiento y reducir la latencia.

Código de aplicación

Puede ser difícil depurar los problemas del código de la aplicación, sobre todo si son intermitentes o no se pueden reproducir.

Para solucionar los problemas, haz lo siguiente:

  • Para diagnosticar los problemas, te recomendamos que instrumentes tu aplicación mediante registros, monitorización y trazas. También puedes usar Cloud Profiler.

  • Intenta reproducir el problema en un entorno de desarrollo local, lo que te permitirá ejecutar herramientas de depuración específicas del lenguaje que no se pueden ejecutar en App Engine.

  • Puedes acceder a una instancia mediante SSH y recopilar un volcado de pila para ver el estado actual de tu aplicación. Reproduce el problema en una prueba de carga o ejecutando la aplicación de forma local. Puedes aumentar el tamaño de la instancia para ver si así se soluciona el problema. Por ejemplo, aumentar la RAM puede solucionar los problemas de las aplicaciones que experimentan retrasos debido a la recogida de elementos no utilizados.

  • Para entender mejor cómo falla tu aplicación y qué cuellos de botella se producen, haz una prueba de carga de tu aplicación hasta que falle. Define un número máximo de instancias y, a continuación, aumenta la carga gradualmente hasta que la aplicación falle.

  • Si el problema de latencia se corresponde con la implementación de una nueva versión del código de tu aplicación, vuelve a la versión anterior para determinar si la nueva versión ha provocado el incidente. Sin embargo, si realizas implementaciones continuas, las implementaciones frecuentes dificultan determinar si la implementación ha causado el incidente en función del momento en que se ha producido.

  • Tu aplicación puede almacenar ajustes de configuración en Datastore o en otro lugar. Crea una cronología de los cambios de configuración para determinar si alguno de ellos coincide con el inicio de la latencia elevada.

Cambio de carga de trabajo

Un cambio en la carga de trabajo puede provocar un aumento de la latencia. Algunas métricas de monitorización que indican cambios en la carga de trabajo son qps, el uso de las APIs y la latencia. También debes comprobar si se han producido cambios en los tamaños de las solicitudes y las respuestas.

Errores de comprobación del estado

El balanceador de carga del entorno flexible de App Engine deja de enrutar solicitudes a las instancias que no superan las comprobaciones de estado. Esto podría aumentar la carga en otras instancias, lo que podría provocar un error en cascada. Los registros de Nginx muestran las instancias que no superan las comprobaciones de estado. Analiza tus registros y tu monitorización para determinar por qué la instancia no está en buen estado o configura comprobaciones del estado para que sean menos sensibles a los errores transitorios. Hay un breve retraso antes de que el balanceador de carga deje de enrutar el tráfico a una instancia en mal estado. Este retraso puede provocar un pico de errores si el balanceador de carga no puede volver a intentar las solicitudes.

Presión de memoria

Si la monitorización muestra un patrón de dientes de sierra en el uso de la memoria o una disminución del uso de la memoria que se corresponde con las implementaciones, es posible que la causa de los problemas de rendimiento sea una fuga de memoria. Una fuga de memoria también puede provocar una recolección de elementos no utilizados frecuente, lo que conlleva una latencia mayor. Si no puedes rastrear este problema hasta un error en el código, prueba a aprovisionar instancias más grandes con más memoria.

Fuga de recursos

Si una instancia de tu aplicación muestra una latencia creciente que se corresponde con la antigüedad de la instancia, es posible que tengas una fuga de recursos que provoque problemas de rendimiento. La latencia se reduce una vez que se completa la implementación. Por ejemplo, una estructura de datos que se ralentiza con el tiempo debido a un mayor uso de la CPU puede provocar que cualquier carga de trabajo vinculada a la CPU se ralentice.

Optimización de código

Para reducir la latencia en App Engine, optimice el código con los siguientes métodos:

  • Trabajo sin conexión: usa Cloud Tasks para evitar que las solicitudes de los usuarios bloqueen la aplicación mientras espera a que se complete el trabajo, como el envío de correos.

  • Llamadas a la API asíncronas: asegúrate de que tu código no se bloquee mientras espera a que se complete una llamada a la API.

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

  • Desnormalizar modelos de datos: reduce la latencia de las llamadas realizadas a la capa de persistencia de datos desnormalizando tus modelos de datos.

Dependencias de aplicaciones

Monitoriza las dependencias de tu aplicación para detectar si los picos de latencia se corresponden con un fallo de una dependencia.

Un cambio en la carga de trabajo y un aumento del tráfico pueden provocar que aumente la latencia de una dependencia.

Dependencia sin escalado

Si la dependencia de tu aplicación no se adapta a medida que aumenta el número de instancias de App Engine, puede que se sobrecargue cuando aumente el tráfico. Un ejemplo de dependencia que puede que no se escale es una base de datos SQL. Un mayor número de instancias de la aplicación conlleva un mayor número de conexiones de la base de datos, lo que puede provocar un fallo en cascada al impedir que la base de datos se inicie. Para solucionar este problema, sigue estos pasos:

  1. Implementa una nueva versión predeterminada que no se conecte a la base de datos.
  2. Cierra la versión predeterminada anterior.
  3. Despliega una nueva versión no predeterminada que se conecte a la base de datos.
  4. Migrar el tráfico a la nueva versión de forma gradual.

Como medida preventiva, diseña tu aplicación para que rechace solicitudes a la dependencia mediante la limitación adaptativa.

Error en la capa de almacenamiento en caché

Para acelerar las solicitudes, utiliza varias capas de almacenamiento en caché, como el almacenamiento en caché perimetral, Memcache y la memoria de la instancia. Si falla una de estas capas de almacenamiento en caché, puede producirse un aumento repentino de la latencia. Por ejemplo, un vaciado de Memcache puede provocar que se envíen más solicitudes a un almacén de datos más lento.