Non dispoñibilidade de Post Mortem en Quay.io

Nota. transl.: a principios de agosto, Red Hat falou publicamente sobre a solución dos problemas de accesibilidade que atoparan os usuarios do seu servizo nos meses anteriores. Quay.io (basase nun rexistro de imaxes de contedores, que a empresa recibiu xunto coa compra de CoreOS). Independentemente do seu interese neste servizo como tal, o camiño que seguiron os enxeñeiros de SRE da empresa para diagnosticar e eliminar as causas do accidente é instrutivo.

Non dispoñibilidade de Post Mortem en Quay.io

O 19 de maio, á primeira hora da mañá (Eastern Daylight Time, EDT), o servizo quay.io fallou. O accidente afectou tanto a consumidores de quay.io como a proxectos de código aberto que utilizan quay.io como plataforma para construír e distribuír software. Red Hat valora a confianza de ambos.

Un equipo de enxeñeiros de SRE involucrouse inmediatamente e intentou estabilizar o servizo de Quay canto antes. Non obstante, mentres facían isto, os clientes perderon a capacidade de impulsar novas imaxes e só ocasionalmente puideron sacar as existentes. Por algún motivo descoñecido, bloqueouse a base de datos de quay.io despois de escalar o servizo ao máximo.

«Que cambiou?"- esta é a primeira pregunta que se adoita facer nestes casos. Observamos que pouco antes do problema, o clúster OpenShift Dedicated (que executa quay.io) comezou a actualizarse á versión 4.3.19. Dado que quay.io funciona con Red Hat OpenShift Dedicated (OSD), as actualizacións periódicas eran rutinarias e nunca causaban problemas. Ademais, durante os seis meses anteriores, actualizamos os clústeres de Quay varias veces sen interrupción do servizo.

Mentres estabamos tentando restaurar o servizo, outros enxeñeiros comezaron a preparar un novo clúster de OSD coa versión anterior do software, para que se pasase algo, puidesen despregar todo nel.

Análise da causa raíz

O principal síntoma do fallo foi unha avalancha de decenas de miles de conexións de bases de datos, o que fixo que a instancia de MySQL fose efectivamente inoperable. Isto dificultou o diagnóstico do problema. Fixemos un límite no número máximo de conexións dos clientes para axudar ao equipo de SRE a avaliar o problema. Non observamos ningún tráfico inusual á base de datos: de feito, a maioría das solicitudes foron lidas e só algunhas foron escritas.

Tamén tentamos identificar un patrón no tráfico da base de datos que podería provocar esta avalancha. Non obstante, non puidemos atopar ningún patrón nos rexistros. Mentres agardabamos a que estea listo o novo clúster con OSD 4.3.18, seguimos intentando lanzar pods de quay.io. Cada vez que o clúster alcanzaba a súa capacidade máxima, a base de datos conxelábase. Isto significaba que era necesario reiniciar a instancia RDS ademais de todos os pods de quay.io.

Á noite, estabilizamos o servizo en modo de só lectura e desactivamos tantas funcións non esenciais como sexa posible (por exemplo, a recollida de lixo do espazo de nomes) para reducir a carga da base de datos. Pararon as conxelacións pero nunca se atopou a razón. O novo clúster OSD estaba listo e migramos o servizo, conectamos o tráfico e continuamos coa vixilancia.

Quay.io traballou de forma estable no novo clúster OSD, polo que volvemos aos rexistros da base de datos, pero non puidemos atopar unha correlación que explicase os bloqueos. Os enxeñeiros de OpenShift traballaron connosco para comprender se os cambios en Red Hat OpenShift 4.3.19 poderían causar problemas con Quay. Non obstante, non se atopou nada, e Non foi posible reproducir o problema en condicións de laboratorio.

Segundo fracaso

O 28 de maio, pouco antes do mediodía EDT, quay.io volveu fallar co mesmo síntoma: a base de datos estaba bloqueada. E de novo botamos todos os nosos esforzos na investigación. En primeiro lugar, foi necesario restaurar o servizo. Porén esta vez, reiniciar RDS e reiniciar os pods de quay.io non fixo nada: outra avalancha de conexións desbordou a base. Pero por qué?

Quay está escrito en Python e cada pod funciona como un único recipiente monolítico. O tempo de execución do contedor executa moitas tarefas paralelas simultaneamente. Usamos a biblioteca gevent en gunicorn para procesar solicitudes web. Cando unha solicitude chega a Quay (a través da nosa propia API ou a través da API de Docker), asígnaselle un traballador gevent. Normalmente este traballador debería contactar coa base de datos. Despois do primeiro fallo, descubrimos que os traballadores de Gevent estaban conectando á base de datos mediante a configuración predeterminada.

Dado o número significativo de pods Quay e miles de solicitudes entrantes por segundo, un gran número de conexións de bases de datos poderían teoricamente desbordar a instancia de MySQL. Grazas ao seguimento, soubo que Quay procesa unha media de 5 mil solicitudes por segundo. O número de conexións á base de datos foi aproximadamente o mesmo. 5 mil conexións estaban dentro das capacidades da nosa instancia RDS (o que non se pode dicir sobre decenas de miles). Por algunha razón houbo picos inesperados no número de conexións, non obstante, non observamos ningunha correlación coas solicitudes entrantes.

Esta vez estabamos decididos a buscar e eliminar a orixe do problema, e non limitarnos a un reinicio. Ao código base de Quay fixéronse cambios para limitar o número de conexións á base de datos para cada traballador xevent. Este número converteuse nun parámetro da configuración: foi posible cambialo sobre a marcha sen construír unha nova imaxe de contedor. Para saber cantas conexións se poderían manexar de forma realista, realizamos varias probas nun ambiente de proba, establecendo diferentes valores para ver como afectaría isto aos escenarios de probas de carga. Como resultado, descubriuse que Quay comeza a lanzar 502 erros cando o número de conexións supera os 10 mil.

Inmediatamente implementamos esta nova versión en produción e comezamos a supervisar o calendario de conexións á base de datos. No pasado, a base estaba bloqueada despois duns 20 minutos. Despois de 30 minutos sen problemas tiñamos esperanza, e unha hora despois tiñamos confianza. Restauramos o tráfico ao sitio e comezamos a análise post mortem.

Conseguindo evitar o problema que leva ao bloqueo, non descubrimos as súas verdadeiras razóns. Confirmouse que non está relacionado con ningún cambio en OpenShift 4.3.19, xa que ocorreu o mesmo na versión 4.3.18, que anteriormente funcionaba con Quay sen problemas.

Había claramente algo máis á espreita no grupo.

Estudo detallado

Quay.io utilizou a configuración predeterminada para conectarse á base de datos durante seis anos sen ningún problema. Que cambiou? Está claro que durante todo este tempo o tráfico en quay.io foi crecendo constantemente. No noso caso, parecía que se alcanzara algún valor límite, que serviu de detonante dunha avalancha de conexións. Seguimos estudando os rexistros da base de datos despois do segundo fallo, pero non atopamos patróns nin relacións obvias.

Mentres tanto, o equipo de SRE estivo a traballar en melloras na observabilidade das solicitudes de Quay e na saúde xeral do servizo. Desplegáronse novas métricas e paneis de control, mostrando cales son as partes do peirao máis demandadas polos clientes.

Quay.io funcionou ben ata o 9 de xuño. Esta mañá (EDT) volvemos a ver un aumento significativo no número de conexións a bases de datos. Esta vez non houbo tempo de inactividade, xa que o novo parámetro limitaba o seu número e non lles permitía superar o rendemento de MySQL. Non obstante, durante aproximadamente media hora, moitos usuarios observaron un rendemento lento de quay.io. Recopilamos rapidamente todos os datos posibles mediante as ferramentas de seguimento engadidas. De súpeto xurdiu un patrón.

Xusto antes do aumento das conexións, realizáronse un gran número de solicitudes á API do rexistro de aplicacións. O Rexistro de aplicacións é unha característica pouco coñecida de quay.io. Permítelle almacenar cousas como gráficos Helm e contedores con metadatos ricos. A maioría dos usuarios de quay.io non traballan con esta función, pero Red Hat OpenShift utilízaa activamente. OperatorHub como parte de OpenShift almacena todos os operadores no Rexistro de aplicacións. Estes operadores forman a base para o ecosistema de carga de traballo OpenShift e o modelo operativo centrado no socio (operacións do día 2).

Cada clúster de OpenShift 4 utiliza operadores do OperatorHub integrado para publicar un catálogo de operadores dispoñibles para a instalación e proporcionar actualizacións aos que xa están instalados. Coa crecente popularidade de OpenShift 4, tamén aumentou o número de clusters en todo o mundo. Cada un destes clústeres descarga o contido do operador para executar o OperatorHub integrado, utilizando o Rexistro de aplicacións dentro de quay.io como backend. Na nosa procura da orixe do problema, perdemos o feito de que a medida que OpenShift foi crecendo gradualmente en popularidade, tamén aumentou a carga dunha das funcións de quay.io pouco usadas..

Fixemos unha análise do tráfico de solicitudes do Rexistro de aplicacións e fixemos un ollo ao código do rexistro. Inmediatamente, reveláronse deficiencias, polo que as consultas á base de datos non se formaron de forma óptima. Cando a carga era baixa, non causaban ningún problema, pero cando a carga aumentaba, convertíanse nunha fonte de problemas. O rexistro de aplicacións resultou ter dous extremos problemáticos que non respondían ben ao aumento da carga: o primeiro proporcionaba unha lista de todos os paquetes do repositorio, o segundo devolveu todos os blobs do paquete.

Eliminación de causas

Durante a próxima semana dedicámonos a optimizar o código do propio Rexistro de Apps e o seu entorno. As consultas SQL claramente ineficaces foron reelaboradas e elimináronse as chamadas de comandos innecesarias tar (executouse cada vez que se recuperaban blobs), engadiuse o caché sempre que foi posible. Despois realizamos probas de rendemento exhaustivas e comparamos a velocidade do Rexistro de aplicacións antes e despois dos cambios.

As solicitudes de API que antes tardaban ata medio minuto complétanse agora en milisegundos. A semana seguinte despregamos os cambios na produción, e desde entón quay.io está a traballar de forma estable. Durante este tempo, houbo varios picos bruscos de tráfico no punto final do Rexistro de aplicacións, pero as melloras realizadas evitaron as interrupcións da base de datos.

Que aprendemos?

Está claro que calquera servizo tenta evitar tempo de inactividade. No noso caso, cremos que as interrupcións recentes axudaron a mellorar Quay.io. Aprendemos algunhas leccións clave que queremos compartir:

  1. Os datos sobre quen usa o teu servizo e como nunca son superfluos. Como Quay "só funcionaba", nunca tivemos que gastar tempo optimizando o tráfico e xestionando a carga. Todo isto creou unha falsa sensación de seguridade que o servizo podería escalar indefinidamente.
  2. Cando o servizo cae, poñelo en marcha de novo é unha prioridade.. Dado que Quay continuou a sufrir unha base de datos bloqueada durante a primeira interrupción, os nosos procedementos estándar non tiveron o efecto previsto e non puidemos restaurar o servizo utilizándoos. Isto levou a unha situación na que houbo que dedicar tempo a analizar e recoller datos coa esperanza de atopar a causa raíz, en lugar de concentrar todos os esforzos en restaurar a funcionalidade.
  3. Avaliar o impacto de cada función do servizo. Os clientes raramente usaban App Registry, polo que non era unha prioridade para o noso equipo. Cando algunhas funcións do produto apenas se usan, os seus erros raramente aparecen e os desenvolvedores deixan de supervisar o código. É fácil caer presa da idea errónea de que así debería ser, ata que de súpeto esa función se atopa no centro dun incidente importante.

Cal é o próximo?

O traballo para garantir a estabilidade do servizo nunca se detén e estamos a melloralo constantemente. A medida que o volume de tráfico segue crecendo en quay.io, recoñecemos que temos a responsabilidade de facer todo o posible para estar á altura da confianza dos nosos clientes. Polo tanto, actualmente estamos a traballar nas seguintes tarefas:

  1. Desplegue réplicas de bases de datos de só lectura para axudar ao servizo a xestionar o tráfico axeitado en caso de problemas coa instancia RDS principal.
  2. Actualizando unha instancia RDS. A versión actual en si non é o problema. Pola contra, simplemente queremos eliminar o rastro falso (que seguimos durante o fallo); Manter o software actualizado eliminará outro factor en caso de futuras interrupcións.
  3. Caché adicional en todo o clúster. Seguimos buscando áreas nas que o caché pode reducir a carga da base de datos.
  4. Engadindo un firewall de aplicacións web (WAF) para ver quen se conecta a quay.io e por que.
  5. A partir da próxima versión, os clústeres de Red Hat OpenShift abandonarán o rexistro de aplicacións en favor dos catálogos de operadores baseados nas imaxes de contedores dispoñibles en quay.io.
  6. Un substituto a longo prazo para App Registry podería ser o soporte para as especificacións de artefactos Open Container Initiative (OCI). Actualmente está implementado como funcionalidade nativa de Quay e estará dispoñible para os usuarios cando finalice a propia especificación.

Todo o anterior forma parte do investimento continuo de Red Hat en quay.io mentres pasamos dun pequeno equipo de "estilo de inicio" a unha plataforma madura dirixida por SRE. Sabemos que moitos dos nosos clientes confían en quay.io no seu traballo diario (incluído Red Hat!) e tratamos de ser o máis transparentes posible sobre as interrupcións recentes e os esforzos continuos para mellorar.

PS do tradutor

Lea tamén no noso blog:

Fonte: www.habr.com

Engadir un comentario