Jun 29

Primeras impresiones de Apache Cassandra

Apache CassandraEstán de moda las bases de datos BigData, bases de datos que son capaces de manejar cantidades ingentes de datos con multitud de clientes simulttáneos insertando, modificando y consultando datos. Al quedarse pequeñas las bases de datos tradicionales, las grandes compañías como google, facebook, … desarrollaron sus propios sistemas de base de datos : Google desarrolló BigTable y Facebook comenzó lo que ahora es Cassandra.

Así que me he puesto a jugar con Apache Cassandra y he aquí mis primeras impresiones.

Lo primero es que me ha parecido muy simple de instalar y poner en marcha. Un simple zip para desempaquetar y arrancar, o bien un instalador adecuado para el sistema operativo. Por ejemplo, el de Windows lo instala directamente como servicio si así lo deseamos.

Conectar varios servidores de Apache Cassandra entre sí para que formen un nodo multi-cluster también es relativamente sencillo. No he visto una documentación que diga correctamente todo lo que hay que tocar, pero no son más que cuatro o cinco propiedades en el fichero de configuración y no cuesta mucho encontrarlas tras revisar un poco la documentación para tenerlo funcionando.

Finalmente, desde java con el conector adecuado o bien desde la misma línea de comandos que ofrece Apache Cassandra, se pueden crear los primeros keyspaces, column families y datos. No he tenido demasiados problemas para hacer funcionar correctamente los ejemplos que encontré por ahí o mis propias pruebas.

Hablando de pruebas, me dio por comparar velocidad entre Apache Cassandra y PostgreSQL. No hice una prueba exahustiva, simplemente cree en ambas bases de datos una tabla igual, con las mismas columnas e índices, un solo servidor Cassandra, sin cluster ni nada, y partiendo de cero registros en cada tabla, lance dós hilos java, uno a hacer "update or insert" en una base de datos y otro lo mismo en la otra. Para Cassandra sólo insert, ya que si la fila existe, hace el update automáticamente. El resultado fue que PostgreSQL es más rápido inicialmente (unos 150 ms por cada 1000 insert/update frente a los 400 ms de Cassandra), pero tras estar funcionando el programa un rato largo y tener cerca de 2 millones de registros en la tabla, PostgreSQL tardaba unos 1700 ms por cada 1000 insert/update, mientras que Cassandra se mantenía firmemente en 400 ms.

Me ha parecido impresionante la facilidad de uso y su posibilidad de distribuir datos entre varios cluster, haciendo réplicas en varios discos o bien repartiendo los datos. Sin embargo, le he visto una gran pega a Apache Cassandra, precisamente su punto fuerte se convierte en su punto débil.

Cassandra está pensada para montar N servidores, cada uno con su ejecutable de Cassandra, trabajando en paralelo sobre M discos duros. Es capaz de manejar mogollón de datos eficientemente porque tiene a su disposición varios ordenadores entre los que repartir la carga y varios discos duros en los que repartir los datos. No es lo mismo que miles de clientes accedan simultáneamente a miles de datos dentro del mismo servidor y mismo disco, que Cassandra sea capaz de distribuir esos clientes en función de la carga de cada servidor y de lo ocupados de los discos. De hecho, los clientes puede conectarse a cualquiera de los ejecutables de Cassandra indistintamente. Pero justo esa distribución de datos en varios discos tiene una pega.

Si se hace una consulta de datos, Cassandra tendría que recorrer todos los discos para asegurarse que encuentra todos los datos solicitados. La busqueda de datos, pensada así, no es eficiente, así que Cassandra de alguna forma prohíbe hacer búsquedas que no estén planificadas previamente. Hablando lenguaje de programador, en la cláusula WHERE de una consulta no podemos poner lo que nos dé la gana. Hay que indicarle a Cassandra, en el diseño de las tablas, cómo vamos a consultar, de forma que Cassandra sea capaz de repartir los datos adecuadamente en los discos y sea luego capaz de saber en qué discos están los datos que estamos pidiendo.

Cassandra repartirá los datos en los discos de acuerdo a unos criterios, de forma que luego sea capaz de encontrarlos eficientemente. El primer criterio es la clave primaria de la tabla, en función de su valor, va a un disco u otro. Siempre se puede consutar por clave primeria, porque Cassandra sabe en qué disco estará ese dato.

Si queremos buscar por otros campos que no sean clave primaria, Cassandra nos obliga a crear índices secundarios para esos campos. Usando estos índices, Cassandra también sabrá en qué disco está cada dato, por lo que las búsquedas serán más eficientes. Pero la misma documentación de Cassandra nos advierte, no es adecuado crear un índice secundario de un campo que tenga valores distintos siempre. Por ejemplo, si nuestra tabla es de una flota de camiones, podemos crear un índice por marca de camión, ya que habrá varios camiones de la misma marca. Pero si estamos guardando las posiciones del camión obtenidas de sus gps, no podemos crear índices por la fecha/hora de la posición, ya que es muy probable que no haya dos fechas/horas iguales en todas las tablas, ni tampoco por latitud/longitud, por el mismo motivo.

¿Qué dice Cassandra que hagamos entonces para ese tipo de campo si queremos buscar por él?. Pues aprovechar que las columnas de las tablas son dinámicas. Cada fila dentro de una misma tabla puede tener columnas diferentes a otras filas y las columnas se ordenan por orden alfabético de nombre de columna. Por ejemplo, si se quieren guardar las posiciones históricas de un camión obtenidas de su GPS, se crearía una tabla en el que la clave sería el identificador de cada camión, es decir, habría una fila por cada camión. En cada fila, cada vez que se obtiene una nueva posición del camión que corresponde a esa fila, se crea una columna cuyo nombre es la fecha/hora y cuyo valor es la posición. Si más adelante queremos consultar las posiciones de un camión, Cassandra sabrá en qué disco está el camión por su id y cargará la fila completa con todas las fecha/hora y posición.

Y surge ahí otra pega. Una fila en Cassandra está limitada a unos 2Gigas, pero además, como se carga en memoria completa, conviente que la fila completa no ocupe más de la memoria que estemos dispuestos a gastar en ello (unos Megas, posiblemente). Así que debemos "partir" esa fila en filas más pequeñas haciendo ciertos "artificios" extraños. Por ejemplo, la clave de la fila, en vez de ser el camión, podria ser una cosa compuesta como <camion>.<dia>, así en cada fila sólo estarán las posiciones de ese camión en ese día.

Y esta tabla sólo para consultar posiciones de un camión en determinadas fechas. Habría que inventar tablas similares si se quieren consultar, por ejemplo, camiones que hayan estado en una zona  geográfica determinada en determinadas fechas, etc, etc. Y todas esas tablas tenemos que tenerlas actualizadas desde código.

Bueno, el detalle no importa, lo importante es hacerse idea del "artificio" que hay que montar para poder hacer consultas eficientes por una columna concreta con una posición geográcia o con una fecha/hora y que el diseño de tablas va a estar muy relacionado con las consultas que queramos hacer. En muchos sitios, a la hora de diseñar una base de datos Cassandra, aconsejan empezar pensando qué consultas va a hacer nuestra aplicación, y luego empezar a diseñar tablas, incluso repitiendo datos en varias tablas si es neceasario por eficiencia.

¿Y cual es la conclusión?. Si vas a tener "BigData" (cantidades ingentes de datos y conexiones simultáneas), adelante, usa Cassandra o una base de datos equivalente, no te queda más remedio ya que las bases de datos SQL no son capaces. Pero si no vas a tener "BigData", usar Cassandra no te va a aportar grandes beneficios, pero si montones de pegas si no tienes muy claro qué consultas vas a hacer exactamente en tus tablas, y tendrás más cosas que codificar en tu aplicación para facilitar consultas "extrañas", como consultar por fecha/hora, ya que tendrás que hacer los insert adecuados en las tablas de columnas variables con claves compuestas <camion>.<dia>.  Por cierto, ¿he comentado que Cassandra no tiene JOINs ni permite consultas mezclando tablas?. Sí, es otra cosa que tendrás que hacer desde tu código.

Hay otro posible caso en que puede ser útil una base de datos NoSQL (pienso quizás en alguna como MongoDB más que Cassandra) y es en pequeñas/medianas aplicaciones donde sólo se necesite una base de datos y no se requiera toda la complejidad de una base de datos SQL (tablas, restricciones, "foreing keys", etc). Bases de datos como MongoDB son muy dinámicas, podemos insertar datos variopintos sobre la marcha sin necesidad de echar unas horas diseñando tablas y modificándolas si luego no nos valen. Evidentemente, con MongoDB también hay que echar una "pensada" previa a lo que queremos, pero no tenemos la rigidez de una base de datos SQL.

Entradas relacionadas:

  • No hay entradas relacionadas.

4 Responses to “Primeras impresiones de Apache Cassandra”

  1. Victor Says:

    Muy buena información. Muchas gracias. Me será muy útil. 🙂

  2. gorlok Says:

    Buen artículo. Muy interesante el análisis.

  3. necroair Says:

    un blog cojonudo. Tienes articulos muy interesantes.

  4. Mario Says:

    Muchas gracias por el articulo 😀 me ha aclarado mucho como definir el modelo de datos.

Leave a Reply