Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ANTONIO SARASA
INTRODUCCIÓN
NoSQL
A LAS BASES DE DATOS
REDIS
CLAVE-VALOR USANDO
https://dogramcode.com/bases-de-datos
Dogram Code
https://dogramcode.com/bases-de-datos
Introducción a las bases de
datos NoSQL clave-valor
usando Redis
Antonio Sarasa
https://dogramcode.com/bases-de-datos
Director de la colección Manuales (Tecnología): Toni Pérez
ISBN: 978-84-9180-485-7
Ninguna parte de esta publicación, incluyendo el diseño general y de la cubierta, puede ser copiada, reproducida,
almacenada o transmitida de ninguna forma ni por ningún medio, ya sea eléctrico, químico, mecánico, óptico, de
grabación, de fotocopia o por otros métodos, sin la autorización previa por escrito de los titulares del copyright.
https://dogramcode.com/bases-de-datos
Autor
Antonio Sarasa
Es licenciado en Ciencias Matemáticas, especialidad en Ciencias de la
Computación, por la Facultad de Matemáticas de la Universidad Complutense
de Madrid. Posteriormente estudió las ingenierías técnicas de Informática de
Gestión e Informática de Sistemas en la Universidad Nacional de Educación
a Distancia (UNED). También obtuvo el graduado en Ingeniería Informática
por la Universitat Oberta de Catalunya (UOC). Es doctor en Informática por la
Universidad Complutense de Madrid (UCM).
Actualmente es profesor contratado doctor en el Departamento de Sistemas
Informáticos y Computación de la Facultad de Informática de la UCM.
Asimismo, ha sido profesor tutor de asignaturas de las carreras de Informática
en varios centros asociados de la UNED, y es consultor de la asignatura Bases de
Datos NoSQL del máster de Business Intelligence de la UOC.
Sus áreas de investigación se centran en la aplicación de las técnicas de proce-
sadores de lenguajes y compiladores al desarrollo de aplicaciones. Asimismo,
ha trabajado en temas de patrimonio digital y e-learning, entre los que destaca su
participación en el proyecto estatal de la red de repositorios de material educativo
digital Agrega. Ha realizado más de cincuenta publicaciones en congresos, revis-
tas nacionales e internacionales.
Es miembro de varios comités de estandarización de AENOR.
https://dogramcode.com/bases-de-datos
https://dogramcode.com/bases-de-datos
Este libro está dedicado a mis hijos.
https://dogramcode.com/bases-de-datos
https://dogramcode.com/bases-de-datos
© Editorial UOC Índice
Índice
Prólogo ............................................................................................ 13
Antonio Sarasa
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
3. Listas....................................................................................... 63
4. Hash ........................................................................................ 67
5. Conjuntos .............................................................................. 70
6. Conjuntos ordenados .......................................................... 74
7. HyperLogLog........................................................................ 80
Bibliografía.................................................................................. 83
10
https://dogramcode.com/bases-de-datos
© Editorial UOC Índice
Conclusión...................................................................................... 147
11
https://dogramcode.com/bases-de-datos
https://dogramcode.com/bases-de-datos
© Editorial UOC Prólogo
Prólogo
13
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
Antonio Sarasa
14
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
Capítulo I
Introducción a las bases de datos NoSQL
orientadas hacia agregados
1. Introducción
15
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
16
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
17
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
18
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
19
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
20
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
21
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
22
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
23
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
24
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
25
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
26
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
27
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
28
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
29
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
30
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
31
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
32
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…
33
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
34
© Editorial UOC Capítulo I. Introducción a las bases…
35
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
ten un conjunto determinado de tipos de datos, por lo que para
almacenar otros, habrá que adaptarlos o transformarlos.
A nivel de concurrencia y consistencia de los datos, solo se
garantiza la atomicidad de las operaciones a nivel de agregado.
Por tanto para garantizar la atomicidad entre varios agregados es
necesario realizarlo directamente desde el código.
Por último, cabe mencionar que este tipo de bases de datos
están relacionadas con las bases de datos de tipo clave-valor,
dado que una base de datos documental puede llegar a compor-
tarse como una base de datos de este otro tipo. Una de las prin-
cipales diferencias entre unas y otras es la opacidad del agregado.
En el caso documental, se puede acceder al contenido de la agre-
gado, sin embargo en el caso clave-valor, el agregado permanece
oculto.
6. Bases de datos NoSQL de tipo clave-valor
Se trata de un tipo de base de datos orientada hacia agregados
cuya principal característica es que el agregado que gestiona puede
ser de cualquier tipo, pero las únicas operaciones de manipulación
permitidas son el almacenamiento y recuperación de este.
En este sentido, no es posible consultar el contenido almace-
nado en el agregado desde el interior de la base de datos (no se
pueden construir consultas en base a la estructura de la informa-
ción), de manera que para acceder al contenido hay que hacerlo
desde fuera.
Por otro lado, el almacenamiento de la información se realiza
utilizando un mecanismo de tipo clave-valor semejante a algunas
estructuras de datos presentes en los lenguajes de programación
36
© Editorial UOC Capítulo I. Introducción a las bases…
tales como diccionarios o tablas hash. Así, a cada agregado que se
quiere insertar en la base de datos, se le asocia una clave que
sirve para poder recuperarlo posteriormente. En este sentido,
cualquier operación de búsqueda y recuperación se basa exclusi-
vamente en la clave que tiene asociado cada agregado, y lo que se
recupera son agregados completos.1
Las bases de datos documentales pueden comportarse como
bases de datos de tipo clave-valor, puesto que se pueden crear
consultas para recuperar un documento utilizando únicamente
el identificador de este como si fuera una clave y sin utilizar res-
tricciones basadas en los contenidos almacenados. Sin embargo,
estos modelos difieren en la forma de gestionar los agregados.
En las bases de datos de tipo clave-valor, el contenido del agre-
gado es opaco e inaccesible, lo que impide construir consultas
usando los contenidos de los agregados (no se pueden establecer
condiciones de recuperación en base al contenido o estructura
del agregado). En cambio en las bases de datos documentales se
puede acceder al contenido y estructura del agregado, y por tanto
se pueden construir consultas en forma de restricciones sobre los
contenidos de estos.
Conviene observar que la opacidad del agregado hace que
no sea necesario realizar transformaciones de la información
ni para almacenarlo ni para recuperarlo, lo que facilita por una
parte la distribución de los agregados en un clúster y, por otra
1 Esto no sucede en todas las bases de datos orientadas hacia agregados, así, por
ejemplo, en las bases de datos documentales, las consultas se construyen utilizan-
do los campos de información y el contenido de los agregados, y se recuperan
como resultado partes de un agregado.
37
© Editorial UOC Introducción a las bases de datos NoSQL
parte, hace no se presente el problema de la impedancia en este
modelo.2
Por último, hay que mencionar que dentro de las bases de
datos de tipo clave-valor se pueden encontrar casos particulares
tales como aquellas que ofrecen soporte para realizar consultas
sobre los agregados usando herramientas externas de búsqueda
u otras que permiten reestructurar los datos que se almacenan en
el agregado aunque este sea opaco.
7. Bases de datos NoSQL orientadas a columnas
38
© Editorial UOC Capítulo I. Introducción a las bases…
la unidad de acceso, partiendo del hecho de que a los datos para
una familia de columnas particular se accederá normalmente de
manera conjunta.
Observemos que este modelo puede entenderse como una
estructura agregada a dos niveles donde la primera clave es un
identificador de fila que permite acceder a un agregado de segun-
do nivel, que es lo que se denominan columnas. El acceso a la fila
es completo, pero existen operaciones que permiten seleccionar
una columna particular.
39
© Editorial UOC Introducción a las bases de datos NoSQL
Bibliografía
Mohamed, M. A.; Altrafi, O. G.; Ismail, M. O. (2014). «Relational
vs. NoSQL Databases: A Survey». International Journal of Computer and
Information Technology (vol. 3, págs. 598-601).
Moniruzzaman, A. B. M.; Hossain, S. A. (2013). «NoSQL Database:
New Era of Databases for Big Data Analytics-Classification,
Characteristics and Comparison» [artículo en línea]. ArXiv.org http://
cort.as/-F2Pl.
Pramod, J. S.; Fowler, M. (2012). NoSQL Distilled: A Brief Guide to the
Emerging World of Polyglot Persistence. Addison-Wesley Professional.
Redmond, E.; Wilson, J. R. (2012). Seven databases in seven weeks: a guide to
modern databases and the NoSQL movement. Pragmatic Bookshelf.
Tiwari, S. (2011). Professional NoSQL. John Wiley & Sons.
Vaish, G. (2013). Getting started with NoSQL. Packt Publishing Ltd.
40
© Editorial UOC Capítulo II. Introducción a Redis
Capítulo II
Introducción a Redis.
Una base de datos NoSQL de tipo clave-valor
1. Introducción
Tal como se ha comentado en el capítulo anterior, el modelo
de datos de tipo clave-valor se clasifica dentro de los modelos
orientados hacia agregados. En particular, en este modelo,
los agregados son estructuras de información opacas dado que
sus datos no son accesibles desde la base de datos, únicamente
se pueden almacenar o recuperar como una unidad, utilizando
una clave asociada a estos. Así, para poder acceder a los con-
tenidos, hay que hacerlo fuera de la base de datos. Entre sus
ventajas, se encuentra el hecho de que no sea necesario realizar
transformaciones de la información para almacenar o para recu-
perar el agregado, y, como inconvenientes, el hecho de no poder
recuperar trozos concretos de un agregado. Asimismo, no es
posible establecer consultas en base al contenido del agregado
propiamente dicho.
Redis (Remote Dictionary Server) es una base de datos
NoSQL de tipo clave-valor creada en el año 2006 por Salvatore
Sanfilippo. Ha sido utilizada por grandes compañías como
Twitter, GitHub, Tumblr, Pinterest, Instagram, Hulu, Flickr, o
The New York Times.
En este capítulo se realiza una introducción a los conceptos
básicos y la terminología fundamental necesaria para poder enten-
der qué es una base de datos en Redis y qué elementos la forman.
41
© Editorial UOC Introducción a las bases de datos NoSQL
2. Principales características
• Redis es una base de datos que almacena toda la información
en la memoria pero con persistencia en el disco, lo cual le
facilita una alta velocidad de escritura y lectura (la mayoría de
las veces se ejecutan en milisegundos). Sin embargo, esta con-
figuración impone una limitación en cuanto a los conjuntos
de datos que puede almacenar, puesto que no pueden ser más
grandes que la memoria. Para gestionar la memoria se utiliza
la memoria virtual que mantiene todas las claves pero solo
escribe los valores menos usados recientemente en el disco. La
persistencia en el disco se puede realizar de dos formas, bien
realizando una copia de los datos en un archivo binario (snap-
shotting) o bien en un archivo de solo anexos (AOF, append-only
file) que contiene todos los comandos ejecutados o cambios
realizados sobre los datos (journaling).
• Otra ventaja de almacenar toda la información en memoria
es que la representación en memoria de estructuras de datos
complejas es mucho más sencilla de manipular en compara-
ción con la misma estructura de datos en el disco.
• En Redis se utiliza una arquitectura maestro-esclavo para la
implementación de un clúster, y se realiza una réplica asíncro-
na de los datos. En este sentido, todos los datos del maestro
42
© Editorial UOC Capítulo II. Introducción a Redis
se copian de forma asíncrona en los nodos esclavos del clús-
ter, de modo que si el nodo maestro fallara, entonces uno
de los nodos esclavos puede ser promovido a nodo maestro.
Además, se consigue una lectura eficiente dado que se puede
repartir entre los nodos esclavos. Conviene observar que la
réplica de los datos se puede hacer sobre cualquier número de
nodos esclavos del clúster.
• Tal como se ha comentado, Redis utiliza una arquitectura
maestro-esclavo, de manera que las actualizaciones se realizan
sobre el nodo maestro del clúster (y se expanden al resto de
nodos de forma asíncrona) y los nodos esclavos se utilizan
solo en modo lectura. Así, puede ocurrir que el nodo maestro
existan nuevos elementos escritos, pero al leer de un nodo
esclavo se estén leyendo valores obsoletos dado que no se
han actualizado aún. En este sentido, el retraso al realizar la
actualización produce una inconsistencia momentánea. Por
esta razón se dice que Redis ofrece una consistencia de tipo
eventual.
• Las operaciones en Redis son atómicas, lo cual asegura que
si hay dos clientes accediendo concurrentemente, el servidor
recibirá el valor actualizado.
• Con el objetivo de conseguir un equilibrio en la carga de traba-
jo, se usa el nodo maestro para escribir los datos y se usan los
esclavos para leer los datos. Asimismo, las solicitudes de lectura
se distribuyen de forma uniforme entre los nodos esclavos.
• Se creó como un proyecto de código abierto con licencia
BSD. Está implementada utilizando C optimizado y permite
ser gestionada por una gran variedad de lenguajes de progra-
mación.
• Permite el almacenamiento en memoria de casi cualquier tipo
de datos con el objetivo de facilitar el uso de las estructuras de
43
© Editorial UOC Introducción a las bases de datos NoSQL
datos más adecuadas para almacenar cada tipo de contenidos,
en vez de obligar a usar una única estructura de datos que no
tiene porqué ser la mejor para todos los casos.
En este sentido, admite una gran variedad de tipos de
datos comparado con otras bases de datos de tipo clave-valor
tales como cadenas, listas, conjuntos sin ordenar, conjuntos
ordenados o HyperLogLogs. Además muchos de los tipos de
datos utilizados son equivalentes a los utilizados en los lengua-
jes de programación lo que facilita el mapeo de los contenidos
entre los programas y la base de datos.
• Dispone de herramientas del tipo Publicador/Suscriptor para
publicar mensajes en canales que se entregan a suscriptores
(esta característica viene bien para implementar sistemas de
chat y mensajería), claves de tipo TTL en las que se puede
configurar un tiempo de vida determinado tras el que se eli-
minan a sí mismas (esta característica resulta especialmente
útil para mantener limpias las bases de datos), un sistema de
transacciones y contadores, contadores atómicos que garan-
tizan que las condiciones de la carrera no creen resultados
incoherentes. Asimismo, se dispone de un lenguaje de scripts
denominado Lua que permite la creación de nuevas funciones
y operaciones sobre Redis.
• Redis ha sido aplicado en diversos ámbitos tales como la crea-
ción de cachés de alto rendimiento para una base de datos,
administración de sesiones de aplicaciones web usando claves
TTL, creación de clasificaciones dinámicas usando conjuntos
ordenados, implementación de colas, listas circulares o la acti-
vación de eventos publicados.
44
© Editorial UOC Capítulo II. Introducción a Redis
3. Instalación de Redis
En la figura 1 se puede observar la página principal del pro-
yecto Redis. Como la mayoría del software, este se encuentra suje-
to a constantes cambios por la aparición de nuevas versiones o
actualizaciones donde se corrigen errores y se introducen nuevas
funcionalidades. Con el objetivo de mostrar los contenidos del
capítulo, se va a utilizar la versión más estable de Redis actual-
mente, la versión 5.0.3. (los pasos de instalación y ejecución son
similares para cualquiera de las versiones).
Figura 1. Página principal de Redis
Fuente: captura de sitio web https://redis.io/
Para realizar la instalación de Redis, se deben seguir los
siguientes pasos:
• Una vez conectado a la página que contiene todas las versio-
nes de Redis (figura 2). (http://download.redis.io/releases/),
se pulsa sobre el enlace que indica la versión 5.0.3.
45
© Editorial UOC Introducción a las bases de datos NoSQL
Figura 2. Descarga del paquete de Redis
Fuente: captura de sitio web https://redis.io/
• Se abre un terminal de comandos de Linux y se navega hasta
el directorio que contiene el paquete descargado y se ejecuta:
tar xzvf redis-5.0.3.tar.gz , para descomprimir el paquete
(figura 3).
Figura 3. Descomprensión del paquete de Redis
Fuente: elaboración propia
46
© Editorial UOC Capítulo II. Introducción a Redis
• Se navega hasta dentro de la carpeta descomprimida y se eje-
cuta el comando sudo make install (figura 4).
Figura 4. Paquete descomprimido de Redis
Fuente: elaboración propia
Una vez que se ha instalado Redis, para poder trabajar con la
base de datos, es necesario lanzar dos programas desde la carpe-
ta src que son redis-server y redis-cli (figura 5). Redis-server es
el servidor de Redis y puede ejecutarse en modo unitario o en
clúster, y redis-cli es el cliente que permite interactuar con Redis
a través de una línea de comandos (se introducen los comandos
y se ejecutan). El servidor de Redis se ejecuta por defecto en el
puerto 6379.
47
© Editorial UOC Introducción a las bases de datos NoSQL
Figura 5. Cliente y servidor de Redis
Fuente: elaboración propia
Para lanzar cada programa se abre un terminal del sistema,
y situándose en la carpeta src de Redis, se escribe el nombre de
cada programa (figura 6).
Figura 6. Ejecución de redis-cli y redis-server
Fuente: elaboración propia
48
© Editorial UOC Capítulo II. Introducción a Redis
4. Bases de datos en Redis
Redis es una base de datos de tipo clave-valor que almacena
conjuntos de datos denominados valores que pueden ser de dife-
rentes tipos. Cada base de datos se identifica mediante un núme-
ro (por defecto toma el valor de 0), y se puede cambiar entre
ellas utilizando el comando SELECT. En la figura 7 se muestra
un ejemplo en el que se cambia de la base de datos por defecto
a la base de datos 1, y viceversa.
Figura 7. Cambio de base de datos
Fuente: elaboración propia
Otro comando muy útil relacionado con las bases de datos es
FLUSHDB que reinicia una base de datos a su estado original y
la deja limpia.
Al ser una base de datos de tipo clave-valor, cada conjunto de
datos tiene asociado una clave que sirve para identificarlo. Por
ejemplo, si se quiere almacenar un valor que es de tipo cadena se
pueden usar los comandos SET y GET que permiten respectiva-
mente asociar una clave a un valor de tipo cadena y recuperar el
49
© Editorial UOC Introducción a las bases de datos NoSQL
valor a partir de la clave. En el ejemplo de la figura 8 se muestra
la creación de una clave y la recuperación del valor asociado.
Figura 8. Creación de un par clave-valor y recuperación del valor
Fuente: elaboración propia
50
© Editorial UOC Capítulo II. Introducción a Redis
Tal como se señalaba más arriba, las claves tienen asociado un
conjunto de comandos. La invocación de los comandos sigue la
misma sintaxis:
Nombre_Comando Nombre_clave
Figura 9. Uso del comando KEYS
Fuente: elaboración propia
Los comandos SETEX, EXPIRE y EXPIREAT están relacio-
nados con el tiempo de vida de una clave. Así, EXPIRE permite
especificar un tiempo de expiración para una clave en segundos,
pasado el cual, la clave se elimina. La ejecución del comando
retornará bien 1, si se ha asociado correctamente, o bien 0 si la
clave indicada no existe o no se puede asociar el tiempo de expi-
ración. Un comando relacionado con este último es el comando
TTL. Cuando se aplica sobre una clave puede devolver como
resultado un valor positivo que representa el tiempo que le queda
de vida, el valor -2 si la clave ya ha expirado o no existe, o bien el
valor -1 si la clave existe pero no tiene asociado un valor de expi-
ración. En la figura 10 se muestra el uso del comando EXPIRE
51
© Editorial UOC Introducción a las bases de datos NoSQL
y del comando TTL sobre una clave a la que se le ha asociado un
tiempo de expiración 10.
Figura 10. Uso del comando EXPIRE Y TTL
Fuente: elaboración propia
De forma similar a los casos anteriores, se tiene el comando
SETEX, que realiza de forma atómica las operaciones de crear
y asociar un tiempo de expiración a una clave dada, y el coman-
do EXPIREAT que actúa de la misma forma que el comando
EXPIRE pero en vez de asociar a la clave un tiempo en segun-
dos, le asocia un valor que representa el tiempo transcurrido
desde el 1 de Enero de 1970.
Por último, hay que observar que las limitaciones que exis-
ten para realizar consultas sobre los contenidos de los valores
almacenados, la forma en la que se almacena la información y el
tipo de estructuras que ofrece la base de datos para gestionar los
diferentes datos, influye en la alta velocidad de procesamiento
que ofrece este producto. En particular, existe un comando en
Redis, redis-benchmark, que permite medir el rendimiento del
sistema en operaciones por segundo. En la figura 11 se muestra
una invocación del mismo, y el resultado que se obtiene.
52
© Editorial UOC Capítulo II. Introducción a Redis
Fuente: elaboración propia
En la tabla 1 se muestran algunos de los comandos más
importantes definidos sobre las claves.
Tabla 1. Comandos asociados a las claves
Nombre del comando Significado
DEL key Elimina la clave si existe.
DUMP key Retorna una versión serializada del valor
almacenado asociado a la clave indicada.
EXISTS key Comprueba si la clave existe o no.
EXPIRE key seconds Configura el tiempo de expiración de una clave
después del tiempo especificado en segundos.
EXPIREAT key timestamp Configura el tiempo de expiración de una clave
después del tiempo especificado en formato
time stamp de Unix.
PEXPIRE key milliseconds Configura el tiempo de expiración de una clave
en milisegundos.
PEXPIREAT key milliseconds- Configura el tiempo de expiración de una
timestamp clave después en formato time stamp de Unix
especificado en milisegundos.
KEYS pattern Encuentra todas las claves encajando con el
patrón específicado.
53
© Editorial UOC Introducción a las bases de datos NoSQL
Nombre del comando Significado
MOVE key db Mueve una clave a otra base de datos.
PERSIST key Elimina el tiempo de expiración de una clave.
PTTL key Obtiene el tiempo restante en claves que
expiran medido en milisegundos.
TTL key Obtiene el tiempo restante en claves que
expiran.
RANDOMKEY Retorna una clave aleatoriamente de la base de
datos.
RENAME key newkey Renombra la clave dada con el nuevo nombre
de clave.
RENAMENX key newkey Renombra la clave dada con el nuevo nombre
de clave, en caso de que no exista ese nombre.
TYPE key Retorna el tipo de datos del valor almacenado y
asociado a la clave.
Fuente: elaboración propia
54
© Editorial UOC Capítulo II. Introducción a Redis
Bibliografía
55
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Capítulo III
Estructuras de datos en Redis
1. Introducción
En este capítulo se van a describir las principales estructuras
de datos de Redis y algunas de las operaciones asociadas a estas.
En este sentido, HELP es un comando fundamental dado que,
aplicado a otro comando, permite recuperar información acerca
del funcionamiento de este último: parámetros, ejemplos o for-
mas de usarlo. En la figura 1 se muestra un ejemplo de invoca-
ción del HELP sobre el comando SET.
Figura 1. Uso del comando HELP
Fuente: elaboración propia
2. Cadenas
Una cadena es un valor que puede ser de tipo textual (XML,
JSON, HTML o texto), valores enteros, reales o datos binarios
(vídeo, imágenes o audio), pero en cualquier caso no puede exce-
der los 512 Mb. El comportamiento de una cadena depende del
57
© Editorial UOC Introducción a las bases de datos NoSQL
tipo de valor que representa. Además para cada tipo de cadena
existen comandos específicos y que puede que no tengan sentido
para otros tipos de cadenas. A continuación se van a introducir
los más importantes.
Los comandos SET y GET sirven respectivamente para crear
una clave asociada a una cadena y recuperar la cadena asociada
a una clave. De forma similar, el comando MSET permite crear
varias claves a la vez especificando los pares clave-valor separa-
dos por espacios tal como se puede observar en la figura 2.
Figura 2. Uso del comando MSET
Fuente: elaboración propia
Figura 3. Uso del comando MGET
Fuente: elaboración propia
58
© Editorial UOC Capítulo III. Estructuras de datos en Redis
retornan como resultado el valor final incrementado. Por último,
los comandos DECR y DECRBY disminuyen el valor asociado
a una clave por el número entero o real especificado y retornan
como resultado el valor disminuido. En todos los casos, se pueden
usar como valores de incremento/disminución números números
positivos o negativos. En la figura 4 se muestran algunos ejemplos
respecto a una clave a la que se asocia el valor 150.
Figura 4. Uso de los comandos de incremento y disminución
Fuente: elaboración propia
Observar que los comandos son atómicos. Es por esta razón
que el incremento/disminución se realiza en una única opera-
ción y no se puede dar el caso de que dos clientes diferentes que
estén ejecutando el mismo comando al mismo tiempo vayan a
obtener el mismo resultado.
Otro conjunto de comandos sirve para gestionar bits. Se trata
de los comandos SETBIT, GETBIT, BITCOUNT y BITOP. El
comando SETBIT establece a 0 o 1 una posición de un conjunto
de bits (y en caso de no existir la posición se crea). Por otra parte
el comando GETBIT permite recuperar el valor de una posición
de un conjunto de bits asociado a una clave. En la figura 5 se
muestra un ejemplo donde se han establecido a 1 los bits de las
posiciones 10 y 15, y después se recuperan.
59
© Editorial UOC Introducción a las bases de datos NoSQL
Figura 5. Uso de los comandos SETBIT y GETBI
Fuente: elaboración propia
EL comando BITCOUNT está asociado a los dos anteriores,
retorna el número de bits marcados a 1 de un conjunto de bits.
En la figura 6 se muestra la invocación del comando sobre el
ejemplo anterior.
Figura 6. Uso de BITCOUNT
Fuente: elaboración propia
En la tabla 1 se muestran los principales comandos relaciona-
dos con las cadenas y su significado.
60
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Tabla 1. Comandos asociados a las cadenas
Comando Significado
APPEND Añade un valor al final del valor existente asociado a la clave (o
crea uno si no existe ninguno todavía).
BITCOUNT Cuenta el número de conjuntos de bits de una cadena. Puede
indicarse un intervalo de la cadena, especificando el comienzo y
final de esta.
BITOP Realiza una operación bit a bit entre varias claves (que contienen
valores de cadena) y almacena el resultado en la clave de destino.
BITPOS Devuelve la posición del primer bit con valor a 1 o 0 en una
cadena dada.
DECR Disminuye el valor asociado a la clave en 1.
DECRBY Disminuye el valor asociado a la clave por el número dado.
GET Recupera un único valor.
GETBIT Devuelve el valor del bit en la posición indicada en el valor de
cadena almacenado en key.
GETRANGE Retorna la subcadena del valor asociado a la clave indicando el
intervalo de comienzo y final. Estos valores pueden ser negativos si
se comienza por el final de la cadena (-1 indica el final).
GETSET Crea una clave simple y devuelve el valor antiguo asociado
a la clave. Se produce un error si no tenía valor asociado
anteriormente.
INCR Incrementa el valor asociado a la clave en 1.
INCRBY Incrementa el valor asociado a la clave por el número dado.
INCRBYFLOAT Incrementa el valor asociado a la clave por el número real dado.
MGET Recupera múltiples valores.
MSET Crea una clave múltiple.
MSETNX Crea una clave múltiple si no existe.
PSETEX Crea una clave con tiempo de expiración en milisegundos.
SET Crea una clave simple.
SETBIT Establece el valor de un bit en 0 o 1 en la posición indicada en el
valor de cadena almacenada para una clave dada.
SETEX Crear clave con tiempo de expiración en segundos.
61
© Editorial UOC Introducción a las bases de datos NoSQL
Comando Significado
SETNX Crea una clave si no existe.
SETRANGE Sobreescribe parte de la cadena almacenada en la clave,
comenzando en el desplazamiento especificado con la longitud del
valor. Si el desplazamiento es mayor que la longitud actual de la
cadena en la clave, la cadena se rellena con cero-bytes para hacer
ajuste de compensación.
STRLEN Longitud del valor asociado a la clave.
Fuente: elaboración propia
Figura 7. Uso de BITOP
Fuente: elaboración propia
62
© Editorial UOC Capítulo III. Estructuras de datos en Redis
3. Listas
Las listas representan un conjunto de valores ordenados para
las cuales se han definido operaciones tales como añadir valores
a la lista, recuperar el primer y último valor, o manipular los
valores usando los índices que indican su posición. Como están
implementadas en forma de listas enlazadas entonces permiten
la inserción de valores por la cabeza o la cola de la lista. Por otra
parte existen un tipo de operaciones denominadas bloqueantes,
dado que cuando se ejecutan sobre una lista vacía, tienen como
efecto que el sistema se quede esperando hasta que se añada un
nuevo elemento. Por otra parte, observaremos que las operacio-
nes sobre listas son atómicas.
A continuación se van a describir algunos de los comandos más
utilizados. En primer lugar, se encuentran los de inserción de datos
LPUSH y RPUSH, que sirven respectivamente para insertar datos al
principio y al final de una lista. En la figura 8 se muestra un ejemplo.
Figura 8. Uso de los comandos LPUSH y RPUSH
Fuente: elaboración propia
63
© Editorial UOC Introducción a las bases de datos NoSQL
En segundo lugar, se tienen los comandos LLEN y LINDEX.
Mediante el comando LLEN se puede obtener la longitud de
una lista y mediante el comando LINDEX se pueden recuperar
los valores de una lista especificando el índice que representa la
posición del valor en esta comenzado por el índice 0 para indi-
car la primera posición y el índice -1 para indicar la última. En
la figura 9 se muestra un ejemplo de cada uno de los comandos
descritos.
Figura 9. Uso de los comandos LLEN y LINDEX
Fuente: elaboración propia
En la tabla 2 se muestran los principales comandos relaciona-
dos con las listas y su significado.
Tabla 2. Comandos asociados a las listas
Comando Significado
BLPOP Es una versión bloqueante del comando LPOP. Se proporcionan
un conjunto de listas, de manera que se extrae un elemento de
la cabeza de la primera lista de las dadas que no esté vacía.
Las listas se comprueban en el orden especificado en el
comando. En caso de no existir elementos en ninguna de las
listas especificadas, entonces se bloquea al cliente que inició la
operación un tiempo especificado en el mismo comando.
BRPOP Es una versión bloqueante del comando RPOP. Se proporcionan
un conjunto de listas, de manera que se extrae un elemento
de la cola de la primera lista de las dadas que no esté vacía.
Las listas se comprueban en el orden especificado en el
comando. En caso de no existir elementos en ninguna de las
listas especificadas, entonces se bloquea al cliente que inició la
operación un tiempo especificado en el mismo comando.
64
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Comando Significado
BRPOPLPUSH Es una versión bloqueante del comando RPOPLPUSH. La principal
diferencia con este último comando es que en caso de no existir
elementos para extraer de la lista especificada, entonces se
bloquea al cliente que inició la operación un tiempo especificado
en el mismo comando. Si existen elementos entonces se
comporta exactamente igual que RPOPLPUSH.
LINDEX Devuelve el valor situado en el índice dado de la lista
almacenada (se empieza a contabilizar por 0 al principio de la
lista y por -1 al final de la lista).
LINSERT BEFORE/ Inserta un valor en la lista almacenada antes o después del valor
AFTER pivote proporcionado.
LLEN Obtener la longitud de la lista almacenada.
LPOP Elimina y retorna el primer elemento de la lista almacenada.
LPUSH Inserta todos los valores especificados en la cabeza de la lista
almacenada. Si la clave no existe, se crea una lista vacía antes
de realizar la operación.
LPUSHX Igual que LPUSH, pero debe existir la clave y contener una lista,
en caso contrario no realiza ninguna operación.
LRANGE Devuelve los elementos especificados de la lista almacenada en
el intervalo de valores especificados. Los índices se especifican
empezando desde 0 para el principio de la lista o -1 para el final
de la lista.
LREM Elimina las n ocurrencias de un valor dado de la lista
almacenada, de manera que si n > 0 se eliminan empezando
desde la cabeza a la cola de la lista, si n > 0 se eliminan
empezando desde la cola a la cabeza y si n = 0 se eliminan
todos las ocurrencias de la lista.
LSET Introduce el valor dado en la posición establecida de la lista
almacenada.
LTRIM Recorta una lista para que contenga solo el rango de elementos
especificados por dos índices que indican el comienzo y final de
la sublista (los índices se comienzan a contar desde 0).
RPOP Elimina y retorna el último elemento de la lista almacenada.
RPOPLPUSH Devuelve y elimina atómicamente el último elemento de la lista
almacenada e introduce el elemento en la primera posición de
la otra lista especificada.
RPUSH Inserta todos los valores especificados en la cola de la lista
almacenada. Si la clave no existe, se crea una lista vacía antes
de realizar la operación.
RPUSHX Igual que RPUSH, pero debe existir la clave y contener una lista,
en caso contrario no realiza ninguna operación.
Fuente: elaboración propia
65
© Editorial UOC Introducción a las bases de datos NoSQL
Para recuperar los valores de una lista, también existen los
comandos LPOP y RPOP. Estos comandos permiten respecti-
vamente recuperar el primer y último elemento de una lista dada
pero eliminándolo de esta. En la figura 10 se muestra un ejemplo
de su uso sobre las listas del ejemplo anterior.
Figura 10. Uso de los comandos LPOP y RPOP
Fuente: elaboración propia
Por último, mencionaremos el comando LRANGE, que per-
mite recuperar una sublista de elementos a partir de una lista
dada. Para ello es necesario especificar un intervalo de índices de
comienzo y final de la sublista. Tal como se ha comentado antes,
el índice 0 indica la primera posición y el índice -1 indica la última
posición de la lista. En la figura 11 se muestra un ejemplo de uso.
Figura 11. Uso del comando LRANGE
Fuente: elaboración propia
Algunos ejemplos de uso en el que son útiles las listas son los
siguientes:
66
© Editorial UOC Capítulo III. Estructuras de datos en Redis
• Implementación de una colección, una pila o una cola.
• Implementación de una cola de eventos.
• Almacenamiento de los posts de usuarios más recientes.
4. Hash
Representa un conjunto de pares clave-valor donde cada clave
permite acceder a un valor asociado. Tanto la clave como el valor
son cadenas. Se implementa como una lista doblemente enlazada
diseñada para ser eficiente en memoria. De esta forma el acceso
a un hash está optimizado y se pueden realizar búsquedas rápi-
das. La principal ventaja de este tipo de datos es que es posible
acceder y actualizar valores concretos sin tener que recuperar o
modificar todo el conjunto de datos asociado a la clave.
A continuación se muestran los principales comandos asocia-
dos a un hash. En primer lugar, se encuentran los comandos HSET
y HMSET, que se usan para insertar datos. El comando HSET
permite asociar un valor a una clave mientras que el comando
HMSET permite hacer la misma operación sobre un conjunto
de pares clave-valor separados por espacios. En cualquiera de los
casos, si no existen los campos involucrados, se crean y, si existen,
se sobreescriben los valores que contengan. En la figura 12 se
muestra un ejemplo de uso de ambos comandos.
Figura 12. Uso de los comandos HSET y HMSET
Fuente: elaboración propia
67
© Editorial UOC Introducción a las bases de datos NoSQL
Figura 13. Uso de los comandos HGET y HMGET
Fuente: elaboración propia
En la tabla 3 se resumen los principales comandos relaciona-
dos con los hashes y su significado.
Tabla 3. Comandos asociados a los hashes
Comando Significado
HINCRBYFLOAT Actúa igual que HINCRBY pero con incrementos reales.
HMGET Retorna los valores asociados a los campos especificados en el
hash almacenado en la clave. Para cada campo no existente, se
devuelve un valor nulo.
68
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Comando Significado
HMSET Asocia a los campos especificados, los valores indicados en el
hash almacenado en la clave. Sobreescribe cualquier campo
especificado ya existente en el hash. Si la clave no existe, se crea
una nueva clave para contener al hash.
HSET Asocia al campo especificado el valor indicado y lo guarda en el
hash almacenado. Si la clave no existe, se crea, y si el campo ya
existe, se sobreescribe.
HSETNX Asocia al campo especificado el valor indicado y lo guarda en el
hash almacenado solo en el caso de que el campo no exista.
En tercer lugar, se pueden destacar un conjunto de comandos
que ofrecen información sobre la estructura de un hash. Se trata
de HGETALL, HKEYS y HVALS. El comando HGETALL
permite recuperar todos los pares clave-valor almacenados en
un hash, HKEYS permite recuperar las claves utilizadas y, por
último, HVALS permite recuperar los diferentes valores almace-
nados. En la figura 14 se muestra un ejemplo de los comandos
mencionados.
Figura 14. Uso de los comandos HGETALL, HKEYS y HVALS
Fuente: elaboración propia
69
© Editorial UOC Introducción a las bases de datos NoSQL
Por último, quedan por mencionar los comandos HDEL, que
permiten eliminar un par clave-valor de un hash especificando
la clave del par, y HINCRBY, que permite incrementar el valor
numérico asociado a una clave. En la figura 15 se muestra un
ejemplo de los comandos mencionados.
Figura 15. Uso de los comandos HDEL y HINCRBY
Fuente: elaboración propia
5. Conjuntos
Representa una colección no ordenada de cadenas diferentes
(por lo que no es posible añadir elementos repetidos). Se imple-
menta como una tabla hash, de manera que las operaciones sobre
conjuntos están optimizadas. A continuación se muestran los
principales comandos asociados a un conjunto. En primer lugar,
para insertar datos en un conjunto se utiliza el comando SADD,
que permite añadir uno o más elementos al conjunto, ignorando
los repetidos, y devolviendo como resultado el número de ele-
mentos añadidos. La figura 16 se muestra un ejemplo de uso del
comando.
70
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Figura 16. Adicción de elementos con SADD
Fuente: elaboración propia
En segundo lugar, existen un grupo de comandos que imple-
mentan operaciones entre conjuntos. Se trata de los comandos
SINTER, SDIFF y SUNION. SINTER implementa la operación
de intersección entre varios conjuntos, SDIFF la diferencia entre
un conjunto y el resto de conjuntos especificados, y SUNION
la unión de los conjuntos especificados sin incluir valores dupli-
cados. La figura 17 muestra un ejemplo de uso de los comandos
descritos.
Figura 17. Operaciones conjuntistas
Fuente: elaboración propia
En tercer lugar, se encuentra un grupo de comandos que
ofrecen información sobre el conjunto. Se trata de los comandos
SCARD y SMEMBERS. El primero permite recuperar la cardi-
nalidad de un conjunto dado, mientras que el segundo recupera
todos los elementos de un conjunto. La figura 18 muestra un
ejemplo de uso de estos comandos.
71
© Editorial UOC Introducción a las bases de datos NoSQL
Figura 18. Operaciones de consulta
Fuente: elaboración propia
Por último, se encuentran los comandos SRANDMEMBER,
que permiten recuperar n elementos aleatorios de un conjunto;
SISMEMBER, que permite comprobar si un elemento concre-
to pertenece a un conjunto, y SREM que permite eliminar un
elemento de un conjunto. En la figura 30 se muestran varios
ejemplos de uso.
Figura 19. Otras operaciones sobre conjuntos
Fuente: elaboración propia
En la tabla 4 se muestran los principales comandos relaciona-
dos con los conjuntos y su significado.
72
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Tabla 4. Comandos asociados a los conjuntos
Comando Significado
SADD Agrega los miembros especificados al conjunto almacenado
en la clave. Los miembros repetidos se ignoran, y si la clave no
existe, se crea un nuevo conjunto antes de realizar la agregación.
SCARD Retorna el número de elementos del conjunto.
SDIFF Devuelve los miembros del conjunto resultantes de la diferencia
entre el primer conjunto y todos los conjuntos sucesivos.
SDIFFSTORE Funciona igual que SDIFF, pero en lugar de devolver el conjunto
resultante, se almacena en el conjunto destino especificado (si
existe, se sobreescribe).
SINTER Devuelve los miembros del conjunto resultantes de la
intersección de todos los conjuntos dados.
SINTERSTORE Funciona igual que SINTER, pero en lugar de devolver el
conjunto resultante, se almacena en el destino (si existe, se
sobreescribe).
SISMEMBER Devuelve 1 si elemento dado es un miembro del conjunto
almacenado en clave, y 0 en caso contrario.
SMEMBERS Devuelve todos los elementos del conjunto almacenado en la
clave.
SMOVE Mueve un elemento de un conjunto dado a otro conjunto. Es
una operación atómica. Si el elemento especificado no existe, no
se hace nada, y si existe en el conjunto destino, simplemente se
elimina del conjunto origen.
SREM Elimina los miembros especificados del conjunto almacenado en
la clave.
SUNION Devuelve los miembros del conjunto resultante de la unión de
todos los conjuntos dados.
SUNIONSTORE Funciona igual que SUNION, pero en lugar de devolver el
conjunto resultante, se almacena en el destino (si existe, se
sobreescribe).
Fuente: elaboración propia
73
© Editorial UOC Introducción a las bases de datos NoSQL
• Filtrado de datos.
• Agrupamiento de datos.
• Comprobar la pertenencia de alguien a algo.
6. Conjuntos ordenados
Representa un conjunto de elementos distintos donde cada ele-
mento tiene asociado un valor numérico positivo o negativo que
se usa para ordenar los elementos del conjunto de menor a mayor
valor. En caso de existir elementos diferentes con el mismo valor
asociado, estos se ordenan lexicográficamente. Se implementan uti-
lizando dos estructuras de datos, por un lado una lista por saltos con
una tabla hash que permite buscar de manera eficiente dentro de una
secuencia ordenada de elementos y una lista doblemente enlazada
diseñada para ser eficiente en memoria. De esta forma las opera-
ciones son rápidas pero no tanto como en el caso de los conjuntos.
A continuación se van a presentar algunos de los comandos
más importantes. En primer lugar, el comando ZADD, que per-
mite añadir un conjunto de pares elementos-valor a un conjunto
ordenado y que devuelve como resultado el número de elemen-
tos que han sido añadidos. En la figura 20 se muestra un ejemplo
de uso del comando.
Figura 20. Adicción de elementos a un conjunto ordenado
Fuente: elaboración propia
74
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Figura 21. Uso de ZRANGE Y ZREVRANGE
Fuente: elaboración propia
75
© Editorial UOC Introducción a las bases de datos NoSQL
76
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo III. Estructuras de datos en Redis
77
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
Comando Significado
78
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Comando Significado
79
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
7. HyperLogLog
80
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo III. Estructuras de datos en Redis
81
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
82
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo III. Estructuras de datos en Redis
Bibliografía
83
https://dogramcode.com/bases-de-datos
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo IV. Persistencia, replicación y particionamiento
Capítulo IV
Persistencia, replicación y particionamiento
1. Introducción
2. Persistencia
85
https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL
86
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo IV. Persistencia, replicación y particionamiento
recomendable que las directivas estén separadas unas de otras
por menos de 30 segundos.
• Se puede deshabilitar este sistema eliminando las reglas del
archivo redis.conf y reiniciando el servidor.
• Este sistema no garantiza la recuperación de todos los datos
con ninguna combinación de frecuencia-cambios.
• Cuando se crea el proceso hijo encargado del archivo .rdb,
puede ocurrir que el proceso principal deje de estar disponible
para los clientes de la base de datos durante un intervalo de
tiempo que dependerá del hardware y el tamaño de los datos
que deben procesarse.
Existen un conjunto de directivas que permiten configurar los
archivos .rdb tal como se muestran en la tabla 1.
Tabla 1. Directivas de configuración de los archivos .rdb
Directiva Significado
rdbcompression Indica si se debe comprimir o no el archivo rdb. Puede tomar
el valor yes o no.
dbfilename Establece el nombre del archivo .rdb.
save Establece la frecuencia de creación del archivo .rdb en función
del número de segundos y cambios que se producen. Por
defecto toma los valores save 3600 1, save 300 100, y
save 60 10000.
dir Especifica el directorio donde se encuentran localizados los
archivos AOF y RDB.
Fuente: elaboración propia
87
© Editorial UOC Introducción a las bases de datos NoSQL
88
https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo IV. Persistencia, replicación y particionamiento
Tabla 2. Directivas de configuración de los archivos AOF
Directiva Significado
appendfilename Especifica el nombre del archivo AOF. Está vacío por
defecto.
appendfsync Existe un proceso que se ejecuta en segundo plano
denominado fsync( ) que realiza una llamada al
sistema operativo para que envíe los datos al disco. Se
puede configurar en base a tres valores:
no: no se ejecuta el proceso y es el sistema operativo
el que decide cuando descargar los datos. Es la opción
más rápida.
always: se ejecuta el proceso en cada escritura. Es la
opción más costosa pero más segura.
everysec: se ejecuta el proceso cada segundo.
Proporciona un buen rendimiento y es la opción por
defecto.
auto-aof-rewrite- Toma un valor entre 0 y 100. Permite reescribir
percentage el archivo mediante el comando BGREWRITEAOF
si el tamaño del archivo crece en un porcentaje
especificado. Por defecto toma el valor 100.
auto-aof-rewrite-min- Tamaño mínimo de AOF para ser reescrito. Esta
size directiva tiene prioridad sobre lo especificado en
auto-aof-rewrite-percentage. El valor por defecto
es de 67108864 bytes.
aof-load-truncated Toma el valor yes o no. Si se produce un fallo el
archivo AOF puede ser truncado. Esta opción indica si
el sistema puede cargar el archivo cargar truncado y
emitir un error o no cargarlo y emitir un error.
dir Especifica el directorio donde se encuentra localizado
los archivos AOF y RDB.
Fuente: elaboración propia
89
© Editorial UOC Introducción a las bases de datos NoSQL
Algunas observaciones:
• La restauración de datos usando el sistema RDB es más rápida
que el sistema AOF debido a que no es necesario volver a eje-
cutar cada cambio realizado en la base de datos, simplemente
consiste en cargarlos.
• Pueden usarse ambas estrategias, de manera que si existen los
dos archivos, el sistema AOF tiene preferencia sobre RDB
dado que garantiza la durabilidad.
• Se pueden seguir las siguientes reglas para seleccionar una
estrategia u otra dependiendo las necesidades de persisten-
cia. Si no es necesaria la persistencia se pueden deshabilitar
ambos sistemas, si existe tolerancia a la pérdida de datos,
entonces se puede usar RDB y, por último, si se requiere
persistencia duradera, entonces se deberían usar ambos sis-
temas, RDB y AOF.
2.3. Replicación
Consiste en mantener copias de los datos en varias instancias
de la base de datos. Así se distingue una instancia denominada
«maestro», de manera que cada vez se escribe en ella, se realiza
una copia de la escritura en el resto de instancias que reciben
el nombre de «esclavos». Se hace una replicación asíncrona de
forma que cada cierto periodo de tiempo los esclavos reciben
datos para replicar. También es posible que entre las instancias
«esclavo» puedan existir conexiones.
90
© Editorial UOC Capítulo IV. Persistencia, replicación y particionamiento
Figura 1. Un nodo servidor y dos nodos clientes
Fuente: elaboración propia
91
© Editorial UOC Introducción a las bases de datos NoSQL
Se permite convertir una instancia en un esclavo de tres for-
mas diferentes:
• Usar el comando SLAVEOF IP PORT.
• Usar en la instancia de redis-server la opción –slaveof IP
PORT
• Añadir una directiva «slaveof IP PORT» al archivo de confi-
guración del servidor y usar esta configuración.
En la figura 1 se muestra un ejemplo de una instancia «maes-
tro» y dos instancias «esclavos». Para ello se abren tres terminales
distintas, de manera que en la primera terminal se escribe: redis-
server –port 5555, en la segunda se escribe: redis-server --port
6666 –slaveof 127.0.0.1 5555, y en la última: redis-server
--port 7777 –slaveof 127.0.0.1 5555). En la figura 2 se abre
otra terminal donde se añadirá una clave al servidor, y a continua-
ción se consulta a las instancias «esclavos» para comprobar que se
ha realizado la copia de lo escrito en el «maestro».
Figura 2. Prueba del funcionamiento de la replicación
Fuente: elaboración propia
El comando SLAVEOF NO ONE permite convertir un servi-
dor esclavo en un servidor maestro (es útil cuando falla un nodo
92
© Editorial UOC Capítulo IV. Persistencia, replicación y particionamiento
Figura 3. Cambio de servidor maestro
Fuente: elaboración propia
Algunas de las principales aplicaciones de la replicación son:
• Permite mejorar la escalabilidad, dado que todas las operacio-
nes de lectura serán redirigidas hacia los nodos «esclavos» y las
escrituras se realizarán solo sobre el nodo «maestro».
• Permite la redundancia de datos, dado que es posible realizar
copias de los datos en las diferentes réplicas.
• Permite desactivar las operaciones de entrada/salida en el
nodo maestro realizando para ello la persistencia sobre las
réplicas. En este caso, el nodo maestro debería tener deshabi-
litada la persistencia y no reiniciarse pues, de lo contrario, al
reiniciarse vacío y replicarse, se borrarían todos los datos de
las réplicas.
93
© Editorial UOC Introducción a las bases de datos NoSQL
La consistencia de los datos se puede mejorar si se establece
como requisito que exista un número mínimo de réplicas conec-
tadas al maestro, de forma que una operación de escritura se
ejecuta solo si se satisface la condición del número de replicas
conectadas junto con una condición de latencia máxima de repli-
cación expresada en segundos (obsérvese que este esquema de
funcionamiento no garantiza que todas las replicas hayan acep-
tado las operaciones de escritura, solo que están conectadas). La
configuración se realiza usando los parámetros min-slaves-to-
write y min-slaves-max-lag que toman los valores por defecto
0 y 10 respectivamente.
Las réplicas son útiles siempre que el servidor maestro falla,
puesto que contienen los datos más recientes, y cualquiera
de ellas puede sustituir al servidor maestro. Sin embargo, cuan-
do el sistema funciona en modo simple, la conversión de un
nodo esclavo a nodo maestro no se realiza de forma automática,
de manera que habrá que configurarlo manualmente.
2.4. Particionamiento
94
© Editorial UOC Capítulo IV. Persistencia, replicación y particionamiento
de claves en diferentes instancias de Redis mientras que el parti-
cionamiento vertical consiste en la distribución de los valores de
las claves en diferentes instancias de Redis. Así, por ejemplo, si se
tuvieran dos conjuntos de datos, en el particionamiento horizon-
tal cada conjunto de datos entero se almacenaría en una instancia
de Redis diferente, mientras que en un particionamiento vertical
los valores de cada conjunto se distribuirían entre diferentes
instancias.
Se van a considerar dos tipos de particionamientos:
a) Por división del rango. Los datos se distribuyen de acuer-
do a rangos de claves, y se asignan rangos de claves a instan-
cias específicas de la base de datos. Esta aproximación tiene
ciertas desventajas tales como:
• Las distribuciones probablemente serán desiguales, y habrá
rangos de claves mayores que otros.
• No permite cambiar fácilmente la lista de servidores
existentes, dado que si el número de instancias de Redis
cambia, entonces la distribución de rangos debe cambiar
también. En este sentido la agregación o eliminación de un
servidor, invalide parte de los datos.
95
© Editorial UOC Introducción a las bases de datos NoSQL
• Particionamiento del lado del cliente. Es el cliente quien selec-
ciona el nodo donde debe escribir o leer una clave dada.
• Particionamiento asistido por proxy. El cliente envía una peti-
ción a un proxy, el cual actúa de intermediario para enviar la
petición al nodo correcto. Asimismo, se encarga de devolver
los resultados al cliente.
• Enrutado de consultas. Se envía la petición a una instancia
cualquiera, y esa instancia se encarga de reenviar la petición a
la instancia correcta.
El particionamiento tiene algunas desventajas tales como:
96
© Editorial UOC Capítulo IV. Persistencia, replicación y particionamiento
Una forma de resolver el problema de escalar Redis cuando se
usa como almacén de datos consiste en crear desde el principio
un conjunto de instancias en un servidor inicial. Cuando crezcan
las necesidades de almacenamiento y se necesiten más servidores
de Redis, se moverán las instancias de un servidor a otro. Una vez
que se agregue el primer servidor adicional, se deberán mover la
mitad de las instancias de Redis del primer servidor al segundo, y
así sucesivamente. Si se usa la replicación, se puede hacer el cambio
con un tiempo de inactividad mínimo o nulo para sus usuarios:
• Se inician instancias vacías en el nuevo servidor.
• Se mueven los datos configurando estas nuevas instancias
como esclavos para sus instancias de origen.
• Se detienen los clientes.
• Se actualiza la configuración de las instancias movidas con la
nueva dirección IP del servidor.
1 https://redis.io/topics/lru-cache.
97
© Editorial UOC Introducción a las bases de datos NoSQL
• Se envía el comando SLAVEOF NO ONE a los esclavos en
el nuevo servidor.
• Se reinician los clientes con la nueva configuración actualizada.
• Finalmente se cierran las instancias que ya no se usan en el
servidor antiguo.
Por último, quedan por mencionar algunas implementaciones
del particionamiento en Redis:
2 Se puede encontrar información sobre Redis Cluster en http://cort.as/-F2mp.
3 Se puede encontrar información sobre Twemproxy en http://cort.as/-F2mr.
4 Se puede encontrar información sobre redis-rb en http://cort.as/-F2mj.
5 Se puede encontrar información sobre Predis en http://cort.as/-F2mk.
98
© Editorial UOC Capítulo IV. Persistencia, replicación y particionamiento
Bibliografía
99
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
Capítulo V
Otros aspectos del uso de Redis
1. Introducción
2. El sistema publicador/suscrito
Redis implementa un sistema de mensajería donde los publi-
cadores envían mensajes a los suscriptores a través de un enlace
denominado canal. De esta forma, un publicador no sabe quié-
nes serán los receptores de sus mensajes, y de igual forma, un
suscriptor no sabrá quiénes son los publicadores de los que ha
recibido un mensaje. Asimismo, un cliente puede susbribirse a
cualquier número de canales.
En la figura 1 se tiene un ejemplo de publicador-suscriptor.
El suscriptor se ha enlazado a un canal denominado «ejemplo»
y existe un publicador que ha publicado en el canal el mensaje
«Esto es un ejemplo».
101
© Editorial UOC Introducción a las bases de datos NoSQL
Figura 1. Ejemplo de publicador y suscriptor
Fuente: elaboración propia
102
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
Un cliente se puede suscribir y darse de baja de cualquier
canal. Las respuestas a las operaciones de suscripción y cancela-
ción se envían en forma de una secuencia coherente de mensajes
donde el primer elemento indica el tipo de mensaje.
Un mensaje es una respuesta formada por tres elementos,
donde el primero de ellos puede ser:
• Subscribe. Significa que se ha realizado una suscripción con
éxito al canal especificado como el segundo elemento en la
respuesta. El tercer argumento representa el número de cana-
les suscritos actualmente.
• Unsubscribe. Significa que anulamos la suscripción al canal
especificado como segundo elemento en la respuesta. El ter-
cer argumento representa el número de canales a los suscritos
actualmente. Cuando el último argumento es cero, entonces
ya no se está suscrito a ningún canal, y el cliente puede emi-
tir cualquier tipo de comando Redis al estar fuera del estado
pub/sub.
• Message. Es un mensaje recibido como resultado de un
comando PUBLISH emitido por otro cliente. El segundo ele-
mento es el nombre del canal de origen, y el tercer argumento
es la carga útil del mensaje real.
El sistema soporta reconocimiento de patrones, de manera que
un cliente puede suscribirse a nombres de canales que coincidan
con un patrón determinado usando el comando PSUBSCRIBE.
En el siguiente ejemplo se realiza una suscripción a canales de
la forma noticias.arte, noticias.politica…:
PSUBSCRIBE noticias.*
103
© Editorial UOC Introducción a las bases de datos NoSQL
De igual forma se puede dar de baja una suscripción de
un conjunto de canales usando un patrón usando el comando
PUNSUBSCRIBE como en el ejemplo siguiente:
PUNSUBSCRIBE noticias.*
Los mensajes recibidos como resultado de la coincidencia de
patrones se envían en un formato de mensaje de tipo pmessage.
Se trata de un mensaje recibido como resultado de un comando
PUBLISH emitido por otro cliente, que coincide con una sus-
cripción de coincidencia de patrón. El segundo elemento es el
patrón original coincidente, el tercero, el nombre del canal de
origen y el último, la carga útil del mensaje real.
Por otro lado, el sistema confirma los comandos PSUBSCRIBE
y PUNSUBSCRIBE que envían un mensaje de tipo psubscribe y
punsubscribe utilizando el mismo formato que el formato de
mensaje de suscripción y cancelación de suscripción.
Por último observemos que:
1) Un cliente puede recibir un mismo mensaje varias veces si
está suscrito a múltiples patrones o varios patrones y canales que
coinciden con un mensaje publicado. En el siguiente ejemplo, el
cliente recibirá dos mensajes, uno de tipo message y otro de tipo
pmessage.
SUBSCRIBE canal
PSUBSCRIBE c.*
2) En los tipos de mensajes el último argumento es el núme-
ro de suscripciones activas. En este sentido, el cliente saldrá del
sistema de mensajería solo cuando este valor valga 0, es decir
104
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
Tabla 1. Comandos asociados al sistema de mensajería
Comando Significado
PSUBSCRIBE patrón Se suscribe a los canales que coinciden con los
patrones dados.
PUBSUB comando argumento Indica el estado del sistema de mensajería.
PUBLISH canal mensaje Publica un mensaje en el canal especificado.
PUNSUBSCRIBE patrón Deja de escuchar los mensajes publicados en los
canales que coinciden con los patrones dados.
SUBSCRIBE canal Escucha los mensajes publicados en los canales
dados.
UNSUBSCRIBE canal Deja de escuchar los mensajes publicados en los
canales dados.
Fuente: elaboración propia
3. Transacciones
En Redis se pueden definir transacciones que permiten eje-
cutar un grupo de comandos en un solo paso, es decir todos los
comandos se ejecutan secuencialmente como una sola opera-
ción aislada (no es posible interrumpir la ejecución de una tran-
sacción) de forma atómica (se procesan todos los comandos o
ninguno). El comando EXEC activa la ejecución de todos los
comandos de una transacción, por lo que si un cliente pierde
la conexión con el servidor en el contexto de una transacción
antes de llamar al comando MULTI, no se realiza ninguna de
105
© Editorial UOC Introducción a las bases de datos NoSQL
las operaciones. En caso contrario, se llama al comando EXEC
y se realizan todas.
Las transacciones se inician con el comando MULTI, a con-
tinuación se pasa una lista de comandos que se quieren ejecutar
dentro de la transacción, y por último, se ejecuta el comando
EXEC que inicia la transacción. Hasta que no se ejecuta EXEC,
los comandos emitidos se encolan. También es posible llamar al
comando DISCARD, que vaciará la cola de mensajes y saldrá de
la transacción.
En la figura 2 se tiene un ejemplo de transacción. Se comienza
con el comando MULTI, y después se añaden las sentencias SET
y GET. A continuación se ejecuta la transacción con el comando
EXEC.
Figura 2. Ejemplo de publicador y suscriptor
Fuente: elaboración propia
Se observa que:
• Cuando se emite un comando dentro del contexto de una
solicitud MULTI, cada comando responde con la cadena
QUEUED, que indica el encolamiento del mismo.
106
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
• EXEC devuelve un array de réplicas donde cada elemento es
la réplica a un único comando de la transacción en el mismo
orden en que los comandos fueron emitidos.
• Durante una transacción es posible encontrar dos tipos de
errores de comando. En primer lugar, es posible que un
comando no pueda encolarse, por lo que puede haber un
error antes de llamar a EXEC, o bien puede que un comando
falle después de llamar a EXEC.
En el primer caso, el servidor detecta que ha habido un
error al encolar, y no ejecutará la transacción. En el segun-
do, el resto de comandos se ejecutarán incluso si falla algún
comando durante la transacción.
WATCH ejemplo
valor = GET ejemplo
valor = valor + 1
MULTI
SET ejemplo $valor
EXEC
En este caso, si se produjera una condición de carrera y varios
clientes intentaran modificar a la vez el resultado de la variable
107
© Editorial UOC Introducción a las bases de datos NoSQL
• Si la clave vigilada expirara antes de ejecutar EXEC, se ejecu-
tará la transacción.
• Se puede llamar a WATCH varias veces. Simplemente, todas
las llamadas de WATCH tendrán el efecto de observar
los cambios que comienzan a partir de la llamada, hasta el
momento en que se llama a EXEC. También puede enviar
cualquier número de claves a una sola llamada de WATCH.
Cuando se llama a EXEC, todas las claves dejan de ser moni-
torizadas, independientemente de si la transacción se abortó o
no. Además, cuando se cierra una conexión de cliente, se deja
de monitorizar todo.
• Es posible usar el comando UNWATCH (sin argumentos)
para liberar todas las claves monitorizadas y poder utilizar
libremente las transacciones.
A continuación, en la tabla 2, se muestran los comandos más
importantes relacionados con las transacciones.
Tabla 2. Comandos asociados a las transacciones
Comando Significado
DISCARD Descarta todos los comandos emitidos después de MULTI.
EXEC Ejecuta todos los comandos después de MULTI.
MULTI Marca el inicio de un bloque de transacción.
UNWATCH Olvida todas las claves controladas.
WATCH clave Controla las claves dadas para determinar la ejecución del bloque
MULTI-EXEC.
Fuente: elaboración propia
108
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
4. Sistema de canalización o pippeling
• La canalización, además de reducir el costo de latencia debi-
do al tiempo de ida y vuelta, también mejora las operaciones
totales que puede realizar por segundo en un servidor deter-
minado. Esto se debe a que el procesamiento de un comando
es muy barato desde el punto de vista de acceder a las estruc-
turas de datos y ofrecer una respuesta, pero es costoso desde
el punto de vista de generar el socket de entrada-salida (implica
invocar las llamadas al sistema read( ) y write( )) y realizar un
cambio de contexto).
• Cuando se utiliza la canalización, muchos comandos se leen
con una sola llamada al sistema read( ), y las respuestas múl-
tiples se entregan con una sola llamada al sistema write( ). Es
por ello que el número de consultas totales realizadas por
segundo aumenta al inicio casi de forma lineal con canaliza-
ciones más largas y, al final, alcanza 10 veces la línea de base
obtenida sin utilizar la canalización.
109
© Editorial UOC Introducción a las bases de datos NoSQL
5. El lenguaje Lua de scripting
Lua es un lenguaje de script interpretado por Redis. Para
ejecutar los scrips existen dos programas en Redis: EVAL y
EVALSHA.
a) EVAL
En este programa, el primer argumento es un conjunto de
comandos que se ejecutarán en el contexto del servidor Redis,
el segundo es el número de argumentos, el tercero son los argu-
mentos que representan nombres de clave y, a continuación,
aparecen otros argumentos adicionales que no son nombres de
clave. Desde los comandos de Lua se puede acceder a los argu-
mentos utilizando la variable global KEYS de forma indexada
empezando desde 1, y al resto de argumentos que no son clave
mediante la variable global ARGV. Por ejemplo:
Se puede llamar a comandos de Redis desde un script Lua
usando las funciones redis.call ( ) y redis.pcall ( ). Por ejemplo:
> eval “return redis.call(‘set’,KEYS[1],’valor’)” 1 clave
Ambas funciones son muy parecidas. Así, cuando una llama-
da a un comando Redis genera un error, entonces redis.call ( )
110
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
forzará a EVAL a devolverlo, mientras que redis.pcall ( ) lo inter-
ceptará y devolverá una tabla que representa el mismo.
Existe una conversión automática entre tipos de datos en Lua
y de Redis. Para ello se siguen unas reglas de conversión de datos:
• Entero Redis ↔ Número Lua
• Conjunto de datos Redis ↔ Cadena Lua
• Múltiples conjuntos de datos Redis ↔ Tabla Lua (Puede tener
otros tipos de datos Redis anidados).
• Estado Redis ↔ Tabla Lua con un campo que contiene el
estado
• Redis error ↔ Tabla con un campo que contiene el error
• Conjunto de datos vacío Redis ↔ Valor booleano False Lua
• Valor booleano True Lua → Entero Redis con valor 1
Hay dos reglas que se deben tener en cuenta:
Considerar los siguientes ejemplos:
> eval “return 10” 0
(integer) 10
111
© Editorial UOC Introducción a las bases de datos NoSQL
> eval “return {1,2,{3,’El coche rojo’}}” 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 3
2) “El coche rojo”
> eval “return redis.call(‘get’,’clave’)” 0
“valor”
> eval “return {1,2,3.3333,’casa’,nil,’camión’}” 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) “casa”
En el último ejemplo, la conversión se para al encontrarse un
«nil» y no se muestra el valor «camión».
Observemos que hay dos funciones especiales que se pueden
utilizar en los scripts de Lua:
Por último, queda mencionar que Redis garantiza la ejecución
atómica de los scripts, de manera que no se ejecutará ningún otro
script o comando Redis mientras se ejecuta otro.
112
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
b) EVALSHA
Funciona igual que EVAL pero en lugar de tener un script
como primer argumento, tiene el resumen SHA1 de un script, de
manera que:
• Si el servidor dispone de un script con un resumen SHA1 coin-
cidente, se ejecuta el script.
• Si el servidor no dispone de un script con ese resumen SHA1,
se devuelve un error que indica que se use EVAL.
Por ejemplo:
> set clave valor
OK
> eval “return redis.call(‘get’,’clave’)” 0
“valor”
> evalsha 8f8f8goll459l44fk7k9k44k578k765l4llfjj4 0
“valor”
> evalsha ejemplodenollamada 0
(error) `NOSCRIPT` No matching script. Please use
[EVAL](/commands/eval).
Se garantiza que los scripts ejecutados se encuentran en la
caché de una ejecución de una instancia de Redis para siempre.
En este sentido, si se realiza un EVAL contra una instancia de
Redis, todas las llamadas de EVALSHA subsiguientes tendrán
éxito. Para que se vacíe el cache de scripts eliminando todos los
ejecutados hasta el momento hay dos formas:
• Ejecutar el comando SCRIPT FLUSH.
• Reiniciar una instancia de Redis.
113
© Editorial UOC Introducción a las bases de datos NoSQL
Redis dispone de un comando SCRIPT que se puede usar
para controlar el subsistema de scripting. Puede tomar los siguien-
tes valores:
• SCRIPT FLUSH. Obliga a Redis a vaciar el caché de scripts.
• SCRIPT EXISTS sha1 sha2 … shaN. Dada una lista de resú-
menes de SHA1 como argumentos, este comando devuelve
una matriz de 1 o 0, donde 1 significa que SHA1 específico
se reconoce como un script ya presente en el caché de scripting,
mientras que 0 significa que no encontró un script con este
SHA1.
• SCRIPT LOAD script. Este comando registra el script especi-
ficado en el caché de script de Redis. El comando es útil para
asegurar que EVALSHA no fallará sin la necesidad de ejecutar
el script.
• SCRIPT KILL. Este comando interrumpe un script de larga
duración que alcanza el tiempo de ejecución máximo con-
figurado para los scripts. El comando SCRIPT KILL solo se
puede usar con scripts que no modificaron el conjunto de datos
durante su ejecución (ya que detener un script de solo lectura
no viola la atomicidad).
Se llama replicación de efectos de un script a la replicación de
los comandos de escritura únicos generados por este. En este
modo de replicación, mientras se ejecutan los scripts de Lua,
Redis recopila todos los comandos ejecutados y cuando finaliza
la ejecución del script, la secuencia de comandos que generó se
envuelve en una transacción MULTI / EXEC y se envía a las
réplicas y al archivo AOF.
En relación con la replicación de efectos de script existe el
comando redis.set_repl ( ) que permite controlar el motor de
114
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
replicación de scripting. Este comando puede tomar cuatro argu-
mentos diferentes:
redis.set_repl(redis.REPL_ALL) – Replica en AOF y el resto
de replicas.
redis.set_repl(redis.REPL_AOF) – Replicate solo en AOF.
redis.set_repl(redis.REPL_REPLICA) – Replicate solo en las
réplicas.
redis.set_repl(redis.REPL_SLAVE) – Se usa por compatibili-
dad con versiones anteriores.
redis.set_repl(redis.REPL_NONE) – No replica en ninguno.
De forma predeterminada, el motor de secuencias de coman-
dos siempre se establece en REPL_ALL. Por ejemplo:
redis.call (‘set’, ‘Clave1’, ‘Valor1’)
redis.set_repl (redis.REPL_NONE)
redis.call (‘set’, ‘Clave2’, ‘Valor2’)
redis.set_repl (redis.REPL_ALL)
redis.call (‘set’, ‘Clave3’, ‘Valor3’)
Después de ejecutar el script anterior, el resultado es que solo
se crearán las claves A y C en las réplicas y AOF.
Los scripts de Redis no pueden crear variables globales, de
manera que si una secuencia de comandos necesita mantener
el estado entre las llamadas se deben usar claves de Redis en
su lugar. Para evitar el uso de variables globales en los scripts se
puede declarar cada variable usando la palabra clave local. Si
se intenta el acceso a la variable global, el script finaliza y EVAL
devuelve un error (lo mismo ocurre ante el intento de acceder a
una variable global que no existe):
115
© Editorial UOC Introducción a las bases de datos NoSQL
redis > eval ‘ejemplo=10’ 0
(error) ERR Error running script (call to 8f8f8goll459l44f
k7k9k44k578k765l4llfjj4): user_script:1: Script attempted
to create global variable ‘ejemplo’
Otra posibilidad que ofrecen los scripts es la escritura en el
archivo de registro de Redis desde los scripts de Lua usando la
función redis.log (loglevel, mensaje) donde el mensaje es una
cadena y el loglevel representa los niveles de registro y puede
tomar los valores:
• redis.LOG_DEBUG
• redis.LOG_VERBOSE
• redis.LOG_NOTICE
• redis.LOG_WARNING
Se observa que solo se emitirán los registros producidos por
secuencias de comandos con un nivel de registro igual o superior
al nivel de registro de instancia de Redis configurado actualmente.
Por ejemplo la siguiente llamada:
redis.log (redis.LOG_WARNING, “Error en el script.”)
Generará lo siguiente:
[32343] 22 Mar 15:21:39 # Error en el script.
116
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
comando redis.conf o utilizando el comando CONFIG GET /
CONFIG SET. Cuando un script se ejecuta durante más tiempo
del especificado, ocurre lo siguiente:
• Se registra que un script se está ejecutando demasiado tiempo.
• Se comienza a aceptar comandos de otros clientes. Los únicos
comandos permitidos son SCRIPT KILL y SHUTDOWN
NOSAVE (para el resto de comandos se responderá con un
error OCUPADO). En este sentido, se ejecutará SCRIPT
KILL para finalizar una secuencia de comandos que ejecuta
solo comandos de solo lectura, y se utilizará SHUTDOWN
NOSAVE para finalizar una secuencia de comandos que eje-
cuta comandos de escritura.
• Usar EVAL cuando se vaya a ejecutar una tubería.
• Acumular todos los comandos para enviar a la canalización,
comprobar los comandos EVAL y usar el comando SCRIPT
EXISTS para verificar si todos los scripts se encuentran defi-
nidos. En caso contrario se debe utilizar el comando SCRIPT
LOAD al principio de la tubería y usar EVALSHA para todas
las llamadas de EVAL.
117
© Editorial UOC Introducción a las bases de datos NoSQL
6. Operaciones de gestión
Existen varios comandos orientados a gestionar el servidor y
las conexiones de Redis:
6.1. Gestión de conexiones
Se tienen los comandos mostrados en la tabla 3:
Tabla 3. Comandos asociados a las transacciones
Comando Significado
ECHO mensaje Imprime la cadena dada.
PING Comprueba si el servidor está en ejecución.
QUIT Cierra la conexión actual.
SELECT índice Cambia de base de datos.
CLIENT LIST Devuelve la lista de clientes conectados al servidor.
CLIENT SETNAME Asigna un nombre a la actual conexión.
CLIENT GETNAME Permite suspender a los clientes durante un tiempo
especificado en milisegundos.
CLIENT PAUSE Es un comando de control de conexión.
CLIENT KILL Cierra una conexión de cliente dada.
Fuente: elaboración propia
6.2. Gestión de la seguridad
En la base de datos se puede añadir un nivel de seguridad de
forma que cualquier cliente tenga que autenticarse antes de eje-
cutar un comando. En este sentido, lo primero que hay que hacer
es configurar un password con el comando CONFIG set require-
118
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
Figura 3. Configuración de un password
Fuente: elaboración propia
6.3. Gestión del servidor
Se trata de un conjunto de comandos orientados a gestionar
el servidor. En la tabla 4 se muestran algunos de los principales.
119
© Editorial UOC Introducción a las bases de datos NoSQL
Tabla 4. Comandos para gestionar el servidor
Comando Significado
BGREWRITEAOF Indica que se inicie un proceso de reescritura de un
archivo de tipo append-only.
CLIENT KILL Elimina la conexión de un cliente.
CLIENT LIST Lista de clientes conectados a un servidor.
CLIENT GETNAME Obtiene el nombre de la conexión actual.
CLIENT PAUSE timeout Detiene el procesamiento de comandos de los clientes
por un tiempo específico.
CLIENT SETNAME Establece el nombre de la conexión actual.
CLUSTER SLOTS Consigue un mapeo de nodos en el clúster.
COMMAND COUNT Número total de comandos.
COMMAND GETKEYS Obtiene las claves de un comando dado.
COMMAND INFO Obtiene detalles específicos de un comando.
nombre_comando
CONFIG GET parametro Obtiene el valor de un parámetro de configuración.
CONFIG REWRITE Reescribe del archivo de configuración con la
configuración en memoria.
CONFIG SET parámetro Establece un parámetro de configuración al valor dado.
valor
CONFIG RESETSTAT Restablece las estadísticas.
DBSIZE Devuelve el número de claves en la base de datos
seleccionada.
DEBUG OBJECT key Obtiene información de depuración sobre la clave
dada.
DEBUG SEGFAULT Hace que el servidor se cuelgue.
FLUSHALL Elimina todas las claves de todas las bases de datos.
FLUSHDB Elimina todas las claves de la base de datos actual.
INFO Obtiene información estadística sobre el servidor.
LASTSAVE Obtiene la marca de tiempo UNIX de la última vez que
se guardó correctamente en el disco.
120
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
Comando Significado
MONITOR Escucha todas las peticiones recibidas por el servidor en
tiempo real.
ROLE Devuelve el rol de la instancia en el contexto de la
replicación.
SHUTDOWN Guarda sincrónamente un conjunto de datos en el
disco y cierra el servidor
SLAVEOF Convierte un servidor en esclavo de otra instancia o lo
promueve como maestro.
SLOWLOG Gestiona el registro de consultas lentas del servidor.
SYNC Comando usado para la replicación.
TIME Retorna el tiempo actual del servidor
Fuente: elaboración propia
Una operación importante del servidor es el proceso de cana-
lización, que consiste en que un cliente puede enviar varias soli-
citudes al servidor sin esperar las respuestas, y finalmente podrá
leerlas todas en un solo paso. Este mecanismo permite mejorar
el rendimiento del sistema.
6.4. Gestión de copias de seguridad
Redis permite realizar copias de seguridad de la base de datos.
Para ello, existe el comando SAVE, el cual crea un archivo deno-
minado dump.rdb con el backup de la base de datos. Para restau-
rar el archivo, hay que situarlo en el directorio de instalación de
Redis y reiniciar el servidor. Para obtener el directorio se usa el
comando CONFIG get dir tal como se muestra en la figura 4.
121
© Editorial UOC Introducción a las bases de datos NoSQL
Figura 4. Obtener directorio
Fuente: elaboración propia
Un comando alternativo es BGSAVE que actúa igual a SAVE
pero se ejecuta en segundo plano.
7. Acceso a Redis usando Python
Redis-py es un cliente en Python para actuar sobre Redis. Para
realizar su instalación basta usar pip:
sudo pip install redis
Para trabajar con el cliente, en primer lugar se crea una cone-
xión (figura 5)
Figura 5. Creación de una conexión
Fuente: elaboración propia
122
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
A continuación, se pueden invocar comandos usando la cone-
xión que se ha creado. En la figura 6 se muestra un conjunto
de ejemplo de invocación de comandos básicos de creación de
claves y recuperación de los valores almacenados.
Figura 6. Ejemplos de uso
Fuente: elaboración propia
123
© Editorial UOC Introducción a las bases de datos NoSQL
En el siguiente ejemplo de la figura 7 se ilustra el uso del
mecanismo de la canalización. Observemos que, por defecto,
la canalización se ejecuta como una transacción, es decir los
comandos son ejecutados de forma atómica.
Figura 7. Ejemplos de canalización
Fuente: elaboración propia
pipe=r.pipeline(transaction=False)
• Tipo: informa sobre el tipo de mensaje, que puede ser «subs-
cribe», «unsubscribe», «psubscribe», «punsubscribe», «messa-
ge», «pmessage».
• Canal: es el canal suscrito o cancelado, o el canal en el que se
publicó un mensaje.
124
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
• Patrón: es el patrón que coincide con el canal de un mensaje
publicado. Será Ninguno en todos los casos, excepto para
tipos «pmessage».
• Datos: son los datos del mensaje. Con mensajes de tipo
«unsubscribe» o «subscribe», este valor será la cantidad de
canales y patrones a los que se ha suscrito actualmente la
conexión. Con mensajes del tipo pmessages o messages, este
valor será el mensaje publicado real.
En la figura 8, se muestra un ejemplo de uso
Figura 8. Ejemplos de canalización
Fuente: elaboración propia
Si en una aplicación no se quieren recibir los mensajes de con-
firmación de suscripción/cancelación de suscripción, se pueden
ignorar pasando el argumento ignore_subscribe_messages
= True al método r.pubsub ( ). De esta forma los mensajes de
suscripción/cancelación de la suscripción se podrán leer pero no
remitirán confirmación de ejecución.
Hay dos estrategias diferentes para leer los mensajes:
125
© Editorial UOC Introducción a las bases de datos NoSQL
while True:
mensaje= p.get_message( )
if mensaje:
# Hacer algo con el mensaje
for mensaje in p.listen( ):
# Hacer algo con el mensaje
En la siguiente dirección se puede encontrar más información
sobre redis-py:
https://redis-py.readthedocs.io/en/latest/
126
© Editorial UOC Capítulo V. Otros aspectos del uso de Redis
Bibliografía
Carlson, J. L. (2013). Redis in action. Manning Publications Co.
Da Silva, M. D.; Tavares, H. L. (2015). Redis Essentials. Packt Publishing
Ltd.
Das, V. (2015). Learning Redis. Packt Publishing Ltd.
Macedo, T., & Oliveira, F. (2011). Redis Cookbook: Practical Techniques for
Fast Data Manipulation. O’Reilly Media, Inc.
Nelson, J. (2016). Mastering Redis. Packt Publishing Ltd.
Redis. Documentation. https://redis.io/documentation.
Redis-py. https://redis-py.readthedocs.io/en/latest/.
127
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
Capítulo VI
Ejemplo de uso de Redis
1. Introducción
En este capítulo se va a mostrar un ejemplo de cómo se puede
utilizar Redis para crear una aplicación que simula una red social
como Twitter donde se realiza un intercambio de mensajes entre
sus usuarios registrados. Cada usuario puede seguir a otros y
ver los mensajes que han escrito, y de igual forma, un usuario
puede ser seguido por otros usuarios que ven lo que publica. El
presente capítulo está basado en el ejemplo que se desarrolla en
(Carlson, 2013).
2. Elementos de información
129
© Editorial UOC Introducción a las bases de datos NoSQL
2.1. Usuario
def crear_usuario(conex, usuario, nombre):
#Se convierte el nombre de usuario a minúsculas para
facilitar las comparaciones.usuario = usuario.lower( )
#Se comprueba que no exista el usuario
if conex.hget(‘usuarios:’, usuario):
return None
#Se incrementa el indentificador de usuario
130
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
id = conex.incr(‘usuario:id:’)
#Se declara una canalización
pipeline = conex.pipeline(True)
#Se actualiza el hash que mantiene el mapeo entre
usuarios e ids.
pipeline.hset(‘usuarios:’,usuario, id)
#Se añade la información de usuario a una clave de tipo
HASH
pipeline.hmset(‘usuario:%s’%id, {
‘usuario’: usuario,
‘id’: id,
‘nombre’: nombre,
‘seguidores’: 0,
‘siguiendo’: 0,
‘posts’: 0,
‘registro’: time.time( ),
})
pipeline.execute( )
return id
Observar que la inicialización de un usuario consiste en inicia-
lizar a 0 los campos de información, asignarle un valor temporal
al registro, un identificador, definir el nombre del usuario y el
usuario propiamente dicho.
2.2. Mensajes propios
Sobre los mensajes que publican los usuarios de una red social
como Twitter podría interesar almacenar la siguiente informa-
ción: el contenido del mensaje, el nombre e identificador del
131
© Editorial UOC Introducción a las bases de datos NoSQL
usuario que lo publicó, un identificador para el mensaje y cuándo
fue publicado. Esta información se podría almacenar como el
valor de una clave de tipo HASH. A continuación, se muestra en
Python la función que permite crear un nuevo mensaje.
def crear_mensaje(conex, uid, mensaje, **datos):
#Se configura una canalización
pipeline = conex.pipeline(True)
#Se obtiene el usuario asociado al identificador de
usuario uid
pipeline.hget(‘usuario:%s’%uid, ‘usuario’)
#Se crea un nuevo identificador para el mensaje
pipeline.incr(‘mensaje:id:’)
#Se ejecuta la canalización
usuario, id = pipeline.execute( )
#Si no se ha conseguido ningún usuario entonces se
sale
if not usuario:
return None
#Se crea el mensaje
data.update({
‘mensaje’: mensaje,
‘publicado’: time.time( ),
‘id’: id,
‘uid’: uid,
‘usuario’: login,
})
#Se guarda el mensaje creado
pipeline.hmset(‘mensajes:%s’%id, datos)
#Se incrementa el número de mensajes enviados.
pipeline.hincrby(‘usuario:%s’%uid, ‘posts’)
132
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
#Se ejecuta la canalización
pipeline.execute( )
#Se devuelve el nuevo identificador de mensaje.
return id
2.3. Mensajes de las personas a las que se sigue
Cuando un usuario se autentica en una red social como
Twitter espera poder ver los últimos mensajes que han publicado
los usuarios a los que está siguiendo. En este sentido, el orden de
publicación es básico. Para garantizar este requisito se puede usar
ZSET, un tipo de clave de Redis que preserva el orden de alma-
cenamiento de sus valores. La información que se va almacenar
serán el identificador del mensaje y una marca temporal que
indica el momento en el cual el mensaje se publicó. Este valor
actuará como elemento de ordenación de los mensajes. Aquellos
más recientes de los usuarios a los que se sigue se almacenarán
en un conjunto que se designará con una clave denominada
«recientesseguidores».
A continuación se muestra una función que implementa esta
funcionalidad:
def obtener_mensajes(conex, uid, mensajesrecientes=’re
cientesseguidores:’, pagina=1, num=30):
#Se recuperan los mensajes más recientes de acuerdo
a las dimensiones indicadas
en
#la función.
mensajes = conex.zrevrange(‘%s%s’%(mensajesrecient
es, uid), (pagina-1)*num, pagina*num-1)
133
© Editorial UOC Introducción a las bases de datos NoSQL
#Se crea una canalización
pipeline = conex.pipeline(True)
#Se procesa cada mensaje usando su id
for id in mensajes:
#Se recupera cada mensaje
pipeline.hgetall(‘mensaje:%s’%id)
#Se devuelven los mensajes recuperados y se filtran los
mensajes que han sido
#previamente eliminados.
return filter(None, pipeline.execute( ))
134
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
2.4. Personas a las que se sigue y personas
seguidas
Para mantener la lista de seguidores y la de las personas a las
que sigue un usuario, se utilizará nuevamente un tipo de datos
ZSET donde se almacenarán los identificadores de los usuarios
y las marcas temporales de cuándo se comenzó la relación de
seguimiento. Asimismo, es importante controlar dos situaciones
extremas, por un lado, cuándo se comienza a seguir a alguien y,
por otro, cuándo se deja de seguir a alguien. En ambos casos,
habrá que hacer modificaciones sobre el tipo HASH que man-
tiene información sobre un usuario, como en el tipo ZSET en
el que se almacena la información de seguidores y seguidos.
Concretamente, habrá que actualizar los valores de las claves que
controlan el número de usuarios seguidores o seguidos, y copiar
o eliminar los mensajes más recientes de la lista de mensajes de
las personas seguidas por un usuario. A continuación, se muestra
el código de la función en Python que implementa lo comentado.
def seguir_usuario (conex, uid, otro_uid):
#Nombre de las claves de seguidores y seguidos
fkey1 = ‘Siguiendo:%s’%uid
fkey2 = ‘Seguidores:%s’%otro_uid
#Se comprueba si el usuario ya está siguiendo al otro
usuario
if conex.zscore(fkey1, otro_uid):
return None
#Se recupera la hora actual
tiempo= time.time( )
#Se declara una canalización.
pipeline = conex.pipeline(True)
135
© Editorial UOC Introducción a las bases de datos NoSQL
136
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
def dejar_seguir_usuario(conex, uid, otro_uid):
#Nombre de las claves de seguidores y seguidos.
fkey1 = ‘Siguiendo:%s’%uid
fkey2 = ‘Seguidores:%s’%otro_uid
137
© Editorial UOC Introducción a las bases de datos NoSQL
138
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
2.5. Almacenar mensajes de los seguidores
139
© Editorial UOC Introducción a las bases de datos NoSQL
de personas seguidas se realizará directamente, mientras que en
el segundo caso se tratará de forma diferida.
En la siguiente función se implementa la actualización del
conjunto de mensajes más recientes de un usuario y se realiza
una llamada a otra función que se encarga de actualizar el con-
junto de mensajes más recientes de los usuarios seguidos por los
seguidores.
def agregar_propio(conex, uid, mensaje, **data):
#Se recupera el identificador del mensaje creado
id = crear_mensaje(conex, uid, mensaje, **data)
#Si se produce un error se finaliza la función.
if not id:
return None
#Se recupera el momento en que se publicó
publicado= conex.hget(‘mensaje:%s’%id, ‘publicado’)
#Si se produce un error se finaliza la función
if not publicado:
return None
#Se crea la entrada a almacenar en el conjunto de
mensajes más recientes del usuario
post = {str(id): float(publicado)}
#Se añade al conjunto de mensajes más recientes del
usuario.
conex.zadd(‘recientespropios:%s’%uid, **post)
#Se envía la entrada para almacenarla en el conjunto
de mensajes más recientes de
#los seguidores
agregar_seguidores(conex, uid, post)
return id
140
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
def agregar_seguidores(conex, uid, post, start=0):
#Se recuperan los siguientes0mil seguidores del usuario
empezando por el último
#usuario que fue actualizado.
seguidores = conn.zrangebyscore(‘seguidores:%s’%u
id, start, ‘inf’,start=0,
num=1000, withscores=True)
#Se inicializa una canalización
pipeline = conn.pipeline(False)
#Se procesa cada seguidor, y se actualiza la variable
start que guardará el último
#usuario actualizado. Esta variable se usará para las
siguientes llamadas a
#agregar_seguidores( )
for seguidor, start in seguidores:
#Se añade el mensaje al conjunto de mensajes más
recientes de los usuarios
#seguidos
pipeline.zadd(‘recientesseguidores:%s’%seguidor,
**post)
#Se divide el conjunto de manera que no sean
demasiado grande
pipeline.zremrangebyrank(‘recientesseguidores:%s’%s
eguidor, 0, -999)
#Se ejecuta la canalización
pipeline.execute( )
141
© Editorial UOC Introducción a las bases de datos NoSQL
#Si se han procesado al menos0mil seguidores entonces
se utiliza la actualización
#retardada
if len(seguidores) >= 1000:
#Ejecución retardada de la actualización del conjunto
de mensajes mas recientes
#de usuarios seguidos
Ejecu_retardada(conex, ‘default’, ‘agregar_seguidores’,
[conex, uid, post, start])
2.6. Eliminación de mensajes
def borrar_mensaje(conex, uid, mensaje_id):
#Nombre de la clave del mensaje
clave = ‘mensaje:%s’%mensaje_id
#Se recupera el identificador de usuario del propietario
del mensaje
if conex.hget(clave, ‘uid’) != str(uid):
return None
#Se abre una canalización
pipeline = conex.pipeline(True)
142
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
#Se elimina el mensaje con la clave dada
pipeline.delete(clave)
#Se actualiza el conjunto de mensajes más recientes
del propio usuario
pipeline.zrem(‘recientespropios:%s’%uid, mensaje_id)
#Se actualiza el conjunto de mensajes más recientes de
los seguidores
pipeline.zrem(‘recientesseguidores:%s’%uid, mensaje_
id)
Disminuye el contador de mensajes posteados de la
información de usuario
pipeline.hincrby(‘usuario:%s’%uid, ‘posts’, -1)
#Se ejecuta la canalización
pipeline.execute( )
return True
3. Conclusión
143
© Editorial UOC Introducción a las bases de datos NoSQL
• La gestión de los retweets.
• Los mensajes que se etiquetan como que gustan a un usuario
concreto.
• La posibilidad de tener grupos de usuarios privados.
• La posibilidad de replicar mensajes y generar hilos de conver-
saciones.
• La posibilidad de etiquetar los mensajes con hashtags.
• Mantener un registro de las personas que mencionan a alguien.
• Disponer de controles de spam o de abusos realizados por
usuarios.
144
© Editorial UOC Capítulo VI. Ejemplo de uso de Redis
Bibliografía
145
© Editorial UOC Conclusión
Conclusión
147
© Editorial UOC Introducción a las bases de datos NoSQL
El segundo objetivo del libro era realizar una introducción a
Redis como base de datos de tipo clave-valor. Para ello, en primer
lugar, se ha descrito como se realiza su instalación. Se ha des-
crito el modelo de datos y la arquitectura que soporta esta base
de datos, y se han introducido los diferentes tipos de claves que
posee. Este último aspecto es importante, dado que Redis ofre-
ce una variedad y riqueza de tipos de clave que permite realizar
mapeos con las estructuras de datos utilizadas en los lenguajes de
programación. Asimismo se han ilustrado varios de los aspectos
comunes a las bases de datos NoSQL tales como son la replica-
ción y particionamiento de la información y los mecanismos de
persistencia de la información. Por otra parte, también se han
introducido otros aspectos de Redis, tales como el sistema de
mensajería, el sistema transaccional, el lenguaje de scripting Lua o
el uso del lenguaje Python para poder interactuar con ella.
Por último, se ha querido mostrar un ejemplo de aplicación
de Redis en un caso real y se ha descrito como se implementaría
una red social similar a Twitter. Se ha mostrado una implemen-
tación de las funcionalidades más básicas, pero su extensión
completa se podría hacer de una forma tan simple como la que
se ha mostrado.
El libro tiene la pretensión de ser un punto de partida para
aquellos que quieren profundizar en las bases de datos NoSQL y
en particular en la base de datos Redis.
148
TECNOLOGÍA
En este libro se ofrece una introducción a las bases de datos NoSQL utilizando
como elemento de ilustración Redis, una base de datos de tipo clave-valor.
Se estructura en dos partes. En la primera, se describen los conceptos
fundamentales de las bases de datos NoSQL, y en la segunda, se introduce Redis.
Se explica su instalación, el modelo y las estructuras de datos, aspectos sobre
replicación, particionamiento y tipos de persistencia, y algunos aspectos de
administración de Redis. En el último capítulo se describe un ejemplo
de aplicación real de este sistema.
Antonio Sarasa
al desarrollo de aplicaciones.
https://dogramcode.com/bases-de-datos