dificultades para construir su propio DBMS / Sudo Null IT News

A menudo resulta que incluso en un gran “zoológico” de soluciones disponibles públicamente no existe ninguna herramienta que cumpla con todos los requisitos. En este caso, los equipos se ven obligados a avanzar hacia el desarrollo de su producto.

Mi nombre es Alexander Klenov. Soy el líder del equipo de desarrollo de Tarantool DB en el equipo de Tarantool. En este artículo le contaré por qué decidimos agregar Tarantool DB a nuestra cartera de productos y qué implementamos en la herramienta, y también le mostraré, usando el ejemplo de diccionarios, por qué es difícil construir su propio DBMS.

Requisitos previos para crear Tarantool DB

Los sistemas de TI modernos a menudo implican no sólo trabajar con grandes flujos de datos, sino también cambiar la naturaleza de la carga. Esto también se aplica, entre otras cosas, a los sistemas OLTP, incluido Tarantool, que cada vez más tienen que procesar en tiempo real no transacciones ordinarias, sino microtransacciones de alta frecuencia.

El matiz es que los DBMS existentes de varios tipos “listos para usar” no son del todo adecuados para tales tareas.

  • Bases de datos relacionales (por ejemplo, MySQL, PostgreSQL, Oracle, MS SQL, Amazon Aurora, etc.) no son un clúster listo para usar y configurar una latencia baja para ellos requiere algo de experiencia y esfuerzo adicional.

  • Bases de datos orientadas a documentos (por ejemplo, MongoDB, CouchDB) no funcionan con tablas e índices, no admiten SQL y no permiten una configuración flexible de los derechos de acceso.

  • Tiendas de valores clave (por ejemplo, Redis, Memcached, Couchbase, Amazon S3) no tienen soporte para transacciones, iteradores e índices secundarios, es decir, su velocidad está limitada en ciertos escenarios.

  • Bases de datos en columnas (por ejemplo, ClickHouse) se centran más en la carga de trabajo OLAP, es decir, el análisis de datos, en lugar de procesar microtransacciones de alta frecuencia.

  • Bases de datos de gráficos también diseñado para un perfil de carga diferente y otras tareas.

Queríamos tener funciones útiles de diferentes tipos de DBMS, por lo que mis colegas crearon una vez el DBMS Tarantool. Sin embargo, Tarantool no es una caja. Con el objetivo de crear una solución en caja, apareció Tarantool DB. La característica principal de la primera versión de Tarantool DB es la abreviatura Time-to-market (TTM). La misión de la segunda versión es hacer la transición a una versión más nueva y tecnológica de la plataforma.

Tarantool DB y sus características

Tarantool DB es un DBMS NoSQL que funciona con los protocolos Redis e IPROTO.

La herramienta combina las propiedades y parámetros más populares de diferentes tipos de bases de datos.

  • Se garantiza que la solución tendrá una latencia baja, admite fragmentación y equilibrio desde el primer momento y tiene una alta tolerancia a fallos.

  • De las bases de datos relacionales, Tarantool DB recibió tablas, transacciones (ACID), índices, soporte SQL, la capacidad de configurar de manera flexible los derechos de acceso y usar iteradores.

  • Tarantool DB heredó el principio de trabajar con archivos, estructuras y anidamientos de los orientados a documentos. En Tarantool DB, los datos se almacenan en MessagePack, un formato de serialización de datos que es un análogo binario eficaz de JSON. Debido a su tamaño compacto y velocidad, MessagePack se elige a menudo para el intercambio de datos en sistemas donde el rendimiento es importante. Puedes leer más sobre MessagePack Aquí y aquí.

  • De Key-value tomé los principios básicos, gracias a los cuales se puede utilizar como reemplazo directo de Memcached y Redis.

Al mismo tiempo, Tarantool DB no se centra en tareas analíticas y no es adecuado para proyectos con una gran cantidad de lógica empresarial, ya que funciona en modo de subproceso único.

Nota: Puede leer más sobre Tarantool DB en página oficial del producto.

Benefíciese del desarrollo de su propio DBMS

Desarrollar nuestra propia solución nos ayudó a obtener una herramienta que satisface mejor nuestras necesidades y los puntos débiles de nuestros clientes. Al mismo tiempo, los recursos gastados en la construcción de la herramienta están completamente justificados, ya que su funcionalidad le permite abandonar los compromisos y construir “muletas”.

Además, en nuestro caso, el desarrollo de Tarantool DB es una inversión a largo plazo en una “cartera de productos” que no solo ofrecemos a los clientes, sino que también utilizamos activamente para proyectos internos.

Dificultades para construir su propio DBMS

Crear su propio DBMS está asociado no solo con beneficios, sino también con dificultades. Esto se debe principalmente a la complejidad de dichos sistemas.

Así, la creación de Tarantool DB implicó el desarrollo de:

  • instalador;

  • conectores;

  • documentación y ejemplos;

  • casos y entornos de prueba;

  • herramientas auxiliares y de prueba;

  • módulos para ampliar la funcionalidad.

Así, detrás de la creación de un DBMS se esconde toda una serie de tareas de desarrollo. Además, cada tarea implica muchas subtareas complejas.

Por ejemplo, el desarrollo de nuevas funciones incluye los siguientes pasos y actividades:

  • desarrollo de ideas;

  • validación de ideas;

  • diseño;

  • revisión arquitectónica;

  • codificación;

  • revisión de código;

  • pruebas (control de calidad);

  • documentación;

  • revisión de documentación;

  • liberar.

Análisis de posibles dificultades utilizando el ejemplo del diseño de un diccionario.

Para comprender completamente los posibles problemas y tareas al crear y desarrollar su DBMS, consideremos solo una etapa de los pasos de desarrollo descritos anteriormente, a saber, el diseño utilizando diccionarios como ejemplo.

Los diccionarios son pequeños conjuntos de datos que normalmente no contienen más de 100 000 entradas, tienen un RPS bajo por entrada y son necesarios en todos los nodos para proporcionar datos a métodos personalizados. Normalmente, los diccionarios contienen datos normalizados, por ejemplo, nombres de calles, ciudades, monedas, sexo del usuario y otros.

Es importante que los diccionarios contengan todos sus datos en cada nodo a la vez. En consecuencia, al colocar diccionarios en los nodos del clúster, es necesario crear un mecanismo para entregar los datos recién llegados a todos los nodos, garantizando su coherencia.

Normalmente, un clúster se distribuye en dos, tres o incluso más centros de datos, y cada centro de datos puede emplear varios servidores. Por ejemplo, supongamos que hay tres (uno para cada centro de datos). De esta manera se obtiene la siguiente topología:

  • cada centro de datos tiene un servidor;

  • en cada servidor hay un nodo de clúster que redirige las solicitudes (enrutador) y nodos de almacenamiento de datos, cada uno de los cuales forma parte de un grupo de replicación (fragmento).

Hay tres formas de ordenar datos en un clúster.

  1. Solicitudes fuera. El método más simple y confiable, que implica que cada nodo accede a otras fuentes de nuevos datos (por ejemplo, archivos) en un intervalo de tiempo establecido. Esta opción implica aumentar la complejidad de la infraestructura, ya que si la fuente son archivos, estos deben distribuirse de alguna manera entre servidores, y si la fuente es una base de datos, existen otras complicaciones, que se analizan a continuación.

  2. Generación adentro. El método implica que se puede utilizar una determinada función para trabajar con datos externos entrantes y formar tablas a partir de ellos. Conveniente, pero en este caso es imposible tener un control total sobre lo que está sucediendo.

  3. Control externo. El método implica descartar identificadores a través de los cuales puede importar y exportar datos.

Todas las opciones son buenas en sus situaciones. Pero lo implementamos de una tercera manera, porque:

  • en comparación con la primera opción, proporciona una solución más compacta y una mayor velocidad de respuesta a nuevos datos;

  • En comparación con la segunda opción, permite gestionar los datos externamente.

En teoría, este enfoque se puede implementar de varias maneras.

Usando replicación

En este caso, no es necesario inventar nada desde cero, sino que se hace hincapié en utilizar lo que ya existe.

Es decir, puede tomar enrutadores, combinarlos en un grupo de replicación y almacenar datos del diccionario en ellos. En consecuencia, en los enrutadores puede agregar o eliminar datos de los diccionarios.

Pero el método claramente no está exento de inconvenientes, especialmente en el contexto de trabajar con Tarantool DB:

  • El grupo de replicación de Tarantool solo admite 32 nodos;

  • un conjunto de réplicas grande inevitablemente tendrá un impacto en el archivador y el clúster;

  • la barrera para empezar a trabajar con el método es alta y requiere documentación detallada;

  • grabar y buscar datos se vuelve más complicado, ya que todas las operaciones deben realizarse a través del enrutador;

  • aumenta la importancia de los routers en el sistema y desaparece la posibilidad de implementar un conector sin router;

  • Aparecen solicitudes adicionales desde Almacenamiento.

Como alternativa a esta opción, puede conectar otro clúster e integrarlo con soluciones existentes (Tarantool, etcd, Consul, ZooKeeper) para transferirles la lógica para trabajar con diccionarios.

Pero, de hecho, la solución no es diferente a colocarlo en enrutadores, por lo que los problemas son los mismos.

Grabación sincronizada

En este caso, para distribuir diccionarios, se pretende utilizar la replicación sincrónica, una confirmación regular de dos fases. En consecuencia, la entrega se realiza en dos pasos: en la primera fase, los datos se distribuyen a cada nodo, en la segunda fase se realiza la confirmación.

Pero este esquema tiene un inconveniente importante. Entonces, si hay una falla en alguno de los nodos, la confirmación no se ejecutará.

Por supuesto, en caso de fallas, se puede implementar un esquema con quórums, pero luego todo se vuelve muy complicado y es necesario prever mecánicas para trabajar con nodos que inicialmente no estaban disponibles, pero luego se activaron.

Además, en dicha implementación, el administrador de transacciones de una confirmación de dos fases también puede fallar. Es decir, puede darse una situación en la que algunos nodos ya hayan recibido datos actualizados, pero otros aún no.

Ampliar un esquema de este tipo tampoco es fácil: al agregar un nuevo nodo, es necesario proporcionar mecanismos para entregarle datos.

En general: el plan tiene más riesgos y dificultades que beneficios.

Esquema con un líder

Aquí todo es sencillo. El método consiste en nombrar un líder a quien le lleguen los datos. Al mismo tiempo, el propio líder distribuye nuevos datos a los nodos restantes.

Si uno de los Almacenamiento falla, el líder simplemente lo ignora y llena los nodos restantes con datos.

En este caso, el líder intentará periódicamente entregar datos al Almacenamiento deshabilitado.

El mecanismo en su conjunto no es nuevo y se utiliza activamente para la replicación en diferentes bases de datos. Pero en el contexto de trabajar con diccionarios, no permite solucionar todos los cuellos de botella.

Entonces, gestionar un líder y controlar que solo haya un líder a la vez es difícil. Además, la implementación de esta opción requiere la construcción de mecánicas complejas, que son simplemente redundantes para el mecanismo existente y la tarea actual.

Tirando y Chismeando

En este caso, todo se reduce al hecho de que “extraemos” los datos y los distribuimos según el principio Gossip. Es decir, todos los nodos se colocan condicionalmente en un círculo y se les informa que:

  • cuando llegan nuevos datos, cada nodo notifica a su vecino izquierdo;

  • Al recibir una notificación, cada nodo va a su vecino derecho en busca de nuevos datos.

En la práctica funciona así:

  • llegan nuevos datos al Almacenamiento B-0;

  • El Almacenamiento B-0 notifica al vecino izquierdo, es decir, el Almacenamiento C-0, sobre esto;

  • después de recibir la notificación, el Almacenamiento C-0 va a su vecino derecho, es decir, el Almacenamiento B-0, para obtener nuevos datos;

  • después de recibir nuevos datos, el Almacenamiento C-0 notifica a su vecino izquierdo, es decir, el Almacenamiento D-0, y el ciclo se repite.

Como resultado, incluso si uno de los nodos de la cadena no está disponible temporalmente, después de encenderlo podrá recibir automáticamente datos actualizados y ser incluido en la tubería construida. Es decir, los datos se entregarán a todos los nodos en cualquier caso.

Al mismo tiempo, dado que este esquema en realidad implementa un enfoque multimaestro, donde se puede escribir en todos los nodos, existe el riesgo de que se realicen dos entradas simultáneamente usando la misma clave, que se contradicen entre sí. Por ejemplo, que x=1 y x=2.

Además, el enfoque habitual para resolver este tipo de conflictos, en el que un significado es inmediatamente sobrescrito por otro, en su forma pura no es del todo adecuado en este caso. Pero el enfoque bien podría modernizarse, ya que la grabación rara vez ocurre. Por lo tanto, simultáneamente con los datos, puede registrar una marca de tiempo y, al distribuir datos nuevos, comparar la marca de tiempo y guardar solo los datos que vinieron después (es decir, los más relevantes).

Por lo tanto, en la versión con Pulling and Gossip, hay un multimaster para implementar diccionarios, resolución de conflictos basada en una marca de tiempo y un reinicio del temporizador para conectar automáticamente nodos temporalmente inactivos. Además, el método tiene una API muy simple, que se reduce a un conjunto básico de comandos: get, set, del.

En este caso, el método garantiza:

  • difusión de nuevos datos;

  • coherencia y coherencia de los datos;

  • manteniendo un orden de grabación claro.

Pero incluso este método, con todas sus ventajas, tiene varios matices:

  1. El orden de grabación está garantizado siempre que la grabación sea rara, es decir, que se cumplan las condiciones de los diccionarios. Si las escrituras se vuelven más frecuentes que la diferencia de tiempo máxima entre los servidores del clúster, el orden ya no está garantizado; es posible que los datos se escriban fuera de orden.

  2. Es importante tener cuidado con la manipulación del tiempo. Entonces, cuando avanza el tiempo, no pasa nada. Pero si retrasa el tiempo, todo el mecanismo se estropeará, ya que el registro recibirá datos creados utilizando marcas de tiempo anteriores al último registro que ya está en la base de datos. Para eliminar tales riesgos, hemos implementado una protección que detendrá la grabación hasta que el tiempo llegue a la última marca.

  3. Debemos recordar que en un DBMS no pueden existir transacciones cluster (por ejemplo, Tarantool no las tiene). Por lo tanto, es importante comprender que las transacciones ocurren dentro de un nodo y tenerlo en cuenta al diseñar. Esto implica que si los datos se almacenan bajo diferentes claves en una transacción en cada nodo, el resultado puede no ser el esperado. Por ejemplo: en un nodo escribimos en una transacción que A = 1 y B = 2. Y en otro nodo escribimos en una transacción que A = 2 y B = 3. Debido a las marcas de tiempo después de confirmar transacciones en nodos y sincronizar datos entre nodos el resultado será: A = 2, B = 2.

Por lo tanto, incluso desarrollar una pequeña función dentro de un DBMS requiere muchos recursos y una profunda inmersión en todos los matices. Y existen más de una docena de funciones y desarrollos de este tipo en el marco de la creación y el soporte de su propio DBMS.

En lugar de conclusiones

Construir su propio DBMS siempre es doloroso, costoso, difícil y requiere mucho tiempo. Por tanto, es aconsejable iniciar dicho desarrollo si:

  • las soluciones existentes no cubren las necesidades;

  • el equipo tiene la experiencia y los recursos necesarios;

  • El desarrollo desde cero está económicamente justificado y cumple con los objetivos comerciales.

Al mismo tiempo, debe comprender que no existe un esquema para crear un DBMS ideal; en cualquier caso, tendrá que utilizar prueba y error para “construir una bicicleta” que satisfaga mejor los requisitos de la empresa. Y una práctica útil en esto sería combinar las opciones existentes: tomando como base las ideas y principios de las opciones existentes, puede, como a partir de cubos de Lego, construir la herramienta más efectiva y confiable, lista para funcionar incluso en sistemas altamente cargados.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *