Soluciona problemas de latencia elevada en las apps de App Engine

En muchos casos, la latencia elevada en la aplicación da como resultado errores de servidor 5xx. Dado que la causa raíz del error y los picos de latencia pueden ser la misma, aplica las siguientes estrategias para solucionar problemas de latencia:

  1. Delimita el problema de latencia
  2. Identifica la causa
  3. Solucionar problemas

Dimensiona el problema de latencia

Para definir el alcance del problema, haz las siguientes preguntas:

  • ¿Qué aplicaciones, servicios y versiones se ven afectados por este problema?
  • ¿Qué extremos específicos del servicio se ven afectados por este problema?
  • ¿Este cambio afecta 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? Considera especificar la zona horaria.
  • ¿Cuáles son los errores específicos?
  • ¿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, ¿la mediste 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 servicio y alguna de ellas experimentó incidentes?
  • ¿Realizaste algún cambio reciente en el código, la configuración o la carga de trabajo que activó este problema?

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

Identifica la causa

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 servicio

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

  1. Supervisa los registros de solicitudes de App Engine. Si ves errores de código de estado HTTP o latencia elevada en esos registros, es probable que el problema se encuentre en la instancia que ejecuta tu servicio.

  2. Si la cantidad de instancias de servicio no se incrementó para satisfacer los niveles de tráfico, es posible que las instancias estén sobrecargadas, lo que generará errores y latencia elevados.

  3. Si ves errores elevados o latencia en Cloud Monitoring, es posible que el problema se deba a la parte 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 del servicio.

  4. Si ves una latencia elevada o errores en las métricas de supervisión, pero no en los registros de solicitud, esto indica una falla en el balanceo de cargas o una falla grave en la instancia que impide que el balanceador de cargas enrute las solicitudes. Para distinguir entre estos casos, consulta los registros de solicitud antes de que comience el incidente. Si los registros de solicitud muestran una latencia creciente antes de la falla, las instancias de la aplicación estaban empezando a fallar antes de que el balanceador de cargas dejara de enrutar las solicitudes a ellas.

Solucionar problemas

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

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

Internet

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

Conexión a Internet deficiente

Para determinar si el problema es de conectividad de Internet deficiente, 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 al Google Front End más cercano. En el caso de las conexiones lentas, soluciona problemas con traceroute para determinar qué salto en la red causa la demora.

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

Ancho de banda bajo

Es posible que la aplicación responda con rapidez, pero los cuellos de botella en la red retrasan la infraestructura de entrega de App Engine para enviar paquetes a través de la red rápidamente, lo que ralentiza las respuestas.

Google Front End (GFE)

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

Asigna 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, según la dirección IP de cliente que 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 Google no enrute las solicitudes del cliente al GFE más cercano.

Bloqueo 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. Para resolver 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, la finalización de SSL requiere un salto adicional. Esto podría agregar latencia para aplicaciones que se ejecutan en algunas regiones. Para obtener más información, consulta Asigna dominios personalizados.

Infraestructura de entrega de App Engine

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

Incidentes en todo el servicio

Google publica los detalles de una interrupción grave en todo el servicio en el panel de 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.

Ajuste de escala automático

Los siguientes casos de ajuste de escala automático pueden generar una latencia o errores elevados:

  • 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, la sobrecarga ocurre cuando un programa informático genera tráfico en lugar de los usuarios finales. Para resolver este problema, limita el sistema que genera el tráfico.

  • Aumentos repentinos de tráfico: Los aumentos repentinos de tráfico pueden causar una latencia elevada en casos en los que un servicio 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 observas aumentos repentinos del tráfico, debes investigar la causa. 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 servicio. Los parámetros de escalamiento pueden volverse no óptimos en las siguientes situaciones:

    • 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 "Se anuló la solicitud después de esperar demasiado tiempo para intentar atenderla" en tus registros, significa que se agotó el tiempo de espera de la solicitud en la fila pendiente mientras esperaba una instancia inactiva.

    • Es posible que notes un aumento en el tiempo pendiente con el escalamiento manual, incluso cuando aprovisionas suficientes instancias. Te recomendamos que no uses el ajuste de escala manual si tu aplicación entrega tráfico de usuario final. El ajuste de escala manual es mejor para cargas de trabajo como las listas de tareas en cola.

    • El ajuste de escala básico minimiza los costos a expensas de la latencia. Te recomendamos que no uses el ajuste de escala básico para los servicios sensibles a la latencia.

    • El parámetro de configuración de escalamiento predeterminado de App Engine proporciona una latencia óptima para la mayoría de los servicios. Si aún ves solicitudes con un tiempo pendiente alto, especifica una cantidad mínima de instancias. Si ajustas la configuración de escalamiento para reducir costos minimizando las instancias inactivas, corres el riesgo de que se produzcan aumentos repentinos de latencia si la carga aumenta de forma repentina.

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

Implementaciones

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 un servicio de App Engine con el mismo nombre de versión que una versión existente del servicio. 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 App Engine reinicia cada instancia 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

En esta sección, se describen las estrategias comunes 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 la aplicación

Los problemas en el código de la aplicación pueden ser difíciles de depurar, en especial si son intermitentes o no se pueden reproducir.

Para resolver problemas, haz lo siguiente:

  • Para diagnosticar tus problemas, te recomendamos que instrumentes tu aplicación con registro, supervisión y seguimiento. También puedes usar Cloud Profiler.

  • Intenta reproducir el problema en un entorno de desarrollo local que podría permitirte ejecutar herramientas de depuración específicas del lenguaje que no son posibles para ejecutarlas en App Engine.

  • Para comprender mejor cómo falla la aplicación 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, revierte la implementación para determinar si la versión nueva causó el incidente. Sin embargo, si implementas de forma continua, las implementaciones frecuentes dificultan 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. Crea 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 indican cambios en la carga de trabajo incluyen qps, el uso de la API y la latencia. También puedes verificar si hay cambios en los tamaños de solicitud y respuesta.

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, es posible que una fuga de memoria sea la causa de los problemas de rendimiento. Una fuga de memoria también puede causar una recolección de elementos no utilizados frecuente, lo que genera una latencia más alta. Si no puedes rastrear este problema hasta un error en el código, intenta 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 correlaciona con la antigüedad de la instancia, es posible que tengas una filtración de recursos que cause problemas de rendimiento. La latencia disminuye después de que se completa 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.

Optimizar código

Para reducir la latencia en App Engine, optimiza 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 que se complete el trabajo, 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.

  • 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.

  • Desnormaliza los modelos de datos: Reduce la latencia de las llamadas realizadas a la capa de persistencia de datos desnormalizando tus modelos de datos.

Dependencias de la aplicación

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

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

Dependencia sin escalamiento

Si la dependencia de tu aplicación no se ajusta a medida que aumenta la cantidad de instancias de App Engine, es posible que la dependencia se sobrecargue cuando aumente el tráfico. Un ejemplo de una dependencia que podría no escalar es una base de datos SQL. Una mayor cantidad de instancias de la aplicación genera 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. Para solucionar este problema, haz lo 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.

Como medida preventiva, diseña tu aplicación para que descarte las solicitudes a la dependencia con la regulación adaptable.

Falla de la capa de almacenamiento en caché

Para acelerar las solicitudes, usa varias capas de almacenamiento en caché, como el almacenamiento en caché perimetral, Memcache y la memoria en la instancia. Un error en una de estas capas de almacenamiento en caché puede provocar un aumento repentino en la latencia. Por ejemplo, una limpieza de Memcache puede hacer que más solicitudes vayan a un Datastore más lento.