
En 2017, ganamos la competencia para el desarrollo del núcleo de transacciones del negocio de inversión de Alfa Bank y comenzamos a trabajar (en HighLoad ++ 2018
, Vladimir Drynkin, Jefe del núcleo de transacciones del negocio de inversión de Alfa Bank, presentó un informe sobre el núcleo del negocio de inversión). Este sistema fue para agregar datos de transacciones de varias fuentes en varios formatos, llevar los datos a una forma unificada, guardarlos y proporcionarles acceso.
En el proceso de desarrollo, el sistema evolucionó y se volvió funcional, y en algún momento nos dimos cuenta de que estábamos cristalizando algo mucho más que solo un software de aplicación diseñado para resolver un rango de tareas estrictamente definido: obtuvimos un
sistema para construir aplicaciones distribuidas con almacenamiento persistente Nuestra experiencia formó la base de un nuevo producto:
Tarantool Data Grid (TDG).
Quiero hablar sobre la arquitectura TDG y las soluciones que surgieron durante el proceso de desarrollo, presentarles la funcionalidad básica y mostrarles cómo nuestro producto puede convertirse en la base para construir soluciones completas.
Arquitectónicamente, dividimos el sistema en
roles separados, cada uno de los cuales es responsable de resolver un cierto rango de tareas. Una instancia en ejecución de una aplicación implementa uno o más tipos de roles. Un clúster puede tener varios roles del mismo tipo:

Conector
Connector es responsable de la comunicación con el mundo exterior; su tarea es aceptar la solicitud, analizarla y, si tiene éxito, enviar los datos para su procesamiento al procesador de entrada. Admitimos los formatos HTTP, SOAP, Kafka, FIX. La arquitectura le permite simplemente agregar soporte para nuevos formatos, el soporte de IBM MQ llegará pronto. Si falla el análisis de la solicitud, el conector devolverá un error; de lo contrario, responderá que la solicitud se procesó con éxito, incluso si se produjo un error durante su procesamiento posterior. Esto se hace a propósito, para trabajar con sistemas que no saben cómo repetir solicitudes, o viceversa, hacerlo de manera demasiado agresiva. Para no perder datos, se utiliza la cola de reparación: el objeto ingresa primero y solo después de que se elimina el procesamiento exitoso. El administrador puede recibir notificaciones sobre los objetos que quedan en la cola de reparación y, después de eliminar un error de software o falla de hardware, intente nuevamente.
Procesador de entrada
El procesador de entrada clasifica los datos recibidos por características y llama a los manejadores adecuados. Los controladores son código Lua que se ejecuta en el sandbox, por lo que no pueden afectar el funcionamiento del sistema. En esta etapa, los datos pueden reducirse a la forma deseada y, si es necesario, ejecutar un número arbitrario de tareas que pueden implementar la lógica necesaria. Por ejemplo, en el producto MDM (Master Data Management) creado en Tarantool Data Grid, al agregar un nuevo usuario, ejecutamos una tarea separada para no ralentizar el procesamiento de la solicitud. El entorno limitado admite solicitudes para leer, cambiar y agregar datos; le permite realizar alguna función en todos los roles, como el almacenamiento y agregar el resultado (asignar / reducir).
Los controladores se pueden describir en archivos:
sum.lua local x, y = unpack(...) return x + y
Y luego, declarado en la configuración:
functions: sum: { __file: sum.lua }
¿Por qué lua? Lua es un lenguaje muy simple. Según nuestra experiencia, un par de horas después de conocerlo, la gente comienza a escribir código que resuelve su problema. Y estos no son solo desarrolladores profesionales, sino, por ejemplo, analistas. Además, gracias al compilador jit, Lua es muy rápido.
Almacenamiento
El almacenamiento almacena datos persistentes. Antes de guardar, los datos se validan para cumplir con el esquema de datos. Para describir el esquema, utilizamos el formato extendido
Apache Avro . Un ejemplo:
{ "name": "User", "type": "record", "logicalType": "Aggregate", "fields": [ { "name": "id", "type": "string"}, {"name": "first_name", "type": "string"}, {"name": "last_name", "type": "string"} ], "indexes": ["id"] }
En base a esta descripción, se generan automáticamente DDL (Lenguaje de definición de datos) para Tarantula DBMS y el esquema
GraphQL para el acceso a datos.
La replicación de datos asíncrona es compatible (planea agregar síncrona).
Procesador de salida
A veces es necesario notificar a los consumidores externos sobre la llegada de nuevos datos, para esto está el papel del procesador de salida. Después de guardar los datos, pueden transferirse al controlador apropiado (por ejemplo, para llevarlos al formulario que el consumidor requiere) y luego transferirse al conector para su envío. La cola de reparación también se usa aquí: si nadie ha aceptado el objeto, el administrador puede intentarlo más tarde.
Escalamiento
Los roles del conector, el procesador de entrada y el procesador de salida no tienen estado, lo que nos permite escalar el sistema horizontalmente, simplemente agregando nuevas instancias de la aplicación con el rol incluido del tipo deseado. Para el escalado de almacenamiento horizontal, se utiliza un
enfoque para la organización del clúster utilizando cubos virtuales. Después de agregar un nuevo servidor, parte del grupo de servidores antiguos en segundo plano se mueve al nuevo servidor; Esto sucede de manera transparente a los usuarios y no afecta el funcionamiento de todo el sistema.
Propiedades de datos
Los objetos pueden ser muy grandes y contener otros objetos. Aseguramos la atomicidad de agregar y actualizar datos, guardando el objeto con todas las dependencias en un depósito virtual. Esto elimina la "mancha" del objeto en varios servidores físicos.
Se admite el control de versiones: cada actualización del objeto crea una nueva versión, y siempre podemos hacer un intervalo de tiempo y ver cómo se veía el mundo en ese momento. Para los datos que no necesitan un historial largo, podemos limitar la cantidad de versiones o incluso almacenar solo una, la última, es decir, deshabilitar el control de versiones para un tipo determinado. También puede limitar el historial por tiempo: por ejemplo, elimine todos los objetos de un tipo determinado de más de 1 año. También se admite el archivado: podemos descargar objetos anteriores al tiempo especificado, liberando espacio en el clúster.
Las tareas
De las funciones interesantes, vale la pena señalar la capacidad de ejecutar tareas en un horario, a solicitud del usuario, o programáticamente desde el sandbox:

Aquí vemos otro rol: corredor. Este rol no tiene estado y, si es necesario, se pueden agregar instancias de aplicaciones adicionales con este rol al clúster. La responsabilidad del corredor es completar las tareas. Como se dijo, la creación de nuevas tareas desde el sandbox es posible; se ponen en cola en el almacenamiento y luego se ejecutan en el corredor. Este tipo de tarea se llama Job. También tenemos un tipo de tarea llamada Tarea: son tareas definidas por el usuario que están programadas para ejecutarse (utilizando la sintaxis cron) o bajo demanda. Para ejecutar y rastrear tales tareas, tenemos un conveniente administrador de tareas. Para que esta funcionalidad esté disponible, debe habilitar la función de planificador; este rol tiene un estado, por lo tanto, no escala, lo que, sin embargo, no es obligatorio; Sin embargo, ella, como todos los demás roles, puede tener una réplica que comienza a funcionar si el maestro se niega de repente.
Registrador
Otro rol se llama registrador. Recopila registros de todos los miembros del clúster y proporciona una interfaz para cargarlos y verlos a través de una interfaz web.
Servicios
Vale la pena mencionar que el sistema facilita la creación de servicios. En el archivo de configuración, puede especificar qué solicitudes deben enviarse al controlador escrito por el usuario que se ejecuta en el entorno limitado. En este controlador, puede, por ejemplo, ejecutar algún tipo de consulta analítica y devolver el resultado.
El servicio se describe en el archivo de configuración:
services: sum: doc: "adds two numbers" function: sum return_type: int args: x: int y: int
La API GraphQL se genera automáticamente y el servicio está disponible para llamar:
query { sum(x: 1, y: 2) }
Esto llamará al manejador de
sum
, que devolverá el resultado:
3
Perfil de consulta y métricas
Para comprender el sistema y el perfil de consultas, implementamos soporte para el protocolo OpenTracing. El sistema puede, bajo demanda, enviar información a herramientas que admiten este protocolo, por ejemplo, Zipkin, que le permitirá comprender cómo se ejecutó la solicitud:

Naturalmente, el sistema proporciona métricas internas que se pueden recopilar con Prometheus y visualizar con Grafana.
Implementar
Tarantool Data Grid se puede implementar desde paquetes o archivos RPM, utilizando la utilidad de la entrega o Ansible, también hay soporte para Kubernetes (
operador de Tarantool Kubernetes ).
Una aplicación que implementa lógica de negocios (configuración, controladores) se carga en el clúster de Tarantool Data Grid como un archivo a través de la interfaz de usuario o mediante un script a través de la API proporcionada por nosotros.
Ejemplos de aplicación
¿Qué aplicaciones puedo crear con Tarantool Data Grid? De hecho, la mayoría de las tareas comerciales están relacionadas de alguna manera con el procesamiento del flujo de datos, el almacenamiento y el acceso a él. Por lo tanto, si tiene grandes flujos de datos que deben almacenarse de forma segura y tener acceso a ellos, nuestro producto puede ahorrarle mucho tiempo en el desarrollo y centrarse en la lógica de su negocio.
Por ejemplo, queremos recopilar información sobre el mercado inmobiliario para posteriormente, por ejemplo, tener información sobre las mejores ofertas. En este caso, distinguimos las siguientes tareas:
- Robots que recopilan información de fuentes abiertas: estas serán nuestras fuentes de datos. Puede resolver este problema utilizando soluciones preparadas o escribiendo código en cualquier idioma.
- A continuación, Tarantool Data Grid aceptará y guardará los datos. Si el formato de los datos de diferentes fuentes es diferente, puede escribir código en el idioma Lua, lo que conducirá a la conversión a un solo formato. En la etapa de preprocesamiento, también puede, por ejemplo, filtrar ofertas recurrentes o además actualizar información sobre agentes que operan en el mercado en la base de datos.
- Ahora ya tiene una solución escalable en el clúster, que se puede llenar con datos y hacer muestras de datos. Luego puede implementar una nueva funcionalidad, por ejemplo, escribir un servicio que consultará los datos y emitirá la oferta más rentable en un día; esto requerirá algunas líneas en el archivo de configuración y un poco de código Lua.
Que sigue
Nuestra prioridad es aumentar la conveniencia de desarrollo con
Tarantool Data Grid . Por ejemplo, este es un IDE con soporte para perfilar y depurar controladores de espacio aislado.
También prestamos mucha atención a los problemas de seguridad. En este momento estamos aprobando la certificación FSTEC Rusia para confirmar el alto nivel de seguridad y cumplir con los requisitos para la certificación de productos de software utilizados en sistemas de información de datos personales y sistemas de información estatales.