Tiempo de respuesta alto esporádico de Heroku

Esto es muy específico, pero trataré de ser breve:

Estamos ejecutando una aplicación Django en Heroku . Tres servidores:

  1. test (1 web, 1 apio dyno)
  2. Entrenamiento (1 web, 1 apio dyno).
  3. prod (2 web, 1 apio dyno).

Estamos utilizando Gunicorn con gevents y 4 trabajadores en cada dinamómetro .

Estamos experimentando tiempos de servicio elevados esporádicos . Aquí hay un ejemplo de Logentries:

High Response Time: heroku router - - at=info method=GET path="/accounts/login/" dyno=web.1 connect=1ms service=6880ms status=200 bytes=3562 

He estado buscando en Google por semanas. No podemos reproducir a voluntad, pero experimentamos estas alertas de 0 a 5 veces al día. Puntos notables :

    • Ocurre en las tres aplicaciones (todas ejecutan código similar)
    • Ocurre en diferentes páginas, incluyendo páginas simples como 404 y / admin
    • Ocurre en tiempos aleatorios
    • Ocurre con un rendimiento variable. Una de nuestras instancias solo conduce 3 usuarios / día. No está relacionado con las dinámicas de sueño porque hacemos ping con New Relic y el problema puede ocurrir a mitad de sesión
    • No se puede reproducir a voluntad. He experimentado este problema personalmente una vez. Al hacer clic en una página que normalmente se ejecuta en 500 ms, se produce un retraso de 30 segundos y, finalmente, una pantalla de error de la aplicación del tiempo de espera de los 30 años de Heroku.
    • Los tiempos de respuesta elevados varían de 5000 ms a 30000 ms.
    • New Relic no apunta a un problema específico. Aquí están las últimas transacciones y tiempos:
      • RegexURLResolver.resolve 4,270ms
      • SessionMiddleware.process_request 2,750ms
      • Render login.html 1,230ms
      • WSGIHandler 1,390ms
      • Lo anterior son llamadas sencillas y normalmente no toman casi esa cantidad de tiempo.

    Lo que he reducido a :

    1. Este artículo sobre Gunicorn y clientes lentos.
      • He visto que este problema ocurre con clientes lentos pero también en nuestra oficina donde tenemos una conexión de fibra.
    2. Trabajadores de Gevent y asíncronos que no juegan bien.
      • Hemos cambiado a gunicorn sync workers y el problema persiste.
    3. Trabajador Gunicorn tiempo de espera
      • Es posible que los trabajadores se mantengan vivos de alguna manera en un estado nulo.
    4. Insuficientes trabajadores / dynos
      • No hay indicación de la sobreutilización de la CPU / memoria / db y New Relic no muestra ninguna indicación de latencia de DB
    5. Vecinos ruidosos
      • Entre mis múltiples correos electrónicos con Heroku, el representante de soporte ha mencionado que al menos uno de mis pedidos largos se debió a un vecino ruidoso, pero no estaba convencido de que ese fuera el problema.
    6. Subdominio 301
      • Las solicitudes llegan bien, pero se atascan aleatoriamente en la aplicación.
    7. Reinicio de Dynos
      • Si este fuera el caso, muchos usuarios se verían afectados. Además, puedo ver que nuestros dynos no se han reiniciado recientemente.
    8. Heroku enrutamiento / problema de servicio
      • Es posible que el servicio de Heroku sea menos que anunciado y esto es simplemente una desventaja de usar su servicio.

    Hemos estado teniendo este problema durante los últimos meses, pero ahora que lo estamos escalando, debemos solucionarlo. Cualquier idea sería muy apreciada ya que he agotado casi todos los SO o enlaces de Google.

    He estado en contacto con el equipo de soporte de Heroku durante los últimos 6 meses. Ha sido un largo período de reducción a través de prueba / error, pero hemos identificado el problema.

    Finalmente noté que estos altos tiempos de respuesta se correspondían con un repentino intercambio de memoria, y aunque estaba pagando un Estándar Dyno (que no estaba inactivo), estos intercambios de memoria tenían lugar cuando mi aplicación no había recibido tráfico recientemente. También quedó claro al observar los gráficos de métricas que esto no fue una pérdida de memoria porque la memoria se estabilizaría. Por ejemplo:

    Intercambio de memoria repentina

    Después de muchas discusiones con su equipo de apoyo, me dieron esta explicación:

    Esencialmente, lo que sucede es que algunos tiempos de ejecución de back-end terminan con una combinación de aplicaciones que terminan usando suficiente memoria que el tiempo de ejecución tiene que intercambiar. Cuando eso sucede, se obliga a un conjunto aleatorio de contenedores dynamics en el tiempo de ejecución a intercambiar arbitrariamente pequeñas cantidades (tenga en cuenta que aquí es probable que los contenedores con memoria a los que no se haya accedido recientemente, pero que aún residan en la memoria). Al mismo tiempo, las aplicaciones que utilizan grandes cantidades de memoria también terminan intercambiando mucho, lo que provoca más iowait en el tiempo de ejecución de lo normal.

    No hemos cambiado la forma en que empaquetamos los tiempos de ejecución desde que este problema comenzó a ser más evidente, por lo que nuestra hipótesis actual es que el problema puede deberse a que los clientes pasaron de las versiones de Ruby anteriores a 2.1 a 2.1 o superior. Ruby compensa un gran porcentaje de las aplicaciones que se ejecutan en nuestra plataforma y Ruby 2.1 realizó cambios en su GC que cambia el uso de la memoria por velocidad (esencialmente, GCs con menos frecuencia para obtener ganancias de velocidad). Esto resulta en un aumento notable en el uso de memoria para cualquier aplicación que se mueva desde versiones anteriores de Ruby. Como tal, la misma cantidad de aplicaciones Ruby que mantenían un cierto nivel de uso de memoria antes ahora comenzaría a requerir más uso de memoria.

    Ese fenómeno, combinado con el mal comportamiento de las aplicaciones que tienen un uso indebido de recursos en la plataforma, alcanzó un punto de inflexión que nos llevó a la situación en la que nos encontramos ahora donde se encuentran los conceptos que no deberían intercambiarse. Tenemos algunas vías de ataque que estamos investigando, pero por ahora, muchas de las anteriores son todavía un poco especulativas. Sin embargo, sabemos con certeza que parte de esto está siendo causado por aplicaciones que abusan de los recursos y esa es la razón por la que el cambio al rendimiento Performance-M o Performance-L (que tienen tiempos de ejecución de back-end dedicados) no debería presentar el problema. El único uso de memoria en esas dinámicas será su aplicación. Entonces, si hay intercambio será porque su aplicación lo está causando.

    Estoy seguro de que este es el problema que yo y otros hemos estado experimentando, ya que está relacionado con la architecture en sí y no con ninguna combinación de lenguaje / marco / configuración.

    Parece que no hay una buena solución que no sea A) endurecer y esperar o B) cambiar a una de sus instancias dedicadas

    Soy consciente de la multitud que dice “Por eso debería usar AWS”, pero creo que los beneficios que ofrece Heroku superan algunos tiempos de respuesta altos ocasionales y su precio ha mejorado a lo largo de los años. Si padece el mismo problema, la “mejor solución” será su elección. Actualizaré esta respuesta cuando escuche algo más.

    ¡Buena suerte!

    No estoy seguro de que esto ayude en absoluto, pero estoy pasando por lo mismo con una aplicación Rails ahora mismo en Heroku: aparentemente no determinista esporádicamente tiempos de solicitud altos. Por ejemplo, el tiempo de actividad de HEAD New Relic hace ping a mi índice de sitio que normalmente demora entre 2 y 5 ms en 5 segundos, o el inicio de sesión en mi sitio, que normalmente dura menos de 12 segundos. También ocasionalmente obtendrás tiempos de espera de 30s al azar. Esto es lo que el apoyo de Heroku tenía que decir en mi caso (al menos en algunos de los casos):

    El anterior de hoy parece una gran parte de Request Queueing después de un reinicio. Si desea evitarlos, puede que desee echar un vistazo a nuestra función de prearranque . Esto le permitirá iniciar un conjunto de diálogos coincidentes después de una implementación, luego pasarles las solicitudes en lugar de eliminar los diálogos existentes y forzar la puesta en cola de solicitudes.

    Debo señalar que este fue uno de los reinicios estándar de Heroku, no un despliegue mío ni nada. A pesar de las advertencias en la página de inicio, lo habilité hace unos minutos, así que veremos si hay alguna diferencia en mi caso. Espero que pueda ayudar, ya que me he estado sacando el pelo por esto también!