Cómo domesticamos terabytes de registros en CYAN

Cómo domesticamos terabytes de registros en CYAN

Hola a todos, mi nombre es Alexander, trabajo en CIAN como ingeniero y estoy involucrado en la administración de sistemas y automatización de procesos de infraestructura. En los comentarios a uno de los artículos anteriores, nos pidieron que dijeramos de dónde obtenemos 4 TB de registros por día y qué hacemos con ellos. Sí, tenemos muchos registros y se ha creado un clúster de infraestructura independiente para procesarlos, lo que nos permite resolver problemas rápidamente. En este artículo hablaré sobre cómo lo adaptamos a lo largo de un año para trabajar con un flujo de datos cada vez mayor.

¿Por dónde empezamos?

Cómo domesticamos terabytes de registros en CYAN

En los últimos años, la carga en cian.ru ha crecido muy rápidamente y, en el tercer trimestre de 2018, el tráfico de recursos alcanzó los 11.2 millones de usuarios únicos por mes. En ese momento, en momentos críticos perdíamos hasta el 40% de los registros, por lo que no podíamos abordar las incidencias rápidamente y dedicamos mucho tiempo y esfuerzo a resolverlas. A menudo tampoco podíamos encontrar la causa del problema y este volvía a aparecer después de un tiempo. Era un infierno y había que hacer algo al respecto.

En ese momento, utilizamos un grupo de 10 nodos de datos con ElasticSearch versión 5.5.2 con configuración de índice estándar para almacenar registros. Se introdujo hace más de un año como una solución popular y asequible: entonces el flujo de registros no era tan grande y no tenía sentido idear configuraciones no estándar. 

Logstash proporcionó el procesamiento de registros entrantes en diferentes puertos en cinco coordinadores de ElasticSearch. Un índice, independientemente de su tamaño, constaba de cinco fragmentos. Se organizó una rotación horaria y diaria, como resultado, cada hora aparecían alrededor de 100 nuevos fragmentos en el grupo. Si bien no hubo muchos registros, el clúster funcionó bien y nadie prestó atención a su configuración. 

Los desafíos del rápido crecimiento

El volumen de registros generados creció muy rápidamente, ya que dos procesos se superponían. Por un lado, creció el número de usuarios del servicio. Por otro lado, comenzamos a cambiar activamente a una arquitectura de microservicios, cortando nuestros viejos monolitos en C# y Python. Varias docenas de nuevos microservicios que reemplazaron partes del monolito generaron significativamente más registros para el clúster de infraestructura. 

Fue la ampliación lo que nos llevó al punto en que el clúster se volvió prácticamente inmanejable. Cuando los registros comenzaron a llegar a una velocidad de 20 mil mensajes por segundo, la rotación frecuente e inútil aumentó el número de fragmentos a 6 mil, y había más de 600 fragmentos por nodo. 

Esto provocó problemas con la asignación de RAM y, cuando un nodo fallaba, todos los fragmentos comenzaban a moverse simultáneamente, multiplicando el tráfico y cargando otros nodos, lo que hacía casi imposible escribir datos en el clúster. Y durante este período nos quedamos sin troncos. Y si había un problema con el servidor, básicamente perdíamos 1/10 del clúster. Una gran cantidad de índices pequeños agregaban complejidad.

Sin registros, no entendíamos las razones del incidente y tarde o temprano podríamos volver a pisar el mismo rastrillo, y en la ideología de nuestro equipo esto era inaceptable, ya que todos nuestros mecanismos de trabajo están diseñados para hacer exactamente lo contrario: nunca repetir. los mismos problemas. Para hacer esto, necesitábamos todo el volumen de registros y su entrega casi en tiempo real, ya que un equipo de ingenieros de turno monitoreaba las alertas no solo a partir de métricas, sino también de registros. Para comprender la magnitud del problema, en ese momento el volumen total de registros era de aproximadamente 2 TB por día. 

Nos propusimos eliminar por completo la pérdida de registros y reducir el tiempo de entrega al clúster ELK a un máximo de 15 minutos en caso de fuerza mayor (más tarde nos basamos en esta cifra como un KPI interno).

Nuevo mecanismo de rotación y nodos calientes.

Cómo domesticamos terabytes de registros en CYAN

Comenzamos la conversión del clúster actualizando la versión de ElasticSearch de 5.5.2 a 6.4.3. Una vez más, nuestro clúster de la versión 5 falló y decidimos apagarlo y actualizarlo por completo; todavía no hay registros. Así que hicimos esta transición en sólo un par de horas.

La transformación a mayor escala en esta etapa fue la implementación de Apache Kafka en tres nodos con un coordinador como búfer intermedio. El intermediario de mensajes nos salvó de perder registros durante problemas con ElasticSearch. Al mismo tiempo, agregamos 2 nodos al clúster y cambiamos a una arquitectura caliente con tres nodos "calientes" ubicados en diferentes racks en el centro de datos. Les redirigimos los registros utilizando una máscara que no debe perderse bajo ninguna circunstancia: nginx, así como los registros de errores de la aplicación. Se enviaron registros menores a los nodos restantes: depuración, advertencia, etc., y después de 24 horas, se transfirieron los registros "importantes" de los nodos "calientes".

Para no aumentar el número de índices pequeños, cambiamos de la rotación temporal al mecanismo de rollover. Hubo mucha información en los foros de que la rotación por tamaño de índice es muy poco confiable, por lo que decidimos usar la rotación por la cantidad de documentos en el índice. Analizamos cada índice y registramos la cantidad de documentos después de los cuales debería funcionar la rotación. Por lo tanto, hemos alcanzado el tamaño de fragmento óptimo: no más de 50 GB. 

Optimización del clúster

Cómo domesticamos terabytes de registros en CYAN

Sin embargo, no nos hemos deshecho completamente de los problemas. Desafortunadamente, todavía aparecían pequeños índices: no alcanzaron el volumen especificado, no se rotaron y se eliminaron mediante la limpieza global de índices de más de tres días, ya que eliminamos la rotación por fecha. Esto provocó la pérdida de datos debido al hecho de que el índice del clúster desapareció por completo y un intento de escribir en un índice inexistente rompió la lógica del curador que utilizamos para la gestión. El alias de escritura se convirtió en un índice y rompió la lógica de rollover, provocando un crecimiento descontrolado de algunos índices hasta 600 GB. 

Por ejemplo, para la configuración de rotación:

сurator-elk-rollover.yaml

---
actions:
  1:
    action: rollover
    options:
      name: "nginx_write"
      conditions:
        max_docs: 100000000
  2:
    action: rollover
    options:
      name: "python_error_write"
      conditions:
        max_docs: 10000000

Si no había ningún alias de rollover, se produjo un error:

ERROR     alias "nginx_write" not found.
ERROR     Failed to complete action: rollover.  <type 'exceptions.ValueError'>: Unable to perform index rollover with alias "nginx_write".

Dejamos la solución a este problema para la siguiente iteración y abordamos otro tema: cambiamos a la lógica de extracción de Logstash, que procesa los registros entrantes (eliminando información innecesaria y enriqueciéndola). Lo colocamos en la ventana acoplable, que lanzamos mediante docker-compose, y también colocamos allí el logstash-exporter, que envía métricas a Prometheus para el monitoreo operativo del flujo de registros. De esta manera nos dimos la oportunidad de cambiar sin problemas la cantidad de instancias de logstash responsables de procesar cada tipo de registro.

Mientras mejorábamos el clúster, el tráfico de cian.ru aumentó a 12,8 millones de usuarios únicos por mes. Como resultado, resultó que nuestras transformaciones estaban un poco por detrás de los cambios en la producción, y nos enfrentamos al hecho de que los nodos "cálidos" no podían hacer frente a la carga y ralentizaron toda la entrega de troncos. Recibimos datos "calientes" sin fallas, pero tuvimos que intervenir en la entrega del resto y realizar una transferencia manual para distribuir los índices de manera uniforme. 

Al mismo tiempo, escalar y cambiar la configuración de las instancias de logstash en el clúster se complicó por el hecho de que se trataba de una composición acoplable local y todas las acciones se realizaban manualmente (para agregar nuevos extremos, era necesario revisar manualmente todos los servidores y hacer docker-compose up -d en todas partes).

Redistribución de registros

En septiembre de este año todavía estábamos cortando el monolito, la carga en el clúster aumentaba y el flujo de registros se acercaba a los 30 mil mensajes por segundo. 

Cómo domesticamos terabytes de registros en CYAN

Comenzamos la siguiente iteración con una actualización de hardware. Pasamos de cinco coordinadores a tres, reemplazamos nodos de datos y ganamos en términos de dinero y espacio de almacenamiento. Para los nodos utilizamos dos configuraciones: 

  • Para nodos “calientes”: E3-1270 v6 / 960Gb SSD / 32 Gb x 3 x 2 (3 para Hot1 y 3 para Hot2).
  • Para nodos “cálidos”: E3-1230 v6 / 4Tb SSD / 32 Gb x 4.

En esta iteración, movimos el índice con registros de acceso de microservicios, que ocupa el mismo espacio que los registros nginx de primera línea, al segundo grupo de tres nodos "calientes". Ahora almacenamos datos en nodos "calientes" durante 20 horas y luego los transferimos a nodos "calientes" al resto de los registros. 

Resolvimos el problema de la desaparición de índices pequeños reconfigurando su rotación. Ahora los índices se rotan cada 23 horas en cualquier caso, incluso si hay pocos datos allí. Esto aumentó ligeramente la cantidad de fragmentos (había alrededor de 800), pero desde el punto de vista del rendimiento del clúster es tolerable. 

Como resultado, había seis nodos "calientes" y sólo cuatro "cálidos" en el clúster. Esto provoca un ligero retraso en las solicitudes durante largos intervalos de tiempo, pero aumentar la cantidad de nodos en el futuro resolverá este problema.

Esta iteración también solucionó el problema de la falta de escalado semiautomático. Para hacer esto, implementamos una infraestructura de clúster Nomad, similar a la que ya implementamos en producción. Por ahora, la cantidad de Logstash no cambia automáticamente según la carga, pero llegaremos a esto.

Cómo domesticamos terabytes de registros en CYAN

Planes para el futuro

La configuración implementada se escala perfectamente y ahora almacenamos 13,3 TB de datos, todos los registros durante 4 días, lo cual es necesario para el análisis de alertas de emergencia. Convertimos algunos de los registros en métricas, que agregamos a Graphite. Para facilitar el trabajo de los ingenieros, contamos con métricas para el cluster de infraestructura y scripts para reparación semiautomática de problemas comunes. Después de aumentar la cantidad de nodos de datos, lo cual está previsto para el próximo año, pasaremos al almacenamiento de datos de 4 a 7 días. Esto será suficiente para el trabajo operativo, ya que siempre intentamos investigar los incidentes lo antes posible y para investigaciones a largo plazo disponemos de datos de telemetría. 

En octubre de 2019, el tráfico a cian.ru ya había aumentado a 15,3 millones de usuarios únicos por mes. Esto se convirtió en una prueba seria para la solución arquitectónica para la entrega de registros. 

Ahora nos estamos preparando para actualizar ElasticSearch a la versión 7. Sin embargo, para esto tendremos que actualizar el mapeo de muchos índices en ElasticSearch, ya que pasaron de la versión 5.5 y fueron declarados obsoletos en la versión 6 (simplemente no existen en la versión 7). Esto significa que durante el proceso de actualización seguramente habrá algún tipo de fuerza mayor, lo que nos dejará sin registros mientras se resuelve el problema. De la versión 7, lo que más esperamos es Kibana con una interfaz mejorada y nuevos filtros. 

Logramos nuestro objetivo principal: dejamos de perder registros y redujimos el tiempo de inactividad del clúster de infraestructura de 2 a 3 fallas por semana a un par de horas de trabajo de mantenimiento por mes. Todo este trabajo en producción es casi invisible. Sin embargo, ahora podemos determinar exactamente qué está sucediendo con nuestro servicio, podemos hacerlo rápidamente en modo silencioso y no preocuparnos de que se pierdan los registros. En general estamos satisfechos, contentos y preparándonos para nuevas hazañas, de las que hablaremos más adelante.

Fuente: habr.com

Añadir un comentario