6.1 Batalla de abreviaturas: BASE vs. ÁCIDO

"En química, el pH mide la acidez relativa de una solución acuosa. La escala de pH va de 0 (sustancias fuertemente ácidas) a 14 (sustancias fuertemente alcalinas); el agua pura a 25 °C tiene un pH de 7 y es neutra.

Los ingenieros de datos han tomado esta metáfora para comparar bases de datos con respecto a la confiabilidad de las transacciones".

Probablemente, la idea era esta: cuanto mayor sea el pH, es decir, cuanto más cerca esté la base de datos de "alcalina" ("BASE"), menos fiables serán las transacciones.

Las bases de datos relacionales populares, como MySQL, aparecieron solo sobre la base de ACID. Pero durante los últimos diez años, las denominadas bases de datos NoSQL, que combinan varios tipos muy diferentes de bases de datos bajo este nombre, han funcionado bastante bien sin ACID. De hecho, hay una gran cantidad de desarrolladores que trabajan con bases de datos NoSQL y no se preocupan en absoluto por las transacciones y su confiabilidad. Veamos si tienen razón.

No se puede hablar en general sobre la base de datos NoSQL, porque es solo una buena abstracción. Las bases de datos NoSQL difieren entre sí en el diseño de los subsistemas de almacenamiento de datos, e incluso en los modelos de datos: NoSQL es tanto CouchDB orientado a documentos como Neo4J gráfico. Pero si hablamos de ellos en el contexto de las transacciones, todos tienden a ser similares en una cosa: brindan versiones limitadas de atomicidad y aislamiento y, por lo tanto, no brindan garantías ACID. Para entender lo que esto significa, respondamos a la pregunta: ¿qué ofrecen, sino ACID? ¿Nada?

No precisamente. Después de todo, al igual que las bases de datos relacionales, también necesitan venderse en un paquete atractivo. Y se les ocurrió su propia abreviatura "química": BASE.

6.2 BASE como antagonista

Y aquí nuevamente no iré en orden de letras, pero comenzaré con el término fundamental: consistencia. Tendré que nivelar su efecto de reconocimiento, porque esta consistencia tiene poco que ver con la consistencia de ACID. El problema con el término consistencia es que se usa en demasiados contextos. Pero esta consistencia tiene un contexto de uso mucho más amplio y, de hecho, esta es exactamente la consistencia que se analiza cuando se analizan los sistemas distribuidos.

Las bases de datos relacionales de las que hablamos anteriormente brindan diferentes niveles de aislamiento de transacciones, y las más estrictas aseguran que una transacción no pueda ver los cambios no válidos realizados por otra transacción. Si usted está parado en la caja de una tienda, y en ese momento el dinero de la renta es retirado de su cuenta, pero la transacción con la transferencia del dinero de la renta falla y su cuenta vuelve a su valor anterior (el dinero es no debitado), entonces su transacción de pago en la caja no notará estos gestos; después de todo, esa transacción nunca se realizó y, según el requisito de aislamiento de transacciones, sus cambios temporales no pueden ser notados por otras transacciones.

Muchas bases de datos NoSQL renuncian a la garantía de aislamiento y ofrecen "coherencia eventual" mediante la cual eventualmente verá datos válidos, pero existe la posibilidad de que su transacción lea valores no válidos, es decir, temporales, parcialmente actualizados u obsoletos. Es posible que los datos se vuelvan consistentes en el modo "perezoso" al leer ("perezosamente en el momento de la lectura").

NoSQL fue concebido como una base de datos para análisis en tiempo real y, para lograr una mayor velocidad, sacrificaron la consistencia. Y Eric Brewer, el mismo que acuñó el término BASE, formuló el llamado "teorema CAP", según el cual:

Para cualquier implementación de computación distribuida, es posible proporcionar no más de dos de las siguientes tres propiedades:

  • consistencia de datos ( consistencia ) - los datos en diferentes nodos (instancias) no se contradicen entre sí;
  • disponibilidad ( disponibilidad ): cualquier solicitud a un sistema distribuido finaliza con una respuesta correcta, pero sin garantía de que las respuestas de todos los nodos del sistema sean las mismas;
  • Tolerancia de partición (tolerancia de partición ): incluso si no hay conexión entre los nodos, continúan funcionando de forma independiente entre sí.

Si desea una explicación muy simple de CAP, aquí la tiene.

Hay opiniones de que el teorema CAP no funciona y, en general, se formula de manera demasiado abstracta. De una forma u otra, las bases de datos NoSQL a menudo rechazan la coherencia en el contexto del teorema CAP, que describe la siguiente situación: los datos se actualizaron en un clúster con varias instancias, pero los cambios aún no se sincronizaron en todas las instancias. Recuerde, mencioné el ejemplo anterior de DynamoDB, que me dijo: sus cambios se volvieron duraderos, aquí hay un HTTP 200 para usted, pero solo vi los cambios después de 10 segundos. Otro ejemplo de la vida diaria de un desarrollador es el DNS, el sistema de nombres de dominio. Si alguien no lo sabe, entonces este es exactamente el "diccionario" que traduce las direcciones http (s) en direcciones IP.

El registro DNS actualizado se propaga a los servidores de acuerdo con la configuración del intervalo de almacenamiento en caché, por lo que las actualizaciones no se notan de inmediato. Bueno, una inconsistencia temporal similar (es decir, consistencia eventual) puede ocurrirle a un clúster de base de datos relacional (digamos, MySQL); después de todo, esta consistencia no tiene nada que ver con la consistencia de ACID. Por lo tanto, es importante comprender que, en este sentido, es poco probable que las bases de datos SQL y NoSQL sean muy diferentes cuando se trata de varias instancias en un clúster.

Además, la consistencia de extremo a extremo puede significar que las solicitudes de escritura se realizarán fuera de orden: es decir, se escribirán todos los datos, pero el valor que finalmente se recibirá no será el último en la cola de escritura.

Las bases de datos NoSQL que no son de ACID tienen el llamado "estado suave" debido al modelo de consistencia de extremo a extremo, lo que significa que el estado del sistema puede cambiar con el tiempo, incluso sin entrada. Pero tales sistemas se esfuerzan por proporcionar una mayor accesibilidad. Proporcionar el 100% de disponibilidad no es una tarea baladí, por lo que estamos hablando de “disponibilidad básica”. Y juntos estos tres conceptos: “básicamente disponible”, “soft state” (“estado blando”) y “consistencia eventual” forman el acrónimo BASE.

Para ser honesto, el concepto de BASE me parece un envoltorio de marketing más vacío que ACID, porque no aporta nada nuevo y no caracteriza la base de datos de ninguna manera. Y adjuntar etiquetas (ACID, BASE, CAP) a ciertas bases de datos solo puede confundir a los desarrolladores. Decidí presentarte este término de todos modos, porque es difícil pasarlo por alto al estudiar la base de datos, pero ahora que sabes lo que es, quiero que te olvides de él lo antes posible. Y volvamos al concepto de aislamiento.

6.3 ¿Entonces las bases de datos BASE no cumplen los criterios ACID en absoluto?

Esencialmente, donde las bases de datos ACID difieren de las que no son ACID es que las que no son ACID en realidad renuncian al aislamiento. Esto es importante de entender. Pero es aún más importante leer la documentación de la base de datos y probarla como lo hacen los chicos del proyecto Hermitage. No es tan importante cómo exactamente los creadores de esta o aquella base de datos llaman a su creación: ÁCIDO o BASE, CAP o no CAP. Lo importante es qué proporciona exactamente esta o aquella base de datos.

Si los creadores de la base de datos afirman que proporciona garantías de ACID, entonces probablemente haya una razón para ello, pero es recomendable que lo pruebe usted mismo para comprender si esto es así y en qué medida. Si declaran que su base de datos no proporciona tales garantías, esto puede significar lo siguiente:

  • El DB no ofrece ninguna garantía de atomicidad. Mientras que algunas bases de datos NoSQL ofrecen una API separada para operaciones atómicas (por ejemplo, DynamoDB);

  • La base de datos no ofrece ninguna garantía de aislamiento. Esto puede significar, por ejemplo, que la base de datos no escribirá los datos en el orden en que fueron escritos.

En cuanto a la garantía de durabilidad, muchas bases de datos se comprometen en este punto por el bien del rendimiento. Escribir en el disco es una operación demasiado larga y hay varias formas de resolver este problema. No quiero adentrarme mucho en la teoría de las bases de datos, pero para que comprenda aproximadamente de qué manera mirar, describiré en términos generales cómo las diferentes bases de datos resuelven el problema con la durabilidad.

Para comparar diferentes bases de datos, entre otras cosas, necesita saber qué estructuras de datos subyacen al subsistema de almacenamiento y recuperación de datos de una base de datos en particular. En resumen: diferentes bases de datos tienen diferentes implementaciones de indexación, es decir, organizan el acceso a los datos. Algunos de ellos le permiten escribir datos más rápido, otros, más rápido para leerlos. Pero no se puede decir en general que algunas estructuras de datos aumenten o disminuyan la durabilidad.

6.4 cómo las diferentes bases de datos indexan los datos y cómo esto afecta la durabilidad, y más

Hay dos enfoques principales para almacenar y recuperar datos.

La forma más sencilla de guardar datos es agregar operaciones al final del archivo en forma de registro (es decir, siempre se produce una operación de agregar): no importa si queremos agregar, cambiar o eliminar datos, todo Las operaciones CRUD simplemente se escriben en el registro. La búsqueda en el registro es ineficiente, y ahí es donde entra en juego el índice: una estructura de datos especial que almacena metadatos sobre dónde se almacenan exactamente los datos. La estrategia de indexación más simple para los registros es un mapa hash que realiza un seguimiento de las claves y los valores. Los valores serán referencias al desplazamiento de bytes para los datos escritos dentro del archivo, que es el registro (log) y se almacena en el disco. Esta estructura de datos se almacena completamente en la memoria, mientras que los datos en sí están en el disco, y se denomina árbol LSM (combinación estructurada de registro).

Probablemente te hayas preguntado: si escribimos nuestras operaciones en el diario todo el tiempo, ¿crecerá de forma exorbitante? Sí, y por eso se inventó la técnica de compactación, que “limpia” los datos con cierta periodicidad, es decir, deja solo el valor más relevante para cada clave, o lo borra. Y si tenemos más de un log en disco, pero varios, y están todos ordenados, entonces obtendremos una nueva estructura de datos llamada SSTable (“tabla de cadenas ordenadas”), y esto sin duda mejorará nuestro rendimiento. Si queremos ordenar en la memoria, obtendremos una estructura similar, la llamada MemTable, pero con ella el problema es que si ocurre un bloqueo fatal de la base de datos, los datos escritos en último lugar (ubicados en MemTable, pero aún no escritos en disco) se pierden. De hecho,

Otro enfoque de la indexación se basa en árboles B ("árboles B"). En un árbol B, los datos se escriben en el disco en páginas de tamaño fijo. Estos bloques de datos suelen tener un tamaño de alrededor de 4 KB y tienen pares clave-valor ordenados por clave. Un nodo de árbol B es como una matriz con enlaces a un rango de páginas. máx. el número de enlaces en una matriz se llama factor de ramificación. Cada rango de páginas es otro nodo de árbol B con enlaces a otros rangos de páginas.

Eventualmente, a nivel de hoja, encontrará páginas individuales. Esta idea es similar a los punteros en los lenguajes de programación de bajo nivel, excepto que estas referencias a páginas se almacenan en el disco en lugar de en la memoria. Cuando se producen INSERCIONES y ELIMINACIONES en la base de datos, algún nodo puede dividirse en dos subárboles para coincidir con el factor de ramificación. Si la base de datos falla por algún motivo en medio del proceso, la integridad de los datos puede verse comprometida. Para evitar que esto suceda, las bases de datos que utilizan árboles B mantienen un "registro de escritura anticipada" o WAL, en el que se registra cada transacción. Este WAL se usa para restaurar el estado del árbol B si está dañado. Y parece que esto es lo que hace que las bases de datos que usan árboles B sean mejores en términos de durabilidad. Pero las bases de datos basadas en LSM también pueden mantener un archivo que realiza esencialmente la misma función que WAL. Por lo tanto, repetiré lo que ya he dicho, y quizás más de una vez: comprender los mecanismos de funcionamiento de la base de datos que ha elegido.

Sin embargo, lo que es seguro acerca de los árboles B es que son buenos para la transaccionalidad: cada clave aparece en un solo lugar en el índice, mientras que los subsistemas de almacenamiento registrados pueden tener varias copias de la misma clave en diferentes fragmentos (por ejemplo, hasta que el se realiza la siguiente compactación).

Sin embargo, el diseño del índice afecta directamente el rendimiento de la base de datos. Con un árbol LSM, las escrituras en el disco son secuenciales y los árboles B provocan múltiples accesos aleatorios al disco, por lo que las operaciones de escritura son más rápidas con LSM que con los árboles B. La diferencia es especialmente significativa para las unidades de disco duro magnéticas (HDD), donde las escrituras secuenciales son mucho más rápidas que las aleatorias. La lectura es más lenta en los árboles LSM porque tiene que mirar a través de varias estructuras de datos diferentes y tablas SS que se encuentran en diferentes etapas de compactación. Con más detalle se ve así. Si hacemos una consulta de base de datos simple con LSM, primero buscaremos la clave en MemTable. Si no está allí, miramos el SSTable más reciente; si no está allí, miramos la penúltima SSTable, y así sucesivamente. Si la clave solicitada no existe, entonces con LSM sabremos esto último. Los árboles LSM se utilizan, por ejemplo, en: LevelDB, RocksDB, Cassandra y HBase.

Lo describo todo con tanto detalle para que comprenda que al elegir una base de datos, debe considerar muchas cosas diferentes: por ejemplo, espera escribir o leer más datos. Y aún no he mencionado la diferencia en los modelos de datos (¿necesita recorrer los datos, como lo permite el modelo gráfico? ¿Hay alguna relación entre las diferentes unidades en sus datos? ¿Entonces las bases de datos relacionales vendrán al rescate?), y 2 tipos de esquemas de datos: al escribir (como en muchos NoSQL) y al leer (como en relacional).

Si volvemos al aspecto de la durabilidad, entonces la conclusión será la siguiente: cualquier base de datos que escriba en el disco, independientemente de los mecanismos de indexación, puede proporcionar buenas garantías para la durabilidad de sus datos, pero debe tratar con cada base de datos específica. , qué es exactamente lo que ofrece.

6.5 Cómo funcionan las bases de datos en memoria

Por cierto, además de las bases de datos que escriben en el disco, también existen las llamadas bases de datos "en memoria" que funcionan principalmente con RAM. En resumen, las bases de datos en memoria suelen ofrecer una menor durabilidad en aras de velocidades de lectura y escritura más rápidas, pero esto puede ser apropiado para algunas aplicaciones.

El hecho es que la memoria RAM ha sido durante mucho tiempo más cara que los discos, pero recientemente ha comenzado a abaratarse rápidamente, lo que ha dado lugar a un nuevo tipo de base de datos, lo cual es lógico, dada la velocidad de lectura y escritura de datos de la RAM. Pero se preguntará con razón: ¿qué pasa con la seguridad de los datos de estas bases de datos? Aquí nuevamente, debe observar los detalles de la implementación. En general, los desarrolladores de dichas bases de datos ofrecen los siguientes mecanismos:

  • Puede usar RAM alimentada por baterías;
  • Es posible escribir registros de cambios en el disco (algo así como los WAL mencionados anteriormente), pero no los datos en sí;
  • Puede escribir periódicamente copias del estado de la base de datos en el disco (lo que, sin usar otras opciones, no ofrece garantía, sino que solo mejora la durabilidad);
  • Puede replicar el estado de la RAM a otras máquinas.

Por ejemplo, la base de datos Redis en memoria, que se usa principalmente como cola de mensajes o caché, carece de durabilidad de ACID: no garantiza que un comando ejecutado con éxito se almacenará en el disco, ya que Redis vacía los datos en el disco (si tener la persistencia habilitada) solo de forma asíncrona, a intervalos regulares.

Sin embargo, esto no es crítico para todas las aplicaciones: Encontré un ejemplo del editor en línea cooperativo EtherPad, que se descargaba cada 1 o 2 segundos y, potencialmente, el usuario podía perder un par de letras o una palabra, lo que no era crítico. De lo contrario, dado que las bases de datos en memoria son buenas porque proporcionan modelos de datos que serían difíciles de implementar con índices de disco, Redis se puede usar para implementar transacciones; su cola de prioridad le permite hacer esto.