Post on 08-Nov-2014
description
Bases de datos NoSQLParte II: Apache Cassandra
Roberto Amor Marcos
Bases de Datos Avanzadas
20 de abril de 2012
ContenidosObjetivos
¿Por qué Cassandra?
Visión general
Modelo de Datos
Arquitectura
Características
CQL
Conexión y acceso desde lenguajes de alto nivel
Aplicación de ejemplo sobre Cassandra
Objetivos
Conocer en profundidad Apache Cassandra.
Conocer y entender la terminología propia de Cassandra.
Conocer las distintas formas de acceder al contenido de la Base de Datos.
Conocer el lenguaje de consulta CQL.
Conocer cuáles son las formas de estructurar la información en Cassandra.
¿Por qué Cassandra?
Es un sistema fácil de entender pues es del tipo de Base de Datos NoSQL más cercano al modelo relacional.
Es de los pocos que ha superado la fase de versiones desarrollo 0.x y es actualizado, corregido y mejorado cada poco tiempo.
Última versión 1.0.9 del 6 de abril de 2012.
Dispone de un lenguaje de consultas muy similar a SQL: CQL (Cassandra Query Language).
Está escrito en Java.
La Fundación Apache está detrás de su desarrollo y mantenimiento.
¿Por qué Cassandra?
Es utilizado en aplicaciones comerciales muy importantes.
Twitter, Netflix, Digg, Cisco Webex, Spotify. Se usó en Facebook.
Su popularidad está en aumento y cada vez es más utilizado.
Existen distribuciones compiladas para todos los sistemas operativos, ofreciendo además, paneles de administración amigables.
Dispone de partners que dan soporte comercial de calidad.
Gran comunidad.
Visión general
Sistema key-value store que almacena column families.
Creado por Avanash Lakshaman y Prashany Malik para ser integrado en el motor de búsqueda de Facebook.
Concretamente para buscar mensajes en la bandeja de entrada.
Influido por Google BigTable (modelo de datos) y Amazon Dynamo (estructura).
Proceso de liberación:
Julio 2008: publicado como proyecto open source en Google Code.
Marzo 2009: pasa a formar parte de los proyectos Apache Incubator.
Febrero 2010: se convierte en proyecto top-level de la Apache Software Foundation.
Es actualmente el modelo de más éxito y el más utilizado. Actualmente sigue creciendo en número de usuarios.
En el momento de su presentación era capaz de ofrecer servicio concurrente a 100 millones de usuarios.
Especialmente diseñado para ejecutarse sobre grandes clusters, siendo muy sencilla su instalación multimáquina.
http://www.screenr.com/5G6 : how to set up a 4 node Cassandra cluster in under 2 minutes.
Visión general
Conceptos básicos:
Cluster: las máquinas (nodos) de una instancia de Cassandra. Los clusters pueden contener múltiples keyspaces.
Keyspace: es la agrupación de ColumnFamilies. Normalmente hay un keyspace por aplicación.
ColumnFamilies: contenedor de múltiples columns. Es equivalente a la tabla en el modelo relacional. Cada entrada (row) se identifica y accede a ella mediante un row-KEY.
Column: unidad básica de almacenamiento. Consistente en una estructura de tres valores: name, value y timestamp.
SuperColumns: se consideran columns que almacenan subcolumnas. Son opcionales y no son muy utilizadas.
Modelo de Datos
De la columna al cluster
Columns
struct Column {1: binary name,2: binary value,3: i64 timestamp
}
Unidad básica de almacenamiento. Es una tripla.
{“name”: “Username”,“value”: “john23”,“timestamp”: 123456789
}
Modelo de Datos
De la columna al cluster
Columns
Los tres valores anteriores son proporcionados por el cliente de alto nivel, incluido el timestamp.
Por ello, es necesario tener sincronizado el reloj del sistema con el reloj del cluster.
El timestamp es utilizado para la resolución de conflictos (Eventual Consistency).
El timestamp puede ser cualquier cosa pero la convención marca que sea el valor en microsegundos desde 1970.
El tamaño máximo que puede albergar una columna es 2GB.
Modelo de Datos
De la columna al cluster
Rows
Agregacio!n de columnas con un nombre para referenciarlo (row-KEY).
El row sería el equivalente a la fila del modelo relacional y el row KEY el equivalente a la clave primaria del modelo relacional.
Es usado para ordenar los ficheros de forma física.
Se pueden almacenar hasta 2 mil millones de columnas en cada row.
Modelo de Datos
De la columna al cluster
Column Family
Agregacio!n rows.Cada ColumnFamily es guardado en un fichero separado y es ordenado por la KEY.
La forma de ordenar tanto de los rows como de las columnas se puede editar desde los ficheros de configuración.
ASCIIUTF-8LongUUID (léxico o de tiempo)FechaCombinaciones de ellos mediante el patrón CompositeType
Modelo de Datos
De la columna al cluster
Column Family
Modelo de Datos
De la columna al cluster
Keyspace
Es equiparable al schema del modelo relacional.
Cluster
Abarca desde el modelo físico al modelo lógico.
Incluso existe la posibilidad de interconectar clusters separados física y lógicamente.
Toda la información de un row debe encontrarse en una misma máquina o nodo del cluster.
Las IPs de los nodos se añaden en un fichero de configuración alojado en cada nodo. Todo lo demás es transparente para el usuario.
Modelo de Datos
El modelo estructural de un solo vistazo
Modelo de Datos
Cassandra reúne la tecnología de sistemas distribuidos de Dynamo y el modelo de datos de BigTable.
De Dynamo: Eventualmente Consistente. Sistema de nodos en anillo.
De BigTable: modelo de datos basado en Familias de Columnas.
Cassandra implementa la ‘parte AP’ del modelo CAP (i.e. Availability y Partitioning tolerance).
Arquitectura
Capas de la arquitectura de Cassandra:
Arquitectura
Core Layer Middle Layer Top Layer
Messaging serviceGossip Failure dectectionCluster statePartitionerReplication
Commit logMemtableSSTableIndexesCompaction
TombstonesHintedHandoffRead repairBootstrapMonitoringAdmin tools
Escritura
2 modos de escritura:
Quorum write: bloqueo hasta que la escritura tenga efecto.
Async write: se envía la petición a cualquier nodo. El nodo se encarga de hacer llegar los datos hasta el nodo apropiado.
Si un nodo está caído, otro nodo lo sustituirá hasta que el nodo original vuelva a estar disponible, escribiendo después en él. Por defecto cada 15 minutos se mueven datos entre nodos.
Arquitectura
Escritura
Camino de datos
Arquitectura
write DiskCommit
Log
nodes
memtables
t
when:out of space
too many keys
on disk: {dataFile (SSTable), indexFile (SSTable Index)}
Escritura
Propiedades de la escritura:
No hay lecturas.
No hay búsquedas.
Rápida.
Atómica respecto a las ColumnFamilies.
Siempre se puede escribir (disponibilidad de nodos).
Arquitectura
Lectura
Camino de datos:
1. Cualquier nodo puede responder (resolución de conflictos si fuera necesario con consistencia eventual).
2. El Partitioner actúa sobre cómo devolver los datos.
3. Espera de los datos desde memtable o desde SSTable.
Arquitectura
Lectura
Propiedades de la lectura:
Posibilidad de lecturas en paralelo de múltiples SSTable.
Mucho más lento que la escritura.
El retardo en las búsquedas se puede mitigar con más RAM.
Lecturas escalables hasta miles de millones de rows."
Arquitectura
Borrado
Se hace mediante una marca de borrado (tombstone) en el memtable.
Durante la fase de escritura del memtable al disco se descartan las entradas marcadas con el tombstone.
Arquitectura
VS MySQL con 50GB de datos
MySQL
~300ms write
~350ms read
Arquitectura
Cassandra
~0.12ms write
~15ms read
Búsquedas sobre +50TB de datos en cluster de 150 nodos.
Keyspace consistente en dos ColumnFamilies.
Query A: buscar mensajes por término de búsqueda.
Min: 7.78ms
Median: 18.27ms
Max: 44.41ms
Arquitectura
Búsquedas sobre +50TB de datos en cluster de 150 nodos.
Keyspace consistente en dos ColumnFamilies.
Query B: interacción de mensajería privada. Dado el nombre de un usuario, devolver todos los mensajes mantenidos con ese usuario.
Min: 7.69ms
Median: 15.69ms
Max: 26.13ms
Arquitectura
Tolerante a fallos:
Datos replicados automáticamente entre nodos.
Replicación a través de múltiples centros de datos.
Nodos automáticamente reemplazados.
Descentralizado: cada nodo es idéntico a los demás en estructura. No hay cuellos de botella.
Eventualmente consistente
Alta disponibilidad
Altamente escalable
Con soporte profesional
Probado
Características
Desde la versión 0.8, Cassandra proporciona un lenguaje de consulta y manipulación de los datos similar a SQL.
Actualmente (marzo 2012) se encuentra en su versión 2.0.
Se puede actuar con él tanto desde prompt como desde clientes de alto nivel.
CQL
SELECT * FROM MyColumnFamily;
UPDATE MyColumnFamily SET 'SomeColumn' = 'SomeValue' WHERE KEY = B70DE1D0-9908-4AE3-BE34-5573E5B09F14;
CQL
Tipo de dato Descripciónascii string de caracteres en US-ASCII
bigint long de 64-bits con signo
blob tipo LOB hexadecimal
boolean frue o false
counter contador distribuido de 64-bits
decimal número decimal de precisión variable
double número en punto flotante de 64-bits. sigue la norma IEEE-754
float número en punto flotante de 32-bits. sigue la norma IEEE-754
int entero con signo de 32-bits
text string en UTF-8
timestamp marca de tiempo de 8 bytes
uuid UUID del tipo 1 o tipo 4
varchar string en UTF-8
variant entero de precisión arbitraria
Tipos de datos en CQL
CQLEl tipo de dato UUID
Identificador Universalmente Único (Universally Unique Identifier).
Identificador estándar universal usado en computación distribuida.
Definido en el RFC-4122
Consiste en número hexadecimal de 16bytes (128-bits) dividido en grupos de la forma 8-4-4-4-12
550e8400-e29b-41d4-a716-446655440000
Hay 3 x 1038 identificadores posibles: 340,282,366,920,938,463,463,374,607,431,768,211,456
CQLEl tipo de dato UUID
Existen 5 tipos o versiones:
Version 1 MAC address
Version 2 DCE Security
Version 3 MD5 hash
Version 4 Random
Version 5 SHA-1 hash
CQLEl tipo de dato UUID
¿Probabilidad de repetición?
Con n = 2122 (122 random bits)
n probabilidad
68,719,476,736 = 236 0.0000000000000004 (4 × 10−16)
2,199,023,255,552 = 241 0.0000000000004 (4 × 10−13)
70,368,744,177,664 = 246 0.0000000004 (4 × 10−10)
CQLInstrucciones soportadas (en orden alfabético)ALTER COLUMNFAMILYBATCHCREATE COLUMNFAMILYCREATE INDEXCREATE KEYSPACEDELETEDROP COLUMNFAMILYDROP INDEXDROP KEYSPACEINSERTSELECTTRUNCATEUPDATEUSE
CQLALTER COLUMNFAMILY
ALTER COLUMNFAMILY <name> ALTER <column_name> TYPE <data_type> | ADD <column_name> <data_type> | DROP <column_name> ;
ALTER COLUMNFAMILY users ALTER email TYPE varchar;
ALTER COLUMNFAMILY users ADD gender varchar;
ALTER COLUMNFAMILY users DROP gender;
Manipular la metainformación de columna en una familia de columnas.
CQLBATCH
BEGIN BATCH
[ USING <write_option> [ AND <write_option> [...] ] ];
<dml_statement> <dml_statement> [...]
APPLY BATCH;
where <write_option> is:
USING CONSISTENCY <consistency_level> TTL <seconds> TIMESTAMP <integer>
Crea un bloque en el que las instrucciones contenidas en él se insertan el la BD con el mismo valor de timestamp.
CQLBATCH
Crea un bloque en el que las instrucciones contenidas en él se insertan el la BD con el mismo valor de timestamp.
BEGIN BATCH USING CONSISTENCY QUORUM AND TTL 8640000 INSERT INTO users (KEY, password, name) VALUES ('user2', 'ch@ngem3b', 'second user') UPDATE users SET password = 'ps22dhds' WHERE KEY = 'user2' INSERT INTO users (KEY, password) VALUES ('user3', 'ch@ngem3c') DELETE name FROM users WHERE key = 'user2' INSERT INTO users (KEY, password, name) VALUES ('user4', 'ch@ngem3c', 'Andrew')APPLY BATCH;
CQLCREATE COLUMNFAMILY
CREATE COLUMNFAMILY <cf_name> ( <key_column_name> <data_type> PRIMARY KEY [, <column_name> <data_type> [, ...] ] ) [ WITH <storage_parameter> = <value> [AND <storage_parameter> = <value> [...] ] ];
CREATE COLUMNFAMILY user_events (user text PRIMARY KEY) WITH comparator=timestamp AND default_validation=int;
CREATE COLUMNFAMILY users ( KEY uuid PRIMARY KEY, username text, email text ) WITH comment='user information' AND read_repair_chance = 1.0;
Crea una nueva Familia de Columnas
CQLCREATE INDEX
CREATE INDEX [<index_name>] ON <cf_name> (<column_name>);
CREATE COLUMNFAMILY users ( KEY uuid PRIMARY KEY, firstname text, lastname text, email text, address text, zip int, state text);
CREATE INDEX user_state ON users (state);
CREATE INDEX ON users (zip);
Crea un nuevo índice secundario
CQLCREATE KEYSPACE
CREATE KEYSPACE <ks_name> WITH strategy_class = <value> [ AND strategy_options:<option> = <value> [...] ];
CREATE KEYSPACE MyKeyspace WITH strategy_class = 'SimpleStrategy' AND strategy_options:replication_factor = 1;
Crea un nuevo Keyspace
CQLDELETE
DELETE [<column_name> [, ...]] FROM <column_family>[USING CONSISTENCY <consistency_level> [AND TIMESTAMP <integer>]]WHERE <row_specification>;
where <row_specification> is:
KEY | <key_alias> = <key_value> KEY | <key_alias> IN (<key_value> [,...])
DELETE email, phone FROM users USING CONSISTENCY QUORUM AND TIMESTAMP 1318452291034 WHERE user_name = 'jsmith';
DELETE FROM users WHERE KEY IN ('dhutchinson', 'jsmith');
Borra una o varias columnas de un row o rows
CQLDROP COLUMNFAMILY
DROP COLUMNFAMILY <name>;
DROP COLUMNFAMILY users;
Elimina una Familia de Columnas
CQLDROP INDEX
DROP INDEX <index_name>;
DROP INDEX users;DROP INDEX users_zip_idx;
Elimina un índice secundario
Si el índice se creó sin nombre, sigue el siguiente patrón:
<column_family_name><column_name>_idx
CQLDROP KEYSPACE
DROP KEYSPACE <name>;
DROP KEYSPACE demo;
Elimina un Keyspace
CQLINSERT
INSERT INTO <column_family> (<key_name>, <column_name> [, ...]) VALUES (<key_value>, <column_value> [, ...]) [USING <write_option> [AND <write_option> [...] ] ];
where <write_option> is:
USING CONSISTENCY <consistency_level> TTL <seconds> TIMESTAMP <integer>
INSERT INTO users (KEY, user_name) VALUES ('cfd66ccc-d857-4e90-b1e5-df98a3d40cd6', 'jbellis') USING CONSISTENCY LOCAL_QUORUM AND TTL 86400;
Inserta o actualiza una o varias columnas identificadas por su KEY y su Familia de Columnas
CQLSELECT
SELECT <column_specification> FROM [<keyspace>.]<column_family>[USING CONSISTENCY <consistency_level>][WHERE <row_specification> [AND <row_specification> [...]][LIMIT <integer>]
where <column_specification> is:
<column_name> [, ...] | [FIRST <integer>] [REVERSED] { <start_of_range> .. <end_of_range> | * } | COUNT(*)
and where <row_specification> is:
KEY | <key_alias> { = | < | > | <= | >= } <key_value> KEY | <key_alias> IN (<key_value> [,...])
Devuelve las rows y columnas de la Familia de Columnas solicitada
CQLSELECT
SELECT name, title FROM employees WHERE KEY IN (199, 200, 207);
SELECT FIRST 3 REVERSED 'time199'..'time100' FROM events;
SELECT COUNT(*) FROM users;
Devuelve las rows y columnas de la Familia de Columnas solicitada
A diferencia que en el SELECT de SQL, en CQL no se garantiza que las columnas solicitadas existan y no dará error si esto ocurre. Simplemente se devolverá el conjunto vacío de resultados.
CQLTRUNCATE
TRUNCATE <column_family>;
TRUNCATE user_emails;
Elimina todos los datos de una Familia de Columnas
CQLUPDATE
UPDATE <column_family> [ USING <write_option> [ AND <write_option> [...] ] ]; SET <column_name> = <column_value> [, ...] | <counter_column_name> = <counter_column_name> {+ | -} <integer> WHERE <row_specification>;
where <write_option> is:
USING CONSISTENCY <consistency_level> TTL <seconds> TIMESTAMP <integer>
and where <row_specification> is:
KEY | <key_alias> = <key_value> KEY | <key_alias> IN (<key_value> [,...])
Actualiza una o varias columnas del row y la Familia de Columnas especificados
CQLUPDATE
UPDATE users USING CONSISTENCY QUORUM SET 'state' = 'TX' WHERE KEY IN (88b8fd18-b1ed-4e96-bf79-4280797cba80, 06a8913c-c0d6-477c-937d-6c1b69a95d43, bc108776-7cb5-477f-917d-869c12dfffa8);
UPDATE users USING CONSISTENCY QUORUM SET 'name' = 'John Smith', 'email' = 'foo@bar.com' WHERE user_uuid = 88b8fd18-b1ed-4e96-bf79-4280797cba80;
UPDATE page_views USING CONSISTENCY QUORUM AND TIMESTAMP=1318452291034 SET 'index.html' = 'index.html' + 1 WHERE KEY = 'www.cosasquecontar.com';
Actualiza una o varias columnas del row y la Familia de Columnas especificados
CQLUSE
USE <keyspace_name>;
USE demo;
Conecta la sesión actual con el Keyspace especificado
Conexión y acceso desde lenguajes de alto nivel
Se ofrecen dos formas de acceder al cluster de Cassandra.
Mediante el terminal usando la línea de comandos prompt.
Mediante lenguajes de alto nivel mediante librerías CLI.
Conexión y acceso desde lenguajes de alto nivel
Acceso desde el prompt
cassandra-cli. >./bin/cassandra-cli
cqlsh. >./bin/cassandra-cliIntérprete de CQL. Precisa de Python para funcionar.
Conexión y acceso desde lenguajes de alto nivel
Lenguajes de alto nivel soportados:
Python
Java (Incluido Driver)
Scala
Node.js (Incluido Driver)
Clojure
.NET
Ruby (Incluido Driver)
PHP (Incluido PDO Driver)
Perl
C++
Haskel
La mayor parte son Frameworks de terceros.
Aplicación de ejemplo sobre Cassandra
Modelo a desarrollar
Aplicación de ejemplo sobre Cassandra
KEYSPACE ejemplo;
Estructura de BD Cassandra
Se crea el Keyspace que contendrá la aplicación
Aplicación de ejemplo sobre Cassandra
Estructura de BD Cassandra
ColumnFamily Usuario;ColumnFamily Tweet;
Por cada clase del modelo UML se crea una Familia de Columas
Por norma general, cada relación que genere una lista de objetos (i.e. relaciones 0..n, 1..n, n..m) se crea una Familia de Columnas donde se
alojarán referencias a cada objeto de la lista. Será indexado por la KEY del objeto principal.
ColumnFamily Following;ColumnFamily Followers;ColumnFamily UserTweets;
Aplicación de ejemplo sobre Cassandra
Estructura de BD Cassandra
ColumnFamily Usuario;ColumnFamily Tweet;
Por cada clase del modelo UML se crea una Familia de Columas
Cuando una clase UML tiene como destino claro realizar búsquedas (por ejemplo, una clase PalabrasClave donde no hay más de un atributo)
no hace falta crear una segunda familia de columnas.
ColumnFamily Following;ColumnFamily Followers;ColumnFamily UserTweets;
Aplicación de ejemplo sobre Cassandra
Estructura de BD Cassandra
La creación de índices secundarios no es recomendable salvo que sea estrictamente necesario para realizar búsquedas.
Las KEY no hay que definirlas.
Aplicación de ejemplo sobre Cassandra
Estructura de BD Cassandra
Usuario = { 'roviyo': { 'password': '12345', 'email': 'roviyo@hotmail.com' }, 'pleys : { 'password': 'abc123', 'email': 'pleys@gmail.com' }, ...}
ColumnFamily Usuario;
Aplicación de ejemplo sobre Cassandra
Estructura de BD Cassandra
Tweet = { '7561a442-24e2-11df-8924-001ff3591711': { 'owner': 'roviyo', 'body': 'hola mundo, esto es un tweet', },}
ColumnFamily Tweet;
Aplicación de ejemplo sobre Cassandra
Estructura de BD CassandraFollowing = { 'roviyo': { # follow KEY: timestamp en que fue añadida a la lista 'pleys': '1267413962580791', 'joan': '1267413990076949', 'bob23' : '1267414008133277', ... }, ...}
Followers = { 'roviyo': { # follow KEY: timestamp en que fue añadida a la lista 'larry': '1267413962580791', 'curly': '1267413990076949' }, ...}
UserTweets = { 'roviyo': { # tweet KEY: timestamp en que fue añadido a la lista '7561a442-24e2-11df-8924-001ff3591711': '1267413962580791', '7561a442-24e2-11df-8924-001ff3110091': '1267413990076949' }, ...}
http://www.datastax.com/cassandrausers - Cassandra Users, Datastax
http://www.nosqldatabases.com/main/tag/avinash-lakshman - The Origins of Cassandra
http://www.datastax.com/docs/1.0/references/cql/index - CQL Language Reference
http://www.ietf.org/rfc/rfc4122.txt - RFC-4122: A Universally Unique IDentifier (UUID)
Bibliografía y Referencias
Realizar el diagrama UML y el diseño del schema Cassandra en JSON del siguiente problema.
Se precisa de un pequeño blog de noticias.
El blog puede contener a varios autores.
Cada autor tiene un nombre, un nombre de usuario, una cuenta de twitter y una descripción.
Las noticias tienen un título, un cuerpo y una fecha de publicación.
Son publicadas por un autor.
Pueden contener o no, una lista de tags.
Los visitantes del blog pueden comentar las noticias. Cada comentario contiene un nombre (escrito por el visitante al enviar el comentario) y un cuerpo.
Ejercicio