Post mortem sobre la indisponibilidad de Quay.io

Nota. traducir: a principios de agosto, Red Hat habló públicamente sobre la solución de los problemas de accesibilidad que los usuarios de su servicio habían encontrado en meses anteriores Muelle.io (Se basa en un registro de imágenes de contenedores, que la empresa recibió junto con la compra de CoreOS). Independientemente de su interés en este servicio como tal, resulta instructivo el camino que recorrieron los ingenieros de la SRE de la empresa para diagnosticar y eliminar las causas del accidente.

Post mortem sobre la indisponibilidad de Quay.io

El 19 de mayo, temprano en la mañana (hora de verano del este, EDT), el servicio quay.io falló. El accidente afectó tanto a los consumidores de quay.io como a los proyectos de código abierto que utilizan quay.io como plataforma para crear y distribuir software. Red Hat valora la confianza de ambos.

Un equipo de ingenieros de SRE se implicó inmediatamente e intentó estabilizar el servicio del Muelle lo antes posible. Sin embargo, mientras hacían esto, los clientes perdieron la capacidad de enviar nuevas imágenes y solo ocasionalmente pudieron extraer las existentes. Por alguna razón desconocida, la base de datos quay.io fue bloqueada después de escalar el servicio a su capacidad máxima.

«¿Qué ha cambiado?" - ésta es la primera pregunta que se suele hacer en estos casos. Notamos que poco antes del problema, el clúster OpenShift Dedicated (que ejecuta quay.io) comenzó a actualizarse a la versión 4.3.19. Dado que quay.io se ejecuta en Red Hat OpenShift Dedicated (OSD), las actualizaciones periódicas eran rutinarias y nunca causaron problemas. Además, durante los seis meses anteriores, hemos actualizado los grupos de Quay varias veces sin ninguna interrupción del servicio.

Mientras intentábamos restaurar el servicio, otros ingenieros comenzaron a preparar un nuevo clúster OSD con la versión anterior del software, para que, si pasaba algo, pudieran implementar todo en él.

Análisis de raíz de la causa

El síntoma principal del fallo fue una avalancha de decenas de miles de conexiones de bases de datos, que hicieron que la instancia de MySQL fuera efectivamente inoperable. Esto dificultó el diagnóstico del problema. Hemos establecido un límite en la cantidad máxima de conexiones de clientes para ayudar al equipo de SRE a evaluar el problema. No notamos ningún tráfico inusual en la base de datos: de hecho, la mayoría de las solicitudes fueron leídas y solo unas pocas fueron escritas.

También intentamos identificar un patrón en el tráfico de la base de datos que podría causar esta avalancha. Sin embargo, no pudimos encontrar ningún patrón en los registros. Mientras esperábamos que el nuevo clúster con OSD 4.3.18 estuviera listo, continuamos intentando iniciar los pods de quay.io. Cada vez que el clúster alcanzaba su capacidad máxima, la base de datos se congelaba. Esto significó que era necesario reiniciar la instancia de RDS además de todos los pods de quay.io.

Por la noche, estabilizamos el servicio en modo de solo lectura y desactivamos tantas funciones no esenciales como fuera posible (por ejemplo, recolección de basura del espacio de nombres) para reducir la carga en la base de datos. Las heladas han cesado pero nunca se encontró la razón. El nuevo cluster OSD estaba listo y migramos el servicio, conectamos el tráfico y continuamos con el monitoreo.

Quay.io funcionó de manera estable en el nuevo clúster OSD, por lo que volvimos a los registros de la base de datos, pero no pudimos encontrar una correlación que explicara los bloqueos. Los ingenieros de OpenShift trabajaron con nosotros para comprender si los cambios en Red Hat OpenShift 4.3.19 podrían causar problemas con Quay. Sin embargo, no se encontró nada y No fue posible reproducir el problema en condiciones de laboratorio..

Segundo fracaso

El 28 de mayo, poco antes del mediodía EDT, quay.io volvió a fallar con el mismo síntoma: la base de datos estaba bloqueada. Y nuevamente volcamos todos nuestros esfuerzos en la investigación. En primer lugar, era necesario restablecer el servicio. Sin embargo esta vez reiniciar RDS y reiniciar los pods de quay.io no hizo nada: otra avalancha de conexiones ha desbordado la base. ¿Pero por qué?

Quay está escrito en Python y cada módulo funciona como un único contenedor monolítico. El tiempo de ejecución del contenedor ejecuta muchas tareas paralelas simultáneamente. Usamos la biblioteca gevent bajo gunicorn para procesar solicitudes web. Cuando una solicitud llega a Quay (a través de nuestra propia API o de la API de Docker), se le asigna un trabajador gevent. Normalmente, este trabajador debe ponerse en contacto con la base de datos. Después del primer error, descubrimos que los trabajadores de gevent se estaban conectando a la base de datos utilizando la configuración predeterminada.

Dada la importante cantidad de pods de Quay y miles de solicitudes entrantes por segundo, una gran cantidad de conexiones de bases de datos podría, en teoría, abrumar la instancia de MySQL. Gracias al seguimiento se conoció que Quay procesa en promedio 5 mil solicitudes por segundo. El número de conexiones a la base de datos fue aproximadamente el mismo. 5 mil conexiones estaban dentro de las capacidades de nuestra instancia RDS (lo que no se puede decir de decenas de miles). Por alguna razón, hubo picos inesperados en la cantidad de conexiones., sin embargo, no notamos ninguna correlación con las solicitudes entrantes.

Esta vez estábamos decididos a encontrar y eliminar la fuente del problema y no limitarnos a reiniciar. Al código base de Quay Se realizaron cambios para limitar el número de conexiones a la base de datos para cada trabajador. evento. Este número se convirtió en un parámetro en la configuración: fue posible cambiarlo sobre la marcha sin crear una nueva imagen de contenedor. Para descubrir cuántas conexiones se podrían manejar de manera realista, ejecutamos varias pruebas en un entorno de prueba, estableciendo diferentes valores para ver cómo esto afectaría los escenarios de prueba de carga. Como resultado, se descubrió que Quay comienza a arrojar errores 502 cuando el número de conexiones supera las 10 mil.

Inmediatamente implementamos esta nueva versión en producción y comenzamos a monitorear el cronograma de conexión de la base de datos. En el pasado, la base se cerraba después de unos 20 minutos. Después de 30 minutos sin problemas teníamos esperanza y una hora después teníamos confianza. Restauramos el tráfico al sitio y comenzamos el análisis post mortem.

Habiendo logrado evitar el problema que provoca el bloqueo, no hemos descubierto sus verdaderas razones. Se confirmó que no está relacionado con ningún cambio en OpenShift 4.3.19, ya que sucedió lo mismo en la versión 4.3.18, que anteriormente funcionaba con Quay sin problemas.

Claramente había algo más acechando en el grupo.

Estudio detallado

Quay.io utilizó la configuración predeterminada para conectarse a la base de datos durante seis años sin ningún problema. ¿Qué cambió? Está claro que durante todo este tiempo el tráfico en quay.io ha ido creciendo de forma constante. En nuestro caso, parecía como si se hubiera alcanzado algún valor umbral, lo que sirvió de detonante para una avalancha de conexiones. Continuamos estudiando los registros de la base de datos después del segundo fallo, pero no encontramos ningún patrón ni relación obvia.

Mientras tanto, el equipo de SRE ha estado trabajando para mejorar la observabilidad de las solicitudes de Quay y el estado general del servicio. Se han implementado nuevas métricas y paneles, que muestra qué partes del Muelle son las más demandadas por los clientes.

Quay.io funcionó bien hasta el 9 de junio. Esta mañana (EDT) volvimos a ver un aumento significativo en el número de conexiones a bases de datos. Esta vez no hubo tiempo de inactividad, ya que el nuevo parámetro limitó su número y no les permitió exceder el rendimiento de MySQL. Sin embargo, durante aproximadamente media hora, muchos usuarios notaron un rendimiento lento de quay.io. Recopilamos rápidamente todos los datos posibles utilizando las herramientas de monitoreo agregadas. De repente surgió un patrón.

Justo antes del aumento de las conexiones, se realizó una gran cantidad de solicitudes a la API de App Registry. App Registry es una característica poco conocida de quay.io. Le permite almacenar cosas como gráficos de Helm y contenedores con metadatos enriquecidos. La mayoría de los usuarios de quay.io no trabajan con esta función, pero Red Hat OpenShift la utiliza activamente. OperadorHub, como parte de OpenShift, almacena todos los operadores en el Registro de aplicaciones. Estos operadores forman la base del ecosistema de cargas de trabajo de OpenShift y del modelo operativo centrado en los socios (operaciones del día 2).

Cada clúster de OpenShift 4 utiliza operadores del OperatorHub integrado para publicar un catálogo de operadores disponibles para instalación y proporcionar actualizaciones a los que ya están instalados. Con la creciente popularidad de OpenShift 4, también ha aumentado la cantidad de clústeres en todo el mundo. Cada uno de estos clústeres descarga contenido del operador para ejecutar el OperatorHub integrado, utilizando el Registro de aplicaciones dentro de quay.io como backend. En nuestra búsqueda del origen del problema, pasamos por alto el hecho de que a medida que OpenShift crecía gradualmente en popularidad, también aumentaba la carga en una de las funciones de quay.io poco utilizadas..

Hicimos un análisis del tráfico de solicitudes de registro de aplicaciones y echamos un vistazo al código de registro. Inmediatamente se revelaron deficiencias, por lo que las consultas a la base de datos no se formaron de manera óptima. Cuando la carga era baja, no causaban ningún problema, pero cuando la carga aumentaba, se convertían en una fuente de problemas. App Registry resultó tener dos puntos finales problemáticos que no respondieron bien al aumento de la carga: el primero proporcionó una lista de todos los paquetes en el repositorio, el segundo devolvió todos los blobs del paquete.

Eliminación de causas

Durante la siguiente semana dedicamos a optimizar el código del Registro de aplicaciones y su entorno. Se reelaboraron consultas SQL claramente ineficaces y se eliminaron llamadas de comandos innecesarias. tar (se ejecutaba cada vez que se recuperaban blobs), se agregaba almacenamiento en caché siempre que era posible. Luego realizamos pruebas de rendimiento exhaustivas y comparamos la velocidad del Registro de aplicaciones antes y después de los cambios.

Las solicitudes de API que antes tardaban hasta medio minuto ahora se completan en milisegundos. La semana siguiente implementamos los cambios en producción y desde entonces quay.io ha estado funcionando de manera estable. Durante este tiempo, hubo varios picos bruscos en el tráfico en el punto final del Registro de aplicaciones, pero las mejoras realizadas evitaron interrupciones en la base de datos.

¿Qué hemos aprendido?

Está claro que cualquier servicio intenta evitar el tiempo de inactividad. En nuestro caso, creemos que las recientes interrupciones han ayudado a mejorar quay.io. Hemos aprendido algunas lecciones clave que nos gustaría compartir:

  1. Los datos sobre quién utiliza tu servicio y cómo nunca son superfluos. Debido a que Quay "simplemente funcionó", nunca tuvimos que dedicar tiempo a optimizar el tráfico y administrar la carga. Todo esto creó una falsa sensación de seguridad de que el servicio podría escalar indefinidamente.
  2. Cuando el servicio se cae, volver a ponerlo en funcionamiento es una prioridad absoluta.. Debido a que Quay siguió sufriendo una base de datos bloqueada durante la primera interrupción, nuestros procedimientos estándar no tuvieron el efecto deseado y no pudimos restaurar el servicio usándolos. Esto llevó a una situación en la que había que dedicar tiempo a analizar y recopilar datos con la esperanza de encontrar la causa raíz, en lugar de centrar todos los esfuerzos en restaurar la funcionalidad.
  3. Evaluar el impacto de cada característica del servicio. Los clientes rara vez usaban App Registry, por lo que no era una prioridad para nuestro equipo. Cuando algunas características del producto apenas se utilizan, sus errores rara vez aparecen y los desarrolladores dejan de monitorear el código. Es fácil caer presa de la idea errónea de que así debe ser, hasta que de repente esa función se encuentra en el centro de un incidente importante.

¿Qué será lo próximo?

El trabajo para garantizar la estabilidad del servicio nunca se detiene y lo estamos mejorando constantemente. A medida que los volúmenes de tráfico continúan creciendo en quay.io, reconocemos que tenemos la responsabilidad de hacer todo lo posible para estar a la altura de la confianza de nuestros clientes. Por ello, actualmente estamos trabajando en las siguientes tareas:

  1. Implemente réplicas de bases de datos de solo lectura para ayudar al servicio a manejar el tráfico adecuado en caso de problemas con la instancia de RDS principal.
  2. Actualización de una instancia RDS. La versión actual en sí no es el problema. Más bien, simplemente queremos eliminar el rastro falso (que seguimos durante el fracaso); Mantener el software actualizado eliminará otro factor en caso de futuras interrupciones.
  3. Almacenamiento en caché adicional en todo el clúster. Seguimos buscando áreas donde el almacenamiento en caché pueda reducir la carga de la base de datos.
  4. Agregar un firewall de aplicaciones web (WAF) para ver quién se conecta a quay.io y por qué.
  5. A partir de la próxima versión, los clústeres de Red Hat OpenShift abandonarán el Registro de aplicaciones en favor de los Catálogos de operadores basados ​​en imágenes de contenedores disponibles en quay.io.
  6. Un reemplazo a largo plazo para App Registry podría ser la compatibilidad con las especificaciones de artefactos de Open Container Initiative (OCI). Actualmente está implementado como funcionalidad nativa de Quay y estará disponible para los usuarios cuando se finalice la especificación.

Todo lo anterior es parte de la inversión continua de Red Hat en quay.io a medida que pasamos de un pequeño equipo "estilo startup" a una plataforma madura impulsada por SRE. Sabemos que muchos de nuestros clientes confían en quay.io en su trabajo diario (¡incluido Red Hat!) e intentamos ser lo más transparentes posible sobre las interrupciones recientes y los esfuerzos continuos para mejorar.

PD del traductor

Lea también en nuestro blog:

Fuente: habr.com

Añadir un comentario