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:
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:
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.
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.
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.
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:
- Internet
- Google Front End (GFE)
- Infraestructura de servicio de App Engine
- Instancia de la aplicación
- 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 ajustes de escalado del entorno estándar de App Engine pueden provocar latencia si se configuran de forma 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" (La solicitud se ha cancelado tras esperar demasiado tiempo para intentar atenderla) en tus registros, significa que la solicitud ha agotado el tiempo de espera en la cola pendiente mientras esperaba una instancia inactiva.Es posible que el tiempo de espera aumente con el escalado manual, incluso cuando hayas aprovisionado suficientes instancias. Te recomendamos que no uses el escalado manual si tu aplicación sirve tráfico de usuarios finales. El escalado manual es más adecuado para cargas de trabajo como las colas de tareas.
El escalado básico minimiza los costes a costa de la latencia. Te recomendamos que no uses el escalado básico en servicios sensibles a la latencia.
El ajuste de escalado predeterminado de App Engine proporciona una latencia óptima para la mayoría de los servicios. Si sigues viendo solicitudes con un tiempo de espera alto, especifica un número mínimo de instancias. Si ajustas la configuración del escalado para reducir los costes minimizando las instancias inactivas, corres el riesgo de que se produzcan picos de latencia si la carga aumenta de repente.
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.
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.
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:
- Implementa una nueva versión predeterminada que no se conecte a la base de datos.
- Cierra la versión predeterminada anterior.
- Despliega una nueva versión no predeterminada que se conecte a la base de datos.
- 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.