¿Cuándo usar Cassandra? ¿Cuándo usar MongoDB?

¿Qué sistema de base de datos NoSQL debemos usar para nuestra aplicación? ¿Cuándo debemos usar Cassandra? ¿Cuándo debemos usar Mongodb? ¿Cuál es mejor?

No pretendo hacer una comparación entre base de datos NoSQL y una base de datos relacional como MySQL. Cada una tiene sus ventajas y desventajas; además tienen objetivos diferentes. Tampoco hablaremos del poder de las base de datos NoSQL, ni lo grandioso que puede ser Redis para nuestra aplicación.

En esta publicación, compartiré información que será de ayuda para comprender que es Cassandra, y en que se diferencia de MongoDB; además de conocer como funciona MongoDB y  que lo hace diferente de Cassandra.

¿Cuál es mejor?….en realidad ambos son excelentes base de datos NoSQL. ¿Y entonces cuándo debo usar MongoDB? ¿Cuándo debo usar Cassandra?…dependerá mucho de la necesidad de tu aplicación, hay muchas variables que debes analizar, por ejemplo, cantidad de escrituras vs lecturas en la base de datos, almacenamiento constante de información, escalabilidad, velocidad de respuesta, incrementos exponenciales en el consumo de información, datos en constante actualización o bajo porcentaje de modificación, entre otras cosas.

Ambos sistemas de base de datos NoSQL tienen varias fortalezas en común; una de ellas es el poder que tienen para manejar grandes, pero grandes cantidades de datos no estructurados y tener la capacidad de escalar horizontalmente.

¿Puedo escalar mi base de datos con Cassandra y MongoDB?

Si, y no serás el primero en querer hacerlo, Cassandra es la base de datos NoSQL de Instagram, en la cual se almacena más de 80 millones de fotos cargadas todos los días. MongoDB es parte del stack tecnológico de Google Compute Engine.


¿Cómo se almacena la información en ambos sistemas de base de datos?

Cassandra almacena la información en “Columns Families” que son objetos de base de datos similares a las tablas de un sistema de base de datos relacional (como MySQL), las cuales contienen filas y columnas, cada fila con una clave única. A diferencia de un sistema de base de datos relacional, todas las filas de una tabla no están obligadas a tener las mismas columnas. Estas columnas también se pueden agregar sobre la marcha y se accede a ellas utilizando el Lenguaje de Consulta de Cassandra (CQL= Cassandra Query Language). Mientras que CQL es similar a SQL en sintaxis, Cassandra no es relacional, por lo que tiene diferentes formas de almacenar y recuperar datos.

MongoDB almacena la información en documentos similares a JSON que pueden tener estructuras variadas. Utiliza un lenguaje propio de consulta para permitir el acceso a los datos almacenados. Como no tiene esquemas, puede crear documentos sin tener que crear primero la estructura del documento.

¿Quienes usan estas base de datos?

Ambas bases de datos tienen miles de seguidores y grandes organizaciones tecnológicas que confían en ellas.

Cassandra, escrita en Java, fue liberada en el 2008, ha sido utilizada por muchas organizaciones, incluidas AppScale, Constant Contact, Digg, Facebook, Twitter, IBM, Instagram, Spotify, Netflix y Reddit.

MongoDB, escrita en C++, fue liberada en el 2009, ha sido utilizado por muchas organizaciones, entre ellas. Google, UPS, Facebook, Cisco, eBay, BOSH, Adobe, SAP, Forbes y muchos más. Puedes consultar la lista completa aquí.

¿Cuál es la sintaxis para consultar información?

Por ejemplo, si queremos consultar registros de una tabla de Productos.

Cassandra: SELECT * FROM products

MongoDB: db.products.find()

Insertar registros a una tabla de Personas (Contactos).

Cassandra: INSERT INTO contacts (contact_id,name,last_name) VALUES (‘c00001′,’Gonzalo’,’Chacaltana Buleje’)

MongoDB: db.contacts.insert({contact_id:’c00001′,name:’Gonzalo’,last_name:’Chacaltana Buleje’})

Actualizando registros en una tabla de Productos.

Cassandra: UPDATE products SET stock=2000 WHERE product_name=’Milk’

MongoDB: db.products.update.({product_name:’Milk’},{$set:{stock:2000}})

¿Cómo funciona la replicación en estas bases de datos?

Cassandra replica desde el primer momento. Solo le dice la cantidad de nodos a los que debe copiar sus datos y se  ocupa del resto del proceso de replicación.

Cassandra permite tener múltiples bases de datos maestras y en caso de la pérdida de un nodo, Cassandra podrá escribir en el resto de base de datos (Cluster). Esta característica permite una mejor tolerancia a fallas, evitando perder tiempo de inactivividad como podría ocurrir con MongoDB.

MongoDB tiene una replicación incorporada con auto-elecciones, es decir, con MongoDB podrás configurar una base de datos secundaria que se puede convertir de manera automática en una base de datos principal si la base de datos principal (inicial) deja de estar disponible. Sin embargo, MongoDB requiere una cierta configuración (y tal vez un poco de ayuda de soporte) para hacer la replicación. MongoDB tiene conjuntos de réplicas donde un miembro es el primario y todos los demás tienen un rol secundario (Modelo Master-Slave). Las lecturas y escrituras se confirman primero en la réplica principal y luego se replican en las réplicas secundarias.

MongoDB tiene una sola base de datos maestra.

Mientras que el proceso de auto-elección ocurre automáticamente, puede tomar de 10 a 40 segundos para que ocurra. Mientras esto sucede, no puede escribir en el conjunto de réplicas.

¿Quién está actualmente detrás de estas bases de datos?

En el caso de Cassandra: Avinash Lakshman y Prashant Malik desarrollaron Cassandra en Facebook para la función de búsqueda en la bandeja de entrada de Facebook. Facebook lanzó Cassandra en julio de 2008 como un proyecto de código abierto. Apache Software Foundation se encuentra actualmente detrás de la base de datos.

MongoDB se inició en 2007 por la empresa de software 10gen, que creó el producto basado en la palabra “humongous”. En 2009, fue lanzado, y 10gen más tarde cambió el nombre de su compañía a MongoDB, Inc. MongoDB, Inc. proporciona el desarrollo del software y vende su solución empresarial.

¿Qué base de datos es adecuada para mi aplicación?

Una de las mayores fortalezas de Cassandra es su capacidad de escalar sin dejar de ser confiable. Es posible implementar Cassandra en múltiples servidores integrados sin mucho trabajo adicional. Parte de esto se debe a que Cassandra maneja la replicación con una configuración mínima, lo que facilita la configuración.

Si necesita una base de datos que sea fácil de instalar y mantener, independientemente de cuánto crezca su base de datos, Cassandra puede ser una buena opción.

Si trabajas en una industria en la que necesitas un rápido crecimiento de tu base de datos, Cassandra ofrece un crecimiento más fácil y rápido que MongoDB.

MongoDB puede ser una gran opción si necesitas escalabilidad y almacenamiento en caché para análisis en tiempo real; sin embargo, no está diseñado para datos transaccionales.

MongoDB se usa con frecuencia para aplicaciones móviles, administración de contenido, análisis en tiempo real y aplicaciones relacionadas con el IoT (Internet de las cosas). Si tiene una situación en la que no tiene una definición de esquema clara, MongoDB puede ser una buena opción.

Si tienes una situación en la que estás des-normalizando el esquema de tu base de datos, los documentos MongoDB se pueden usar para almacenar los datos no estructurados de una manera que es más fácil de actualizar. En una situación donde la carga de escritura es alta, MongoDB puede ser una buena opción. Ofrece una alta tasa de inserción.

Y entonces ¿Con cuál de las base de datos utilizarías para tu proyecto?

Construyendo aplicaciones web con PHP, LUA y REDIS

php_redis

En un post anterior ya habíamos mencionado que es REDIS y que podríamos hacer con él.
Para el siguiente post, es necesario que ya tengan instalado REDIS y conocer algunos comandos básicos. Otro requisito para el presente ejemplo es conocer el lenguaje de programación LUA.

Conociendo LUA

lua

LUA es un lenguaje de programación imperativo, estructurado y muy veloz, se puede usar para desarrollar aplicaciones de todo tipo. LUA es muy conocido porque se usa en las distintas aplicaciones comerciales de Adobe Macromedia, en videojuegos como Warcraft,Angry birds, y ademas para controlar hardware.

Es considerado uno de los lenguajes de programación mas veloces del mundo, siendo por ello, muy utilizado para el desarrollo de videojuegos y en aplicaciones móviles en las distintas plataformas.

Fue creado en 1993 por Roberto Lerusalimschy, Luiz Henrique de Figueiredo y Waldemar Celes, miembros del Grupo de Tecnología en Computación Gráfica (Tecgraf) de la Pontificia Universidad Católica de Río de Janeiro, Brasil.

Robert_Ierusalimschy_at_the_Lua_Workshop_2013

LUA significa “Luna” en portugués, de ahí su logo.

Su ultima versión estable a la fecha es la 5.2.3, bajo licencia MIT.

LUA es portable, es pequeño y corre en todas las plataformas que tengan un compilador C standard, como UnixWindowsOS-X, y los distintos Sistemas Operativos para móviles.

LUA no es un lenguaje orientado a objetos puro, pero proporciona meta-mecanismos para la implementación de clases y herencia.

LUA es un lenguaje dinámico y es muy flexible en la forma en que se declaran las variables. Al igual que Ruby, no hace falta una declaración formal, simplemente escribes el nombre y le asignas un valor (no tienen tipo).

Los datos pueden ser lógicos, enteros, números de coma flotante o cadenas.

Las estructuras de datos como vectores, conjuntos, tablas hash, listas y registros pueden ser representadas utilizando la única estructura de datos de LUA: La tabla.

Su sintaxis se basa en Scheme,SNobol,ModulaCLU C++.

Puedes visitar la documentación de LUA.

Instalando modulo de REDIS para PHP

Descargarse la librería de REDIS para PHP del siguiente repositorio de Github.

https://github.com/gchacaltana/phpredis

o también puede clonar el repositorio con GIT.

$ git clone https://github.com/gchacaltana/phpredis.git

Una vez descargado, ingresamos al directorio principal de la librería y ejecutamos desde nuestro terminal.

$ sudo apt-get install php5-dev
$ sudo phpize
$ ./configure
$ sudo make && make install

En el mensaje de la instalacion se muestra la ruta del archivo redis.so que se creo.
Copia el archivo redis.so en la siguiente ruta.

$ sudo cp /path/redis.so /etc/php5/conf.d/

Luego debe editar el archivo de configuracion de PHP (php.ini), agregando la siguiente linea.

extension = redis.so

Y reinicias tu servidor web

Para linux:

$ sudo service apache2 restart

Para Nginx:

$ sudo service nginx restart

En la información del phpinfo, debe aparecer el modulo redis, como se aprecia en la siguiente imagen.

phpinfo_redis

Ejemplo: Usuarios en linea

Como ejemplo, vamos a utilizar REDIS para almacenar el nombre de usuario y la fecha de
su última conexión a nuestro Sistema, para mostrar cuantos usuarios están en línea, de
esta forma evitamos realizar repetidas consultas a nuestra base de datos (MySQL), ya que
REDIS es un motor de base de datos en memoria RAM.

Creando un Sorted Set en REDIS.

Iniciamos el servicio de redis en nuestro servidor.

$ sudo service redis_6379 start

Ingresamos a redis y creamos una lista ordenada llamada “usersonline”, donde almacenaremos la lista de usuarios que se conectan a nuestro sistema. La clave sera el timestamp de la fecha de ingreso y el valor a almacenar sera el login de usuario.

Ejemplo:

El usuario jaimito ingreso al Sistema el día 09-03-2014 a las 00:48:00.

El valor timestamp de 2014-03-09 00:48:00 es 1394326080.

$ redis-cli
Redis 127.0.0.1:6379> zadd usersonline 1394326080 jaimito.
Redis 127.0.0.1:6379> zadd usersonline 1394326089 pepito.
Redis 127.0.0.1:6379> zadd usersonline 1394326099 gchacaltana.

Script PHP para conectarnos a REDIS

/**
 * Connecting Redis Server
 */
function connectRedis()
{
    (string) $serverRedis = "127.0.0.1"; //localhost
    (int) $portRedis = "6379"; //default port
    try {
        if (!class_exists('Redis')) {
            throw new Exception("Redis Library not found.");
        }
        $connection = new Redis();
        $connection->connect($serverRedis, $portRedis);
    } catch (Exception $e) {
        throw new Exception("There was a problem connecting to redis server.");
    }
 
    //validate redis connection
    if (isset($connection->socket)) {
        return $connection;
    } else {
        throw new Exception("The redis server is turned off.");
    }
}

Script PHP para Insertar registros a REDIS

/**
 * Insert element Sorted Set Redis Server.
 * @param string $set, nombre de la lista ordenada en redis.
 * @param string $key, llave con que ordenaremos nuestra lista, 
 * en este caso sera el datetime de la fecha de ingreso del usuario.
 * @param string $value, será el nombre de usuario.
 */
function setSortedSetRedis($set, $key, $value)
{
    //conectamos a redis
    $redis = connectRedis();
 
    //El metodo zAdd agrega un elemento a una lista ordenada de Redis
    $redis->zadd($set, $key, $value);
 
    //cerramos la conexion a Redis.
    $redis->close();
    return true;
}

Script PHP para recuperar datos de REDIS.

/**
 * Get Records SortedSet redis server
 * @param string $set nombre del sorted set de redis.
 * @param string $order_by indica si el listado lo devuelve en forma
 * descendente o ascendente.
 */
function getElementsSortedSetRedis($set, $order_by = "desc")
{
    //conectado a Redis
    $redis = connectRedis();
    $records = array();
 
    if ($order_by == "desc") {
        //zRevRangeByScore: metodo que retorna los elementos de un
        //sorted set en forma descendente.
        $records = $redis->zRevRangeByScore($set, '+inf', '-inf');
    } else if ($order_by == "asc") {
        //zRangeByScore: metodo que retorna los elementos de un
        //lista en forma ascendente.
        $records = $redis->zRangeByScore($set, '-inf', '+inf');
    }
    //cerramos conexion a redis.
    $redis->close();
 
    //devolvemos listado
    return $records;
}

Script PHP para obtener cantidad de registros de una lista REDIS

/**
 * Get Count Set Order Redis Server
 * @param string $set, nombre de la lista ordenada en redis.
 * @return int cantidad total de registros de una lista.
 */
function getCountSortedSetRedis($set)
{
    //conectamos con redis
    $redis = connectRedis();
 
    //zCount: metodo que devuelve la cantidad de registros de una lista.
    (int) $value = $redis->zCount($set, '-inf', '+inf');
 
    //cerramos conexion
    $redis->close();
 
    //devolvemos el numero de registros de la lista.
    return $value;
}

Script LUA para eliminar elemento de una lista en REDIS.

--[[
LUA Script to delete items from list REDIS.
KEYS[1] = list name sent as a parameter.
KEYS[2] = datetime up to where you want to remove from the list.
--]]
local set = KEYS[1]
local maxValue = KEYS[2]
 
-- delete records sorted set redis.
local deleted = redis.call('zremrangebyscore',set,'-inf',maxValue)
-- return records deleted.
return deleted

Script PHP para ejecutar LUA en REDIS.

/**
 * Delete elements sorted set from LUA Script
 * @param string $set lista name REDIS.
 * @param int $maxValue datetime up to where you want to remove from the list.
 */
function delElementsSortedSetRedisFromLua($set, $maxValue)
{
    //indicamos la ruta del script .lua
    (string) $filename = "/path/script.lua";
    //verificamos si existe el archivo .lua
    if (!file_exists($filename)) {
        throw new Exception('file procedure script not found.');
    }
    //cargamos el contenido del script.lua en una variable php.
    $luaScript = file_get_contents($filename, FILE_USE_INCLUDE_PATH);
    //declaramos los parametros que recibira nuestro script.lua
    $params = array($set, $maxValue);
    //cantidad de parametros a enviar al script.lua
    (int) $paramCount = count($params);
    //abrimos conexion a redis
    $redis = connectRedis();
    //usamos el metodo eval de redis para ejecutar script.lua
    (int) $deleted = $redis->eval($luaScript, $params, $paramCount);
    //cerramos conexion a redis.
    $redis->close();
    //devolvemos el numero de elementos eliminados que devuelve script.lua
    return $deleted;
}

PHP + LUA + REDIS

Idea_images

Construir aplicaciones web usando REDIS + LUA te permite acelerar el tiempo de respuesta de las transacciones que puedas requerir en comparación con alguna base de datos relacional convencional, teniendo en cuenta para que tipo de soluciones necesitas almacenar información en memoria RAM.

REDIS de por sí es muy rápido y aplicando LUA como procedimiento almacenado, para ejecutar múltiples tareas, mejora la performance de REDIS y de la aplicación.