Categorías
Techies

4 – Cassandra DB, Crear un Clúster usando Docker

Si quieres poner en práctica lo que sabes de Cassandra de forma teórica, es imprescindible montar un cluster con varios nodos. No todo el mundo puede contar con varios servidores físicos para hacer esto y montar varias máquinas virtuales en un ordenador medio puede hacerse demasiado pesado.

La solución que os propongo hoy es Docker. ¿Vamos?

Partiré de una instalación de Debian Lite.

Instalar Docker

Instalamos dependencias que vamos a necesitar.

sudo apt-get install curl software-properties-common apt-transport-https ca-certificates gnupg-agent

Añade la clave del repositorio Docker.

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

Y agrega el repositorio a apt:

sudo add-apt-repository "deb https://download.docker.com/linux/debian buster stable"

Ahora sí, a instalar:

sudo apt-get update
sudo apt-get install docker-ce

Utilizaremos las imágenes oficiales en Docker que existen de Cassandra para crear nuestro primer nodo:

docker run --name node1 -d cassandra:3.11

Con el siguiente comando verificamos si está activo y funcionando.

docker ps

Tambien podemos ver la ip del nodo:

docker inspect --format='{{ .NetworkSettings.IPAddress }}' node1

Ahora creamos un segundo nodo:

docker run --name node2 -d --link node1:cassandra cassandra:3.11

Con el siguiente comando vemos el estado del cluster.

docker exec -it node1 nodetool status

Ya tenemos nuestro cluster de 2 nodos. Vamos a añadir un tercero para poder hacer unas pruebas.

docker run --name node2 -d --link node1:cassandra cassandra:3.11
docker run --name node3 -d --link node2:cassandra cassandra:3.11

Nota que estamos linkando el nodo2 al nodo1 y el nodo3 al nodo2. Sin embargo si consultamos el estado del cluster en el nodo1 vemos los tres nodos.

Esto es por el protocolo P2P gossip del que hablamos anteriormente. ¡La teoría es cosa del pasado, por fin vemos algo palpable!

Con el siguiente comando puedes parar los nodos. Será útil en futuros testeos simular que se cae un nodo.

docker stop node2

Con el siguiente comando puedes ver el listado de contenedores docker del sistema incluso si están parados.

docker ps -a

En el pantallazo de arriba puedes ver que el nodo2 está parado(Exited). Para arrancarlo:

docker start node2

Ahora viene lo interesante. Vamos a crearnos un KEYSPACE y una tabla para empezar a jugar.

Abrimos una conexión con sqlsh en el nodo1.

docker exec -ti node1 cqlsh

Y creamos nuestro entorno de pruebas, con un factor de replicación 2.

CREATE KEYSPACE my_ks WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 2};
USE my_ks;
CREATE TABLE messages (id int,message text,date timeuuid,PRIMARY KEY (id));
INSERT INTO messages(id,message,date) values (1,'Hola, es el primer mensaje.',now());
INSERT INTO messages(id,message,date) values (2,'Segundo mensaje',now());

exit;

Con el último exit salimos de cqlsh y del docker para volver a nuestra maquina.

Vamos a parar el nodo1 e iniciaremos una sesión cqlsh en el nodo3.

docker stop node1
docker exec -ti node3 cqlsh

Vamos a verificar que las replicas se están haciendo.

USE my_ks;
SELECT * FROM messages;

Ahí están, mis dos mensajes en perfecto estado, ¿y si estando el nodo1 parado insertamos un nuevo registro en el nodo3 y posteriormente iniciamos el nodo1? ¿estará el mensaje en el nodo1? Sin salirnos del nodo3 vamos a insertar un nuevo valor.

INSERT INTO messages(id,message,date) values (3,'¿Estás ahí, nodo1?',now());
exit;

Ahora iniciamos el nodo1 y abrimos sesión:

docker start node1
docker exec -ti node1 cqlsh

¿Existira el nuevo registro?

USE my_ks;
SELECT * FROM messages;

¿Veis la potencia de Cassandra ante caídas de nodos?

Seguramente, los que sigais toda la serie de artículos, os preguntareis ¿y qué hay del nivel de consistencia a la hora de consultar o escribir? Ejecutad el siguiente comando sin salir del docker nodo1:

CONSISTENCY

Es decir, `por defecto contamos con un nivel de consistencia UNO. Si lo recordais, esto permite las velocidades de respuesta más alta, porque solo nos basta la respuesta de uno de los nodos para que obtengamos el resultado deseado. Con los riesgos que supone, sobre todo a la hora de consultas-actualizaciones masivas en tiempo real. ¿Obtenemos realmente el último dato actualizado? Con este factor, no. Vamos a cambiarlo y a realizar una query:

CONSISTENCY ALL
SELECT * FROM messages;

Lo que está ocurriendo es que hemos consultado la información en todos los nodos replicados y hemos obtenido el valor más actualizado. ¿Qué ocurre si perdemos el nodo1 y hacemos la misma consulta desde el nodo3 con consistencia ALL?

Es decir, nos retorna un error porque no tenemos todos los nodos disponibles y no podemos garantizar la consistencia solicitada. Si cambiamos la consistencia a UNO y repetimos la consulta obtendremos el resultado del nodo3.

No es magia, es Cassandra. ¿Podéis notar la potencia de esto? Y aún no hemos hablado de montar en un cluster varios datacenters que pueden estar separados a kilómetros de distancia. Pero esto, ya lo explicaremos otro día.

Por último, y como curiosidad, quizás os habeis preguntado ¿cómo puedo saber en cuál de los nodos ha sido guardado el dato?

docker exec -ti node1 nodetool getendpoints my_ks messages 3

Es decir, al nodetool le pasamos la función getendpoint seguido de nuestro keystore, tabla y valor de la clave de partición.