Categorías
Techies

1 – Cassandra DB, ¿Qué es?

Cassandra es una base de datos NoSQL. Siquieres saber más sobre NoSQL lee el siguiente atículo.

Se fraguó de la necesidad de Facebook de hacer frente al crecimiento de consultas que hacían sobre su web. Y no sólo el número de consultas, si no que además el volumen de datos manejado se hacía ya insostenible. Buscando rapidez de respuesta en las consultas sobre un almacén de datos gigantesco, así nació Cassandra.

¿Por qué elegir Cassandra y no otra para tu proyecto? Empezamos hablando del teorema de CAP.

Teorema de CAP

El teorema CAP, también llamado Conjetura de Brewer, enuncia que es imposible para un sistema de cómputo distribuido garantizar simultáneamente:
– La consistencia (Consistency), es decir, cualquier lectura recibe como respuesta la escritura más reciente o un error.
– La disponibilidad (Availability), es decir, cualquier petición recibe una respuesta no errónea, pero sin la garantía de que contenga la escritura más reciente.
– La tolerancia al particionado (Partition Tolerance), es decir, el sistema sigue funcionando incluso si un número arbitrario de mensajes son descartados (o retrasados) entre nodos de la red.

Según el teorema, un sistema no puede asegurar más de dos de estas tres características simultáneamente.

Wikipedia
1*rxTP-_STj-QRDt1X9fdVlA.png (473×374)
medium.com

Cassandra proporciona alta disponibilidad y tolerancia al particionado. ¿Pero qué hay de la Consistencia? ¿si hago la misma consulta en dos nodos distintos obtendré el mismo resultado? El nivel de consistencia en Cassandra es configurable. Cassandra es más consistente cuanto más tiempo pasa. Por lo tanto, en proyectos donde las consultas se van a hacer bastante más tarde que las escrituras, tendremos máxima consistencia. Si lo que necesitamos es garantizar la escritura y la consulta no es una prioridad en tiempo real, Cassandra debe ser la elegida. Para ahondar más en el tema vamos a ver el siguiente punto.

Base de datos Distribuida

Cassandra fue diseñada para no tener un nodo principal, en ella todos los nodos actúan por igual y los datos se distribuyen entre todo el cluster (conjunto de nodos).

Esquema de un Cluster o Anillo de Cassandra

Factor de replicación

Se puede configurar el factor de replicación para evitar perdidas de datos cuando un nodo cae. Eso unos de los pasos más importantes en un proyecto en producción. Un factor 2, significa que una misma fila se almacena en dos nodos. ¿Lo recomendable? Dependiendo de los recursos disponibles y de la criticidad de los datos. En mis proyectos suelo utilizar un factor 2 o 3. Si uno de los nodos cae, siempre queda algún otro con los datos disponibles.

¿Qué pasa si tengo un factor de replicación 2 en un sistema con 2 nodos en los que uno de ellos ha caído? En este caso las escrituras se guardan para cuando el nodo vuelva a estar activo.

También se puede configurar la estrategia de replicación:

  • SimpleStrategy. Estrategia simple. Copia la información al siguiente nodo hasta cumplir el factor de replicación configurado. Es la estrategia elegida normalmente en entornos de desarrollo.
  • NetworkTopologyStrategy. Solo se usa cuando disponemos de varios datacenters. Se utiliza sobre todo en entornos de producción y podemos elegir el factor de replicación de cada datacenter. Además se asegura, si es posible, de no dejar una replica del dato en el mismo rack. Un rack es un grupo de nodos, que normalmente están físicamente en el mismo sitio. Un datacenter puede tener varios racks.

Nivel de consistencia

Por un lado está el factor de replicación, pero también tenemos el nivel de consistencia. No deben confundir ambos términos ya que son cosas distintas. El nivel de consistencia especifica cuántos nodos ha decidido el cliente que deben responder a una determinada consulta.

Si vienes de las bases de datos relacionables lo que te voy a contar te va a resultar llamativo. En Cassandra el cliente, cuando abre una nueva sesión, decide qué nivel de consistencia quiere en cada operación de consulta o escritura. Es decir, ¿cuántos nodos del cluster quiero que me respondan ante una lectura o escritura? A más nivel de consistencia, más seguridad en los valores.

En operaciones de consulta, el cliente puede especificar cuantos nodos de réplica deben responder antes de devolver el dato.

En operaciones de escritura, el cliente especifica cúantos nodos de replica deben responder antes de confirmar la escritura. Tened en cuenta que las actualizaciones a otros nodos de réplica pueden continuar en segundo plano.

Mejor partamos de un ejemplo:

  • Tenemos un clúster de 5 nodos (A-B-C-D-E).
  • Tenemos un factor de replicación fijado en 3. Es decir, cada vez que escribas el valor se almacenará en 3 de los nodos.

Un cliente X abre una sesión en la que va a escribir un dato. Cuanto mayor sea el nivel de consistencia, mayor será el tiempo necesario para realizar una escritura y recibir la confirmación. Veamos distintas posibilidades:

  • Nivel de consistencia UNO. El cliente recibe que su operación de escritura ha sido exitosa cuando se ha escrito el valor en uno de los nodos (por ejemplo el B). En segundo plano Cassandra se preocupará por replicar la información en tres nodos (por ejemplo B-D-E) pero sin que el cliente tenga confirmación.
  • Nivel de consistencia TODOS. El cliente recibe que su operación de escritura ha sido exitosa cuando se ha escrito el valor en tres de los nodos (por ejemplo B-D-E). Si alguno de ellos está caido, no lograremos insertarlo y a cambio de la consistencia perderemos la disponibilidad.
  • Nivel de conssitencia ANY. Cuando al menos un nodo del cluster esté activo la inserción se hará. Se hará incluso si el nodo que ha recibido la orden no tiene acceso al resto porque están caidos. En ese caso guardará el dato y se la enviara al resto cuando esté activo. El problema aquí es que no podremos consultar ese dato hasta que el resto de nodos estén levantados y almacenen el dato. Disponibilidad total(con un nodo activo en todo el cluster nos vale), la consistencia es mínima(escribimos pero no podemos consultar el dato de momento)
  • Hay muchos niveles de consistencia, para profundizar más podéis consultar la documentación oficial.

Ahora otro cliente Y abre una sesión y va a consultar el dato escrito por el cliente X. Cuanto mayor sea el nivel de consistencia, mayor será el tiempo necesario para obtener la respuesta de nuestra consulta. Veamos disintas posibilidades:

  • Nivel de consistencia UNO. El cliente recibe el resultado de su consulta de uno de los nodos. que su operación de escritura ha sido exitosa cuando se ha escrito el valor en uno de los nodos (por ejemplo el B). El riesgo aquí es que paralelamente un cliente Z actualice el dato en el nodo D y aún no se haya replicado a los otros dos nodos (B-E). Esto no nos garantiza que el resultado obtenido sea el último escrito.
  • Nivel de consistencia TODOS. El cliente recibe el resultado de la consulta cuando haya verificado la última versión de los tres nodos (B-D-E). A cambio tardaremos más en obtener la respuesta.
  • Nivel de consistencia QUORUM. Esto es el resultado de la fórmula (nodos/2)+1. En nuestro caso 3/2+1=2. Es decir, un equivalente a DOS en nuestro caso. Hasta que no se haya recibido confirmación de escritura en DOS de los nodos, esteremos esperando. Ojo que si no tienes el suficiente número de nodos funcionando, la escritura-lectura fallará.

P2P

Cassandra no sigue el patrón maestro-esclavos. Al no existir un nodo principal, ¿dónde se encuentra la información de todos los nodos? La respuesta es en todos. Mediante el protocolo P2P gossip toda la información acerca del cluster, topología, rendimiento, disponibilidad de nodos… se intercambia entre todos los nodos. Es un protocolo P2P. Esta información es útil para que el cliente sepa cual es el mejor nodo para leer o escribir en cada momento.

Escalable linealmente

En cuanto al número de nodos de la red siempre es recomendable que el número de nodos supere el factor de replicación. También dependerá de las exigencias en cuanto a número de operaciones por segundo, a más nodos, más operaciones por segundo están permitidas.

Si duplicamos el número de nodos, duplicamos el número de operaciones que se pueden hacer por segundo.

Escabilidad Horizontal

En una estabilidad vertical, lo que hacemos es añadir recursos a la máquina que usamos como servidor. Es lo que se suele hacer en las bases de datos relacionales. Si nuestro sistema empieza a saturar por el aumento en el volumen de uso, la solución es añadir más CPU, mas RAM, mas espacio en disco… esto supone grandes costes a las empresas. Es lo que ocurrió en Facebook, los costes se disparaban más y más y el rendimiento cada vez iba a menos dado que el volumen no paraba de aumentar.

En una escabilidad horizontal como Cassandra, lo que hacemos es poner otro servidor más y repartir la carga.

Cómo almacena el dato

Lo primero que hace Cassandra es guardarlo en un Commit log, por si perdemos la alimentación y asi evitar perder el dato. A continuación lo guarda en memoria en la estructura memtable(corresponde con nuestras tablas). Una vez el dato está en memtable, el cliente tendrá el ok. Si os fijáis en este momento no ha habido ninguna lectura al disco. En una base de datos relacional se necesita leer del disco para verificar que la PK no existe, que la FK existe… Cassandra hace 0 lecturas y ya ha confirmado al usuario la escritura. En Cassandra la escritura es mucho más rápida que la lectura.

Cuando la memtable se llena se hace Flush al disco en la estructura SSTable y se hace en bloque. Muchos mas eficiente que en una base de datos relacional. Apuntar algo importante, las SSTable no se modifican nunca.

Si las SSTable no se modifican, ¿no se nos llena el disco de cosas innecesarias (registros eliminados, duplicados…)? Para solucionar esto está la compactación.

Al crear una tabla tenemos que seleccionar la estrategia de compactación. Existen estas tres:

  • SizeTieredCompactionStrategy. Si nuestro caso de uso es que se escribe una vez y los datos no se suelen modificar.
  • LeveledCompactionStrategy. Si nuestro caso de uso es que se escribe y además se modifica bastante.
  • DateTieredCompactionStrategy. Y si estamos guardando datos de sensores que se suelen leer en fragmentos de tiempo. Ojo porque es una estrategia poco depurada y por lo tanto bastante inestable actualmente. De momento no he logrado hacerlo funcionar 100% en un entorno productivo. Pero promete.

Comunicación Cliente-Cassandra

La comunicación entre el cliente y Cassandra se puede realizar a través de dos protocolos o lenguajes.

  • CQL(Cassandra Query Language). Este es el más reciente y el más utilizado ya que es prácticamente igual que SQL en las bases de datos relacionales.
  • RFC

El cliente se comunica con un nodo, que puede ser cualquier nodo del cluster. Este nodo hará de coordinador. Supongamos que el Cliente acceder al Nodo E y le pide insertar un dato. Aplica una función hash y resulta que correspondería insertarlo en el Nodo B y como tiene un factor de replicación 2, también al Nodo C.

En el caso de varios datacenters, el coordinador contactará con los coordinadores de otros datacenters.

Normalmente la API que usemos para conectar con Cassandra tendrá implementada la función hash que decide a qué nodo ir ante una consulta. Lo que hará esta API es conectar directamente con el nodo objetivo para maximizar la eficiencia. Y si este nodo está caído, a cualquier otro.

Ventajas-Desventajas

Como ventaja principal está la alta disponibiliad, muy importante para los casos en los que la caída de un sistema es un desastre.

Otra ventaja es la tolerancia a particiones y su escalabilidad.

La principal desventaja es que las queries debemos conocerlas previamente. En un sistema de bases de datos relacional, podemos hacer lo que queramos uniendo todas las tablas disponibles. En Cassandra antes del modelado necesitamos saber la query que vamos a necesitar. Esto en la práctica es complicado, ¿qué cliente no cambia de opinión cada día?

Modelado de datos

Cassandra almacena los datos por Clave-Valor. Cada clave primaria puede mapear uno o más valores. Y la clave primaria se puede formar por dos claves especiales; la clave de partición (para repartir los datos en todo el clúster) y opcionalmente la clave de agrupación(para agrupar y organizar los datos de una partición con fines de eficiencia).

Por ejemplo en el esquema anterior podemos poner que las claves son ids de usuario, que la Columna 1 es un clustering key con la fecha de publicación y el resto de campos cosas extras como mensaje, asunto…

Hay que tener mucho cuidado en elegir la clave primaria, porque esta será la que se use para hacerle hash y elegir el nodo destino. El cómo se distribuyan nuestros datos dentro del cluster dependerá de la clave primaria elegida. Podría pasar que todos los registros vayan siempre al mismo nodo, y eso no es lo que queremos.

También hay que prestar especial atención en seleccionar correctamente las Clustering Columns. para que Cassandra guarde los datos de forma lineal en el disco.

Un paréntesis aquí para explicar diferencias de clave primaria, clave de partición, clustering:

  • Clave principal. Identifica inequívocamente una fila dentro de una tabla. Puede ser una clave compuesta por varias columnas, o una sola.
  • Calve de partición. Es la que se usa para hacer el hash y ver a que nodo pertenece.
  • Calave de agrupacion o clustering. Es la parte de la clave principal que no es clave de partición. Estos campos deciden el orden de los datos dentro de la partición.

Ejemplos de definición:

  • PRIMARY KEY (a): La clave principal y de partición es a.
  • PRIMARY KEY (a, b): La clave principal es a y b. La clave de partición es a. La clave de clustering es b.
  • PRIMARY KEY ((a, b)): La clave principal y de partición compuesta es (a, b).
  • PRIMARY KEY (a, b, c): La clave principal es a, b y c. La clave de partición es a. La clave de agrupación compuesta es (b, c).
  • PRIMARY KEY ((a, b), c): La clave principal es a, b y c. La clave de partición compuesta es (a, b). La clave de clustering es c.

Para verlo mejor vamos a poner el siguiente ejemplo. Queremos una consulta de todos los libros que se lee un usuario. Esta consulta tendrá los siguientes campos:

  • ID usuario. Será PK, ya que queremos que los datos de un mismo usuario estén en una unica particion para obtener los datos más rápidos.
  • ISBN del libro será Clustering Clomunn.
  • Título del libro
  • Autor
  • Nombre del usuario.

Se suele usar la siguiente fórmula para ver cuanto de grandes pueden tener nuestras particiones. El resultado de la fórmula es recomendable que sea por debajo de 1 millón. Veamos con nuestro ejemplo:

Ncells=Nrow*(NCols-Npk-Nstatic)+Nstatic
Nrow(número de filas de nuestra partición)=Número de libros que se lee un usuario
NCols(número de columnas)=5
Npk(columnas de la clave de partición)=1
Nstatic(columnas estáticas)=0
Ncells(número de celdas)=Nrow*4<1M

Mientras los usuarios no se lean 250000 libros, vamos bien. Si nos saliese un valor extremadamente alto, deberíamos modificar la clave de partición añadiendo mas columnas. Se suele utilizar sobre todo partes de fecha.

A la hora de modelar los datos tenemos que cambiar la mentalidad del join. En Cassandra tenemos que conocer la query previamente y montar una tabla que represente esa query. La idea es aligerar al cliente de cualquier join.

También cambia la mentalidad del ahorro. Se va duplicar mucha información. Podemos tener una tabla con información de usuarios y mensajes, y otra tabla con la misma información de usuarios y su actividad en la web. El espacio hoy en día es barato.

Cualquier consulta obligatoriamente tiene que incluir la primary key.

Una buena práctica podría ser tener dos datacenters. Uno para lecturas, y otro para escrituras.

CQL

Si sabéis SQL, no tendréis problemas en familiarizaros con CQL. CQL es básicamente un subconjunto de SQL.

Particularidades llamativas:

  • No hay JOINs.
  • Se puede utilizar en un WHERE: “=”, IN, “>=” pero no “!=” o LIKE.

Si estás familiarizado con las bases de datos relacionales de toda la vida, estarás notando el paralelismo. En el próximo artículo de la serie instalaremos un entorno de desarrollo para ponernos manos a la obra.

Hasta entonces.

Deja una respuesta

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