La traducción del artículo fue preparada especialmente para los estudiantes del curso "Arquitecto de alta carga" .

Introduccion
En la arquitectura de microservicio de Netflix, la transferencia de conjuntos de datos de uno a varios puntos finales puede ser extremadamente difícil. Estos conjuntos de datos pueden contener desde una configuración de servicio hasta resultados de procesamiento por lotes. Para optimizar el acceso, a menudo es necesaria una base de datos residente, y los cambios deben enviarse inmediatamente después de actualizar los datos.
Un ejemplo que refleja la necesidad de una distribución distribuida de un conjunto de datos es el siguiente: en cualquier momento, Netflix realiza una gran cantidad de pruebas A / B. Estas pruebas cubren varios servicios y comandos, y los operadores de prueba deberían poder reconfigurarse sobre la marcha. También requiere la capacidad de detectar nodos que no pudieron obtener la última configuración de prueba, y la capacidad de volver a versiones anteriores en caso de que algo salga mal.
Otro ejemplo de un conjunto de datos que necesita ser distribuido es la secuencia de salida de un modelo de aprendizaje automático: los resultados de su trabajo pueden ser utilizados por varios equipos, sin embargo, los equipos de ML no están necesariamente interesados en apoyar servicios de acceso ininterrumpido en una situación crítica. En lugar de la situación cuando cada equipo necesita crear copias de seguridad para poder retroceder sucintamente, se presta especial atención para garantizar que varios equipos puedan usar los resultados de un solo equipo.
Sin soporte a nivel de infraestructura, cada equipo finalmente intenta implementar su propia solución, pero resulta que con diferentes equipos con diferentes éxitos. Los conjuntos de datos en sí son de diferentes tamaños, desde unos pocos bytes hasta unos pocos gigabytes. Es importante crear la capacidad de monitorear el desempeño de los procesos y detectar el mal funcionamiento utilizando herramientas especiales para que los operadores puedan realizar cambios rápidamente sin tener que crear su propia solución.
Difusión de datos.En Netflix, utilizamos un sistema interno de datos pub / sub llamado Gutenberg. Gutenberg le permite distribuir conjuntos de datos con versiones: los destinatarios se suscriben a los datos y reciben sus últimas versiones cuando se publican. Cada versión del conjunto de datos permanece sin cambios y contiene una representación completa de los datos, es decir, no hay dependencia de versiones anteriores. Gutenberg le permite ver versiones antiguas de datos en caso de que necesite, por ejemplo, depurar, resolver rápidamente un problema de datos o volver a capacitar un modelo de aprendizaje automático. En este artículo, hablaremos sobre la arquitectura de alto nivel de Gutenberg.
Modelo de datos
1 tema -> muchas versionesEl diseño de alto nivel de Gutenberg es el tema. El editor publica datos dentro del tema y los destinatarios los extraen de él. La publicación en el tema se agrega como una versión separada. Estos se caracterizan por una política de almacenamiento específica que determina el número de versiones, según el caso de uso. Por ejemplo, puede configurar un tema para almacenar 10 versiones o versiones de los últimos 10 días.
Cada versión contiene metadatos (claves y valores) y un puntero de datos. El puntero de datos puede considerarse como metadatos especiales que indican dónde se almacenan realmente los datos publicados. Hoy, Gutenberg admite punteros de datos directos (si la carga útil se escribe en el valor del puntero de datos en sí) y punteros de datos S3 (si la carga útil se almacena en S3). Los punteros de datos directos generalmente se usan cuando los datos son pequeños (menos de 1 MB), y S3 se usa como almacenamiento de respaldo en caso de que el volumen de datos sea grande.
1 tema -> muchos conjuntos publicadosGutenberg ofrece la posibilidad de enviar una publicación a un conjunto específico de usuarios destinatarios; por ejemplo, un conjunto puede agruparse por una región, aplicación o clúster específico. Esto se puede usar para controlar la calidad de los cambios de datos o para limitar el conjunto de datos para que un subconjunto de aplicaciones pueda suscribirse. Los editores determinan el área de publicación de una versión particular de los datos y pueden agregar áreas a los datos publicados previamente. Tenga en cuenta que esto significa que el concepto de la última versión de los datos depende de un área específica: las dos aplicaciones pueden recibir las últimas versiones diferentes de los datos dependiendo del área de publicación definida por el editor. El servicio Gutenberg asigna las aplicaciones de los destinatarios a las áreas de publicación antes de decidir qué enviar como la última versión.
Casos de uso
El caso de uso más común para Gutenberg es distribuir datos de diferentes tamaños de un editor a múltiples destinatarios. A menudo, los datos se almacenan en la memoria del destinatario y se usan como un "caché compartido", donde siempre permanecen disponibles durante la ejecución del código del destinatario y se reemplazan atómicamente debajo del capó si es necesario. Muchos de estos casos de uso se pueden agrupar en "configuraciones", como la configuración de caché del
dispositivo Open Connect , ID de tipo de dispositivo admitido, metadatos de métodos de pago admitidos y configuraciones de prueba A / B. Gutenberg proporciona una abstracción entre la publicación y la recepción de estos datos, lo que permite a los editores iterar libremente a través de su aplicación sin afectar a los destinatarios posteriores. En algunos casos, la publicación se realiza mediante una interfaz de usuario administrada por Gutenberg, y los equipos no necesitan tocar su propia aplicación de publicación.
Otro uso del sistema Gutenberg es un repositorio de datos versionados. Esto es útil para aplicaciones de aprendizaje automático donde los equipos construyen y entrenan modelos basados en datos históricos, ven cómo cambian con el tiempo, luego cambian ciertos parámetros y vuelven a ejecutar la aplicación. Con mayor frecuencia en los cálculos por lotes, Gutenberg se utiliza para almacenar y distribuir los resultados de estos cálculos como diferentes versiones de conjuntos de datos. Los casos de uso en línea se suscriben a temas para proporcionar datos en tiempo real de los conjuntos de versiones más recientes, mientras que los sistemas autónomos pueden usar datos históricos de los mismos temas, por ejemplo, para enseñar un modelo de aprendizaje automático.
Es importante tener en cuenta que Gutenberg no está diseñado como un sistema de eventos, está destinado únicamente para el control de versiones y la distribución de datos. En particular, las publicaciones frecuentes no significan que el suscriptor deba recibir cada versión. Cuando solicita una actualización, recibirá la última versión, incluso si en este momento su versión actual está muy por detrás de la actual. Los sistemas tradicionales de pub-sub o evento son más adecuados para mensajes pequeños que se envían secuencialmente. Es decir, los destinatarios pueden crear una idea del conjunto de datos completo al consumir todo el flujo de eventos (comprimido). Sin embargo, Gutenberg está destinado a publicar y usar una representación completa e inmutable de un conjunto de datos.
Desarrollo y arquitectura.
Gutenberg consta de un servicio gRPC y una API REST, así como una biblioteca de cliente Java que utiliza la API gRPC.
Arquitectura de alto nivelCliente
La biblioteca del cliente Gutenberg maneja tareas tales como administrar una suscripción, cargar / descargar S3, métricas de
Atlas y parámetros que se pueden configurar usando las propiedades de
Archaius . Ella interactúa con el servicio Gutenberg a través de gRPC, utilizando
Eureka para descubrir servicios.
Publicar
Los editores suelen utilizar API de alto nivel para publicar cadenas, archivos y conjuntos de bytes. Dependiendo del tamaño de los datos, pueden publicarse como un puntero directo a los datos o cargarse en S3, y luego publicarse como un puntero de datos S3. El cliente puede cargar la carga útil a S3 en nombre del editor o publicar solo los metadatos de la carga útil que ya están en S3.
Los punteros de datos directos se replican automáticamente de forma global. Los datos publicados en S3 son, de manera predeterminada, cargados por el editor en varias áreas, aunque esto también se puede personalizar.
Gestión de suscripciones
La biblioteca del cliente proporciona gestión de suscripción de destinatario. Esto permite a los usuarios crear suscripciones para ciertos temas de los cuales la biblioteca extrae datos (por ejemplo, de S3) para transferirlos al destinatario establecido por el usuario. Las suscripciones funcionan de acuerdo con el modelo de encuesta: solicitan una nueva actualización del servicio cada 30 segundos, enviando la versión que recibieron por última vez. Los clientes suscritos no utilizarán una versión anterior de los datos que la que tienen actualmente si no se corrige (consulte "tolerancia a fallos" a continuación). La lógica de solicitud repetida está cableada y configurable. Por ejemplo, los usuarios pueden configurar Gutenberg para usar versiones anteriores de los datos si el proceso de descarga se interrumpe o para procesar la última versión de los datos al inicio, con mayor frecuencia para trabajar con cambios de datos que son incompatibles con los comentarios. Gutenberg también proporciona una suscripción preconfigurada que almacena los datos más recientes y los oculta atómicamente cuando llegan los cambios. Esto cumple con la mayoría de los casos de uso de suscripción en los que los suscriptores solo se preocupan por el valor actual en un momento dado, lo que permite a los usuarios especificar un valor predeterminado, por ejemplo, para un tema que nunca se ha publicado antes (por ejemplo, si el tema se usa para la configuración), o si hay un error dependiendo del tema (para evitar bloquear el inicio del servicio cuando hay un valor predeterminado válido).
API destinatario
Gutenberg también proporciona API de clientes de alto nivel, que bajo el capó tienen API gRPC de bajo nivel y proporcionan funcionalidad adicional y transparencia de ejecución de consultas. Un ejemplo es la descarga de datos para un tema y una versión específicos, que es ampliamente utilizado por los componentes conectados a
Netflix Hollow . Otro ejemplo es la recepción de la última versión de un tema en un momento determinado, un caso de uso común para depurar o enseñar modelos de aprendizaje automático.
Sostenibilidad y "transparencia" del cliente
Gutenberg fue diseñado con un enfoque en permitir que los servicios del destinatario se inicien con éxito, en lugar de garantizar que comiencen con los datos más actuales. Por esta razón, la biblioteca del cliente se creó con una lógica de respaldo para manejar estados cuando no puede interactuar con el servicio Gutenberg. Si las solicitudes HTTP fallan, el cliente carga el caché de metadatos de respaldo del tema publicado desde S3 y trabaja con él. Este caché contiene toda la información para decidir si se aplica la actualización y dónde recuperar los datos (ya sea de los metadatos de la publicación o de S3). Esto permite a los clientes recuperar datos (que están potencialmente desactualizados, dependiendo del estado actual de la memoria caché de respaldo) sin usar el servicio.
Una de las ventajas de proporcionar una biblioteca de cliente es la capacidad de obtener métricas que pueden usarse para informar problemas de infraestructura en general y errores en aplicaciones específicas. Hoy, el equipo de Gutenberg utiliza estas métricas para monitorear nuestra distribución SLI de publicaciones y alertas en caso de problemas típicos. Algunos clientes también usan estas métricas para informar errores específicos de aplicaciones específicas, por ejemplo, fallas de publicación individuales o un rechazo de un tema en particular.
Servidor
Gutenberg es una aplicación
Governator / Tomcat que proporciona puntos finales gRPC y REST. Utiliza el clúster Cassandra replicado globalmente para almacenar y distribuir metadatos de publicación en cada región. Las instancias que procesan solicitudes de destinatarios se escalan por separado de las instancias que procesan solicitudes de publicación. Hay aproximadamente 1,000 veces más solicitudes de publicación que solicitudes de publicación. Además, esto le permite eliminar la dependencia del hecho de la publicación en el recibo, por lo que un aumento repentino en las publicaciones no afectará el recibo, y viceversa.
Cada instancia en el Clúster de solicitudes de destinatarios procesa su propio caché en memoria de publicaciones recientes, extrayéndolo de Cassandra cada pocos segundos. Esto es necesario para procesar una gran cantidad de solicitudes de recepción procedentes de clientes firmados sin transferir tráfico al clúster Cassandra. Además, los cachés con un pequeño grupo de solicitudes ttl protegen contra los picos de consulta que podrían retrasar tanto a Cassandra que afecte a toda la región. Tuvimos situaciones en las que los errores repentinos que coincidían con la redistribución de grandes grupos causaban interrupciones en el servicio Gutenberg. Además, utilizamos el
limitador de concurrencia adaptativo que se encuentra en la aplicación original para suprimir aplicaciones con comportamiento incorrecto sin afectar a otros.
En los casos en que los datos se publican en S3 en varias regiones, el servidor decide qué segmento enviar de vuelta al cliente para su descarga, dependiendo de dónde se encuentre el cliente. También permite que el servicio proporcione al cliente un segmento en la región "más cercana" o lo obligue a moverse a otra región si la región actual está desconectada por una razón u otra.
Antes de devolver los datos de suscripción a los destinatarios, Gutenberg primero verifica la coherencia de los datos. Si la verificación falla y el suscriptor ya recibió algunos datos, el servicio no devuelve nada, lo que significa que la actualización no está disponible. Si el cliente suscriptor aún no ha recibido ningún dato (por lo general, esto significa que acaba de comenzar), el servicio solicita el historial del tema y devuelve el último valor que pasa la comprobación de coherencia. Esto se debe al hecho de que observamos retrasos episódicos en la replicación a nivel de Cassandra, donde cuando los suscriptores solicitan nuevos datos, los metadatos asociados con la última versión publicada solo se replicaron parcialmente. Esto puede hacer que el cliente reciba datos incompletos, lo que provocará errores en la solicitud de datos o errores en la lógica empresarial. La realización de tales comprobaciones de coherencia en el servidor protege a los destinatarios de las alertas de posible coherencia que vienen con la elección de un servicio de almacenamiento de datos.
La capacidad de monitorear publicaciones de temas y sitios que usan estos temas es una función importante para auditar y recopilar información de uso. Para recopilar estos datos, el servicio intercepta las solicitudes de los editores y los destinatarios (ambas solicitudes para actualizar los datos de los suscriptores y otros) y los indexa en Elasticsearch utilizando la
canalización de datos
Keystone . Entonces, tenemos la oportunidad de obtener datos para monitorear los temas que se utilizan y que ya no están allí. Publicamos enlaces en profundidad al panel de Kibana desde la interfaz de usuario interna para que los propietarios de los temas puedan administrar de forma independiente a sus suscriptores.
Además de los clústeres que manejan las solicitudes de editor y destinatario, el servicio Gutenberg lanza otro clúster que procesa las solicitudes periódicas. En particular, resuelve dos problemas:
- Cada pocos minutos, todas las últimas publicaciones y metadatos se recopilan y se envían a S3. Esto inicia el inicio de la memoria caché de respaldo, que utiliza el cliente, como se describió anteriormente.
- El recolector de basura elimina versiones de temas que no cumplen con sus políticas de retención. También elimina datos asociados con él (por ejemplo, objetos S3) y ayuda a garantizar un ciclo de vida de datos bien definido.
Tolerancia a fallos
Snap
Las implementaciones fallidas suceden en el mundo del desarrollo de aplicaciones, y las reversiones a versiones anteriores son una estrategia común para solucionar tales problemas. La arquitectura basada en datos complica la situación, porque el comportamiento está determinado por datos que cambian con el tiempo.
Los datos distribuidos por Gutenberg influyen y, en muchos casos, controlan el comportamiento del sistema. Esto significa que si algo sale mal, necesita una forma de volver a una versión comprobada de los datos. Para aliviar la situación, Gutenberg hace posible "vincular" el tema a una versión específica. Los pines anulan la última versión de los datos y obligan al cliente a actualizar a esta versión, lo que le permite solucionar rápidamente una situación crítica, en lugar de tratar de descubrir cómo publicar la última versión de trabajo. Incluso puede aplicar el enlace al área de publicación para que solo los destinatarios de esta área puedan usar los datos. Los pines también anulan los datos publicados durante el enlace activo, pero cuando se elimina el pin, los clientes recibirán la última versión, que puede ser la última versión anclada o una nueva versión que se publicó mientras se anclaba la anterior.
Despliegue secuencial
Al implementar un nuevo código, a menudo se recomienda crear nuevos ensamblados con un subconjunto de tráfico, implementarlos gradualmente o, de alguna otra manera, reducir los riesgos de implementación, ralentizándolo. , , .
, Gutenberg, —
Spinnaker . , . , . , , , , , . , AWS- .
Gutenberg Netflix . Gutenberg , 6 . – , 1-2 , 12 .
24- , , . , 200, 7. - , , Hollow. , , , – 60, – 4.
, Gutenberg:
- : Gutenberg Java-, Node.JS Python-. , REST API Gutenberg . , Node.JS Python.
- : Gutenberg . Gutenberg.
- : , . , .
- : , Gutenberg, Gutenberg . , .
- : , , . , Elasticsearch.
- : Netflix – . , Gutenberg , .
Eso es todo. .