Tulip: modernizando la plataforma de datos de Meta
Las migraciones son difíciles. Además, se vuelven mucho más difíciles en Meta debido a:
Antes de entrar en detalles sobre la historia de la migración, nos gustaría dar un paso atrás e intentar explicar la motivación y el fundamento de esta migración.
Con el tiempo, la plataforma de datos se ha transformado en diversas formas a medida que crecían las necesidades de la empresa. Lo que al principio era una modesta plataforma de datos se ha convertido en una plataforma de escala de exabytes. Algunos sistemas que prestaban servicios a menor escala comenzaron a mostrar signos de ser insuficientes para las crecientes demandas que se les imponían. En particular, nos hemos topado con algunos problemas concretos de confiabilidad y eficiencia relacionados con la (des)serialización de datos, lo que nos ha hecho repensar la forma en que registramos los datos y revisar las ideas de los primeros principios para abordar estos problemas apremiantes.
Logger está en el corazón de la plataforma de datos. El sistema se utiliza para registrar datos analíticos y operativos en Scuba, Hive y canalizaciones de procesamiento de flujo a través de Scribe. Cada equipo de plataforma de datos y productos interactúa con el registro. El formato de datos para el registro era Hive Text Delimited o JSON, por motivos heredados. Las limitaciones de estos formatos se describen en nuestro artículo anterior sobre Tulip.
Para abordar estas limitaciones, se desarrolló el formato de serialización Tulip para reemplazar los formatos de serialización heredados específicos del destino.
Los cuadros a continuación representan gráficamente el proceso de migración para la conversión del formato de serialización a Tulip para mostrar el progreso en varias etapas e hitos.
Podemos ver que, si bien la cantidad de esquemas de registro se mantuvo aproximadamente igual (o experimentó cierto crecimiento orgánico), los bytes registrados experimentaron una disminución significativa debido al cambio en el formato de serialización. Los detalles relacionados con el ahorro de bytes específicos del formato se tabulan en la siguiente sección.
Nota: Las cifras del Cuadro 2 se extrapolan (al tráfico general) en función de los ahorros reales observados para los cinco esquemas de registro más grandes (por volumen).
Nos gustaría presentar nuestro viaje migratorio como dos fases distintas con sus propias perspectivas.
Diseñar el sistema teniendo en cuenta la migración ayuda a que la migración sea mucho más fácil. Se desarrollaron las siguientes soluciones de ingeniería para garantizar que el equipo estuviera equipado con las herramientas y el soporte de infraestructura necesarios para cambiar el formato del cable de forma segura y depurar problemas que puedan surgir durante la fase de migración de manera escalable.
Las soluciones se clasificaron aproximadamente en los siguientes grupos:
Desafío: ¿Cómo se puede facilitar la migración y reducir el riesgo al no requerir que los productores y consumidores de datos cambien los formatos de serialización de forma atómica?
Solución: al invertir un esquema de registro único para usar el nuevo protocolo de serialización Tulip para escribir cargas útiles, era necesario admitir cargas útiles en modo mixto en una única secuencia de escritura, ya que sería imposible cambiar "atómicamente" todos los productores de datos para usar el nuevo formato. . Esto también permitió al equipo limitar la velocidad de implementación del nuevo formato de serialización.
El formato de cable de modo mixto era importante para respaldar el concepto de registradores de sombra, que se usaban ampliamente para pruebas de aceptación de un extremo a otro antes de un lanzamiento a gran escala.
El principal desafío para el formato de cable de modo mixto fue no poder cambiar la serialización existente de cargas útiles en formato Hive Text o JSON. Para solucionar esta limitación, cada carga útil serializada de Tulip tiene el prefijo 0x80 0x00 de la secuencia de 2 bytes, que es una secuencia utf-8 no válida.
Desafío: en algunos sistemas, el formato de serialización Hive Text (o JSON) se infiltró en el código de la aplicación que terminó dependiendo de este formato para consumir cargas útiles. Esto es el resultado de que los consumidores rompieron la abstracción del formato de serialización.
Solución: Dos soluciones abordaron este desafío.
Lector (contraparte del registrador para deserialización de datos)
Reader es una biblioteca que convierte una carga útil serializada en un objeto estructurado. El lector (como el registrador) viene en dos versiones: (a) código generado y (b) genérico. Un objeto lector consume datos en cualquiera de los tres formatos (Tulip, Hive Text o JSON) y produce un objeto estructurado. Esto permitió al equipo cambiar a los consumidores para que utilizaran lectores antes de que comenzara la migración. El código de la aplicación tuvo que actualizarse para consumir este objeto estructurado en lugar de una línea serializada sin formato. Esto abstrajo el formato de cable lejos de los consumidores de datos.
Conversión a formatos heredados en consumidores
Para los casos de uso en los que actualizar el código de la aplicación para consumir un objeto estructurado era inviable o demasiado costoso (desde el punto de vista del costo de ingeniería), equipamos el sistema consumidor con un conversor de formato que consumiría la carga útil serializada de Tulip y la convertiría en un texto Hive. (o JSON) carga útil serializada. Esto fue ineficiente en términos de utilización de la CPU, pero permitió al equipo avanzar con la migración para una larga lista de casos de uso.
“La depuración es dos veces más difícil que escribir el código en primer lugar. Por lo tanto, si escribe el código de la forma más inteligente posible, por definición no será lo suficientemente inteligente como para depurarlo”. - Brian W. Kernighan
Desafío: Permitir pruebas visuales sencillas y validación de datos después de la migración en un esquema de registro.
Solución: La herramienta CLI loggertail se desarrolló para permitir la validación de datos posteriores a la migración en la cola de escritura de un esquema de registro específico. Loggertail utiliza un deserializador genérico. Consulta el esquema de serialización para un esquema de registro con nombre y lo utiliza para decodificar el mensaje de entrada. Luego produce una lista legible por humanos de pares (nombre de campo, valor de campo) e imprime los datos como un objeto JSON.
“¿Fuiste tú el que entró al palco o el que volvió a salir? Nos turnamos. El truco está en dónde intercambiaríamos”. - "El prestigio"
Desafío: pruebas y verificación de un extremo a otro de los datos registrados mediante el nuevo formato.
Solución: Los registradores paralelos imitaron el esquema de registro original, excepto que registraron datos en tablas que el equipo de registradores monitoreaba. Esto constituyó una prueba de aceptación de un extremo a otro.
Además de las columnas especificadas por el usuario, un esquema de registro paralelo tenía dos columnas adicionales.
Los registradores de sombra registraron una pequeña fracción de filas en una tabla de sombra cada vez que se solicitaba el inicio de sesión en el esquema de registro original. Se utilizó un trabajo de Spark para analizar las filas de estas tablas y garantizar que el contenido fuera idéntico para las filas con el mismo ID, pero con un formato de serialización diferente. Esta validación proporcionó al equipo una gran confianza antes del lanzamiento.
Desafío: ¿Cómo podemos contener rápidamente el sangrado en caso de un problema durante la implementación de la serialización de Tulip en un esquema de registro?
Solución: Aunque se había realizado una validación mediante registradores ocultos para cada esquema de registro que se migraba, teníamos que estar preparados para problemas imprevistos durante la migración. Creamos un limitador de frecuencia para reducir el riesgo y permitir que el equipo detenga rápidamente la hemorragia.
Con más de 30 000 esquemas de registro restantes, la fase de escalamiento de la migración se centró en realizar la migración, siendo de autoservicio y utilizando la automatización. Otro aspecto importante de la fase de escalado fue garantizar que los ingenieros experimentaran la menor fricción posible.
Desafío: ¿Cómo se eligen los esquemas para migrar en función de los consumidores de datos del flujo de escriba correspondiente?
Solución: Cada esquema de registro se clasificó en función de los consumidores intermedios del flujo de escritura correspondiente. Sólo aquellos esquemas de registro que habían soportado todos los consumidores intermedios se consideraron listos para consumir el formato Tulip.
Con estos datos, se creó una herramienta para que un ingeniero solo necesitara ejecutar un script que apuntara automáticamente a los esquemas de registro no migrados para su conversión. También creamos herramientas para detectar posibles pérdidas de datos para los esquemas de registro específicos.
Finalmente, esta herramienta se ejecutó diariamente mediante un sistema de programación similar a cron.
Desafío: Hubo numerosos aspectos no técnicos con los que el equipo tuvo que lidiar durante la migración. Por ejemplo, motivar a los usuarios finales a migrar y brindarles soporte para que puedan migrar de forma segura y sencilla.
Solución: dado que la migración variaba en escala y complejidad según cada caso, comenzamos brindando tiempo de anticipación a los equipos de ingeniería a través de tareas para planificar la migración. Se nos ocurrió una guía de migración en vivo junto con un video de demostración que migraba algunos registradores para mostrar a los usuarios finales cómo se debe hacer. En lugar de una guía de migración que se escribió una vez y nunca (o rara vez) se actualizó, se tomó la decisión de mantener esta guía viva y en constante evolución. Se creó un grupo de apoyo y un horario de oficina para ayudar a los usuarios si tropezaban con algún bloqueador. Estos fueron particularmente útiles porque los usuarios publicaron sus experiencias y cómo se desbloquearon, lo que ayudó a otros usuarios a poner las cosas en marcha si encontraban problemas similares.
Hacer grandes apuestas, como la transformación de los formatos de serialización en toda la plataforma de datos, es un desafío a corto plazo, pero ofrece beneficios a largo plazo y conduce a una evolución con el tiempo.
Diseñar y diseñar soluciones que tengan en cuenta los aspectos técnicos y no técnicos de realizar una migración a esta escala es importante para el éxito. Esperamos haber podido dar una idea de los desafíos que enfrentamos y las soluciones que utilizamos durante este proceso.
Nos gustaría agradecer a los miembros del equipo de la plataforma de datos que se asociaron con el equipo de registrador para que este proyecto fuera un éxito. Sin el apoyo multifuncional de estos equipos y el apoyo de los usuarios (ingenieros) de Meta, este proyecto y la migración posterior no habrían sido posibles.