Está en la página 1de 150

TECNOLOGÍA

ANTONIO SARASA

INTRODUCCIÓN
NoSQL
A LAS BASES DE DATOS

REDIS
CLAVE-VALOR USANDO

https://dogramcode.com/bases-de-datos
Dogram Code

Accede a Gratis a la Biblioteca Online +300 Libros en PDF


https://dogramcode.com/biblioteca
Únete al canal de Telegram
https://t.me/bibliotecagratis_dogramcode
Únete al Grupo de Facebook
https://www.facebook.com/groups/librosyrecursosdeprogramacion

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

Diseño de la colección: Editorial UOC


Diseño de la cubierta: Natàlia Serrano

Primera edición en lengua castellana: abril 2019

© Antonio Sarasa, del texto

© Editorial UOC (Oberta UOC Publishing, SL) de esta edición, 2019


Rambla del Poblenou, 156
08018 Barcelona
http://www.editorialuoc.com

Realización editorial: Reverté-Aguilar

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

Capítulo I. Introducción a las bases de datos NoSQL


orientadas hacia agregados ................................................. 15
1. Introducción.......................................................................... 15
2. Las bases de datos NoSQL ................................................ 15
3. Características comunes de las bases de datos
NoSQL................................................................................... 23
4. Bases de datos NoSQL orientadas hacia agregados....... 28
5. Bases de datos NoSQL documentales.............................. 35
6. Bases de datos NoSQL de tipo clave-valor ..................... 36
7. Bases de datos NoSQL orientadas a columnas............... 38
Bibliografía.................................................................................. 40

Capítulo II. Introducción a Redis.


Una base de datos NoSQL de tipo clave-valor ............. 41
1. Introducción.......................................................................... 41
2. Principales características .................................................... 42
3. Instalación de Redis ............................................................. 45
4. Bases de datos en Redis ...................................................... 49
Bibliografía.................................................................................. 55

Capítulo III. Estructuras de datos en Redis ....................... 57


1. Introducción.......................................................................... 57
2. Cadenas .................................................................................. 57

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

Capítulo IV. Persistencia, replicación


y particionamiento ................................................................. 85
1. Introducción.......................................................................... 85
2. Persistencia ............................................................................ 85
2.1. Redis Database (RDB) ................................................. 85
2.2. Append-only file (AOF) ................................................... 88
2.3. Replicación..................................................................... 90
2.4. Particionamiento ........................................................... 94
Bibliografía.................................................................................. 99

Capítulo V. Otros aspectos del uso de Redis....................... 101


1. Introducción.......................................................................... 101
2. El sistema publicador/suscrito .......................................... 101
3. Transacciones ........................................................................ 105
4. Sistema de canalización o pippeling..................................... 109
5. El lenguaje Lua de scripting .................................................. 110
6. Operaciones de gestión ....................................................... 118
6.1. Gestión de conexiones ................................................ 118
6.2. Gestión de la seguridad ............................................... 118
6.3. Gestión del servidor..................................................... 119
6.4. Gestión de copias de seguridad.................................. 121
7. Acceso a Redis usando Python .......................................... 122
Bibliografía.................................................................................. 127

10

https://dogramcode.com/bases-de-datos
© Editorial UOC Índice

Capítulo VI. Ejemplo de uso de Redis.................................. 129


1. Introducción.......................................................................... 129
2. Elementos de información ................................................. 129
2.1. Usuario ........................................................................... 130
2.2. Mensajes propios .......................................................... 131
2.3. Mensajes de las personas a las que se sigue ............. 133
2.4. Personas a las que se sigue y personas seguidas ...... 135
2.5. Almacenar mensajes de los seguidores ..................... 139
2.6. Eliminación de mensajes ............................................. 142
3. Conclusión............................................................................. 143
Bibliografía.................................................................................. 145

Conclusión...................................................................................... 147

11

https://dogramcode.com/bases-de-datos
https://dogramcode.com/bases-de-datos
© Editorial UOC Prólogo

Prólogo

El mundo de las bases de datos ha cambiado en los últimos


años con la llegada del fenómeno denominado big data. El para-
digma de persistencia más extendido hasta ese momento eran las
bases de datos relacionales. Cualquier sistema de información uti-
lizaba el modelo relacional para almacenarla. Este modelo ofrece
grandes ventajas tales como un sistema de transacciones que ase-
gura la consistencia de la información; el lenguaje SQL, que
constituye un lenguaje de consultas estándar; el modelo relacional,
que constituye un modelo formal en el que se sustentan estas
bases de datos; así como otras características como el rol de ele-
mento de integración entre diferentes aplicaciones. Sin embargo,
las necesidades de persistencia en el big data cambian sustancial-
mente. Así, hay varios elementos clave del cambio. En primer
lugar, la cantidad de datos que es necesario procesar; se trata de
enormes cantidades de datos cuya generación es casi inmediata
y cuyo tamaño aumenta de manera exponencial. Por otro lado,
existe la necesidad de procesarlos casi en tiempo real, dado que
el valor de la información decrece al pasar el tiempo. Y por últi-
mo, los formatos y estructuras de los datos. En este contexto, los
datos pueden ser de cualquier forma, pueden tener estructura o
no tenerla y, en caso de tenerla, esta puede cambiar de manera
dinámica. Todas estas nuevas características chocan con las de las
bases de datos relacionales, que esperan datos con una estructura
regular, en cantidades estables y con una capacidad de procesa-
miento determinada. Estos aspectos constituyen elementos clave
en este cambio, dado que la forma más eficiente de adaptarse a

13

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

estas necesidades de procesamiento han sido soluciones de escala-


miento horizontal cuya ejecución se basa en clústers de máquinas.
Y precisamente este ambiente de ejecución no es el más adecuado
para una base de datos relacional diseñada para entornos centra-
lizados. Asimismo, la necesidad de disponer de un esquema de
estructuración de la información previo a su almacenamiento, lo
hace incompatible con este nuevo contexto de procesamiento de
información con estructuras cambiantes.
En este libro se distinguen dos partes. En el primer capítulo se
pretende realizar una introducción a los conceptos fundamenta-
les relacionados con las bases de datos NoSQL. A continuación,
los restantes capítulos se centran en una base de datos NoSQL
concreta: Redis. Se trata de una de las bases de datos de tipo
clave-valor más utilizadas y sirve para ilustrar todas las posibilida-
des que ofrecen este tipo de sistemas de persistencia. Para ello, el
libro se estructura en un conjunto de capítulos donde se describe
cómo realizar su instalación, su arquitectura, sus estructuras de
datos y se realiza una introducción a los tópicos sobre persisten-
cia, particionamiento y replicación de la información. Asimismo,
existe otro capítulo donde se tratan otros aspectos interesantes
de esta base de datos tales como el lenguaje de scripting Lua o
el sistema transaccional implementado en Redis. Por último, se
presenta un ejemplo de aplicación de la base de datos Redis para
la construcción de una red social similar a Twitter.
Espero que el libro le resulte ameno al lector y que cumpla su
objetivo de servir de medio de acercamiento a este nuevo ámbito
de las bases de datos NoSQL, en particular a Redis.
Madrid, 30 de enero de 2019

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

Las bases de datos orientadas hacia agregados son un tipo de


bases de datos NoSQL que presentan unas características particu-
lares en cuanto a la organización de la información. Es por ello
que este capítulo se estructura de la siguiente forma. En primer
lugar se realiza una breve descripción acerca de qué son las bases
de datos NoSQL y se muestran sus principales características. A
continuación, se introducen las bases de datos orientadas hacia
agregados y se muestra el modelo de datos común que compar-
ten. Para finalizar, se describen las familias concretas de este tipo
de bases de datos que existen: las documentales, las orientadas
hacia columnas y las de tipo clave-valor.

2. Las bases de datos NoSQL

La aparición del fenómeno denominado big data tiene impli-


caciones en muchos aspectos tecnológicos, y en particular en el
contexto de los mecanismos de persistencia de la información.
Durante décadas, el modelo más utilizado para almacenar la
información fueron las bases de datos relacionales. Se trata de
un modelo que presenta unas características muy ventajosas en

15

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

cuanto a las necesidades de persistencia que existían antes del big


data. Así, se pueden destacar las siguientes:

• Un modelo de concurrencia. Un problema habitual que se


presenta en la explotación de datos es la gestión de varias
aplicaciones que están manipulando los mismos almacenes de
datos. Esto requiere coordinar todas las aplicaciones que están
accediendo a ellos y modificándolos para evitar que se pro-
duzcan inconsistencias en la información. La gestión manual
de la concurrencia es muy compleja y puede dar lugar a erro-
res con facilidad. En este sentido, el modelo relacional ofrece
un mecanismo de transacciones que garantiza la consistencia
de la información frente a las operaciones de manipulación
realizadas por un conjunto de aplicaciones que se ejecutan
concurrentemente. Aunque el modelo puede dar lugar a
errores, también ofrece mecanismos que permiten revertir
las acciones realizadas por una transacción con el objetivo de
mantener un estado de consistencia en la información.
• Un mecanismo de integración. En muchas ocasiones un sis-
tema informático consiste en un conjunto de aplicaciones
independientes que deben coordinar sus acciones para llevar a
cabo la funcionalidad del sistema. Esta coordinación normal-
mente se traduce en acciones del tipo productor-consumidor,
es decir, una aplicación produce unos datos que otra aplica-
ción utiliza. Una forma de implementar esta interacción es
utilizando una única base de datos que contenga aquellos
que son manipulados de forma común y coordinada por
las diferentes aplicaciones, de esta manera la base de datos
sirve de mecanismo de integración del sistema informático.
Ahora bien, tal como se indicaba anteriormente, un requisito
para conseguir estas características es la disponibilidad de un

16

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

sistema de concurrencia que garantice la consistencia de las


manipulaciones que realiza cada aplicación sobre los datos.
• Un modelo de persistencia de datos. Existen diferentes for-
mas de mantener la información disponible de forma perma-
nente como, por ejemplo, podría ser el uso de archivos. Sin
embargo, un sistema informático que gestiona cantidades de
información importantes requiere de operaciones de manipu-
lación que sean rápidas, eficientes y flexibles. En este sentido,
las bases de datos relacionales ofrecen una forma simple,
flexible y rápida de recuperar, modificar y almacenar grandes
cantidades de datos. Es importante destacar que muchos
problemas que surgen en estas operaciones son resueltos por
el propio sistema de gestión de bases de datos, liberando al
programador de estas tareas.
• Un modelo de acceso a la información estándar. Una de las
ventajas más importantes de las bases de datos relacionales
es la de ofrecer un modelo estándar de organización y acceso
a la información. La organización de la información se basa
en el denominado modelo relacional, que la estructura en
términos de tablas formadas por filas y columnas. Esta forma
de organización resulta, por lo general, bastante intuitiva y
de fácil aplicación a la mayoría de los casos de persistencia de
información que se presentan. Asimismo, ofrece un mecanis-
mo estándar de acceso basado en un lenguaje de consultas
denominado SQL que tiene sus fundamentos en un modelo
formal denominado «álgebra relacional». La universalización
y estandarización de este lenguaje, hace que cualquier pro-
gramador que conozca el lenguaje estándar pueda utilizar
cualquier base de datos relacional con independencia del pro-
ducto comercial que la implemente (existen dialectos de SQL
e implementaciones que aumentan la sintaxis, pero todos los

17

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

productos deben implementar la sintaxis nuclear del estándar


SQL).

Sin embargo, las necesidades en cuanto a persistencia de la


información cambiaron radicalmente con la aparición del big
data. Algunas de las necesidades que caracterizan este nuevo
contexto son:

• Necesidad de gestionar inmensas cantidades de datos. Por ejem-


plo, los datos que generan cada segundo los diferentes tipos
de sensores que se pueden encontrar en relojes inteligentes,
smartphones, sensores de contaminación, etc. Numéricamente,
superan a la capacidad habitual que gestionaban las bases de
datos relacionales de los sistemas de información anteriores al
big data.
• Necesidad de manipular datos muy heterogéneos que pueden
ser estructurados, semiestructurados o simplemente no pre-
sentar una estructura regular. Las bases de datos se caracte-
rizan precisamente por estar diseñadas para almacenar datos
que presentan una estructura regular acorde un esquema
definido. De hecho, el primer paso para crear una base de
datos relacional es definir su esquema, es decir, cómo van a
ser los datos que se van almacenar. Este esquema se supone
fijo y estable, permitiendo leves modificaciones a lo largo de
la vida de la base de datos. En este sentido, el diseñador espe-
ra encontrar una estructura fija y regular en los que se quiere
almacenar. Es por ello que para este nuevo contexto, el uso
de esquemas fijos no es una solución óptima pues tal como
se ha argumentado, los datos pueden ser estructuralmente
heterógeneos. Esto obligaría a estar realizando continuos
cambios en los esquemas de las bases de datos, introduciendo

18

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

en muchos casos anomalías como, por ejemplo, la existencia


de filas con muchas columnas vacías, dado que para algunos
datos no tendrían sentido.
• Necesidad de un procesamiento eficiente de la información.
En el contexto del big data, la información debe ser pro-
cesada de forma conjunta, con rapidez, y si es posible en
tiempo real.
Esta necesidad se debe principalmente a que el resultado
del procesamiento permitirá tomar decisiones que tienen aso-
ciadas una ventaja económica (por ejemplo, en una empresa,
ofrecer un producto a un determinado tipo de usuario o
realizar una inversión de acuerdo al resultado de predicción
obtenida). Además, el resultado del procesamiento será más
fiable cuantos más datos se estén usando en este, razón por la
cual se requiere el procesamiento conjunto de toda la infor-
mación disponible.
En este sentido, las bases de datos relacionales tampoco
ofrecen una solución óptima para esta necesidad. En primer
lugar, presentan el denominado problema de la «impedancia»
de la información. Este problema se refiere a las diferentes
estructuras de datos utilizadas para almacenar la información
en los lenguajes de programación y en las bases de datos
relacionales. Estas últimas solo permiten almacenar aquella
información que se corresponde con tipos de datos básicos
tales como enteros, booleanos, reales, etc. Sin embargo, los
lenguajes de programación utilizan estructuras de datos más
complejas y ricas para el almacenaje, tales como pilas, colas y
otras. Esto genera un problema en el tránsito de la informa-
ción de las bases de datos a los programas, y viceversa, dado
que requiere de un proceso de traducción. Así, cada vez que
se quiere almacenar información desde un programa en una

19

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

base de datos relacional habrá que descomponer la informa-


ción estructurada en los tipos de datos básicos definidos en el
esquema de aquella.
Igualmente, se produce el problema en sentido inverso
cuando se quiere almacenar información procedente de
un sistema de persistencia en una estructura de datos
de un programa. Si se considera que, en el contexto del
big data, el número de datos que se manipulan es enorme,
entonces estas operaciones de traducción suponen una carga
de trabajo que hacen muy ineficiente el uso de las bases de
datos relacionales. En segundo lugar, se tiene el problema del
escalado del procesamiento. Tal como se ha descrito ante-
riormente, el número de datos que es necesario gestionar en
el contexto del big data es enorme y tienen un crecimiento
exponencial. Esta situación influye directamente en las nece-
sidades en cuanto a capacidad de procesamiento de la infor-
mación de las herramientas utilizadas.
Esencialmente, existen dos formas de escalar la capaci-
dad de procesamiento: escalado vertical y escalado horizon-
tal. El escalado vertical se basa en el uso de máquinas con
capacidad de procesamiento cada vez más potentes. Así,
si una de ellas no cubre las necesidades de procesamiento,
lo que se hace es sustituirla por otra con mayor capacidad.
Esta solución no es económicamente muy rentable si el
tiempo durante el que se va a poder utilizar es pequeño,
situación que se da en este contexto. El crecimiento expo-
nencial de datos comentado con anterioridad hará que, en
un tiempo breve, la máquina quede obsoleta para las nuevas
necesidades.
El escalado horizontal se basa en conseguir las necesidades
de capacidad de procesamiento mediante la cooperación de un

20

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

conjunto de máquinas que trabajan en paralelo, denominado


clúster, cuya suma de capacidades de procesamiento cubren
la requerida. Esta solución presenta como principal ventaja el
hecho de que es sostenible económicamente. Las máquinas
que se utilizan en un clúster normalmente son mucho más
baratas, pues presentan menos prestaciones que en el caso del
escalado vertical (no se pretende conseguir toda la necesidad
de procesamiento con una única máquina), de manera que
cuando se requiere más capacidad de procesamiento, basta
con añadir nuevas máquinas. En cualquier caso, económica-
mente, será más barato.
El uso del modelo de escalado horizontal también tiene
una implicación importante en cuanto a la organización de la
información. En el caso del escalado vertical, la información
se encuentra almacenada en la única máquina utilizada en este
modelo. Sin embargo, en el escalado horizontal, la informa-
ción se encuentra distribuida y replicada entre las diferentes
máquinas que forman el clúster, de manera que el procesa-
miento se realiza de manera distribuida. En este sentido, el
escalado horizontal ofrece otra característica no presente en
el escalado vertical, que es la alta fiabilidad.
Si se usa el escalado vertical y la máquina utilizada falla, el
sistema dejará de funcionar, dado que toda la información y
la capacidad de procesamiento se encuentra en esa máquina.
Sin embargo, en el escalado horizontal, si una máquina falla,
el sistema no tiene porque dejar de funcionar, dado que la
información se encuentra distribuida y replicada entre las
diferentes máquinas que forman el clúster. Esto asegura que
el sistema se mantendrá en funcionamiento en caso de averías
de elementos del clúster, haciéndolo independiente de las
máquinas concretas que lo forman.

21

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

El principal problema que se presenta en cuanto al esca-


lado horizontal y su uso con bases de datos relacionales, es
que estas no están diseñadas para ejecutarse en clústers. Su
ejecución en este tipo de entornos presenta un gran número
de problemas difíciles de resolver tales como la implemen-
tación de operaciones de tipo JOIN, el aseguramiento de la
consistencia de la información ante operaciones concurren-
tes o la distribución de las filas de una tabla en las diferentes
máquinas del clúster. Aunque se han creado soluciones de
bases de datos relacionales para su ejecución en clúster, el
uso de las mismas ha demostrado que su rendimiento y efi-
ciencia no son demasiado buenos para este tipo de entornos
distribuidos.

Las limitaciones presentadas anteriormente propiciaron que


algunas empresas decidieran desarrollar sistemas alternativos al
modelo relacional que se ajustaran mejor a las nuevas necesida-
des impuestas por el fenómeno big data.
Concretamente fueron dos, Google y Amazon, las primeras
en proponer dos sistemas de almacenamiento de la informa-
ción basados en el uso de clústeres y que no seguían el modelo
relacional. Se trata de las bases de datos Big Tables de Google y
Dynamo de Amazon. Ambos casos permiten procesar grandes
cantidades de datos en ambientes distribuidos basados en el uso
de clústeres, y donde la información no se estructura de acuerdo
al modelo relacional.
Este primer hito supuso el punto de partida para el desarro-
llo de un conjunto de diferentes modelos de bases de datos que
tenían en común no utilizar el modelo relacional como apoyo
para organizar la información y en la mayoría de los casos estar
diseñadas para ejecutarse en entornos distribuidos.

22

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

A estas bases de datos se las ha denominado bases de datos


NoSQL.
Resulta difícil hablar de tipos de bases de datos NoSQL
dado que los diferentes modelos propuestos no son puros, es
decir, comparten algunas características. Sin embargo, obvian-
do aquello que es común en todas ellas, existe una categori-
zación mayoritariamente aceptada de acuerdo al modelo de
organización de la información propuesto en las bases de datos
que diferencia los siguientes tipos:

• Bases de datos clave-valor: Riak, Redis, Dynamo, Voldemort.


• Bases de datos orientadas a documentos: MongoDB, CouchDB.
• Bases de datos basadas en columnas: Cassandra, Hypertable,
HBase, SimpleDB.
• Bases de datos de grafos: Neo4j, Infinite Graph.

3. Características comunes de las bases de datos


NoSQL

Tal como se comentaba en el punto anterior, las bases de


datos NoSQL presentan algunas características comunes tales
como:

• En la mayoría de los casos nacieron dentro del contexto de


proyectos de código abierto.
• El lenguaje de consultas que utilizan para recuperar la infor-
mación no es SQL. En muchos casos, son lenguajes adapta-
dos a la forma en que se encuentra organizada la información
(al diferir el modelo relacional basado en tablas con filas y

23

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

columnas, no es aplicable el lenguaje SQL). Sin embargo, hay


algunas bases de datos NoSQL que han mantenido algunas
características de SQL como es el caso de la base de datos
Cassandra, que utiliza el lenguaje CQL que presenta algunas
similitudes con aquel.
• La mayoría de las bases de datos NoSQL están diseñadas
para ejecutarse en ambientes distribuidos basados en el uso
de clústeres de máquinas. Aunque no todas ellas cumplen esta
característica, como es el caso de las bases de datos orientadas
hacia grafos.
• Una característica común a las bases de datos NoSQL es su
aproximación a la consistencia de la información. Existe un
teorema denominado CAP que establece que si se consideran
las propiedades de consistencia de la información, su disponi-
bilidad y la tolerancia a la partición con respecto a la capa de
datos de un sistema de información, entonces solo es posible
que se mantengan dos de estas propiedades a la vez.
Esto significa que una capa de datos solo podrá pre-
sentar alguna de las siguientes combinaciones de propie-
dades: disponibilidad-tolerancia de partición (esta combi-
nación tiene que renunciar a la consistencia de la informa-
ción), disponibilidad-consistencia (esta combinación tiene que
renunciar a la tolerancia de partición que afectará la la cantidad
de datos que la capa de datos puede manejar) y tolerancia de la
partición-consistencia (esta combinación tiene que renunciar
a la disponibilidad).
En este sentido, un cambio importante en las bases de datos
NoSQL se refiere a la aproximación de la consistencia. En las
bases de datos relacionales se cumplían las propiedades ACID
(atomicity, consistency, isolation, durability). Estas propiedades repre-
sentan un sistema con una capa de datos que presenta consis-

24

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

tencia-disponibilidad. Así, la atomicidad se refiere a que en una


transacción todas las operaciones se completan o ninguna será
completada; la coherencia se refiere a que la base de datos se
encontrará en un estado consistente durante el inicio y final
de una transacción y no puede dejar ese estado; el aislamiento
se refiere a que no habrá interferencia entre las transacciones
concurrentes y la durabilidad se refiere a que una vez que
se comprometa una transacción, los efectos de esta se man-
tendrán permanentes.
Sin embargo, en las bases de datos NoSQL se cumplen
las propiedades BASE (basically available, soft state, eventually
consistent ). Estas propiedades representan un sistema con una
capa de datos que presenta tolerancia a la partición-disponibi-
lidad. Así, básicamente disponible significa que garantiza una
respuesta a una solicitud incluso si los datos están obsoletos, el
estado flexible se refiere a que cuando se produce un cambio
en los datos en uno de los elementos del sistema donde se
encuentran replicados, los datos en el resto de réplicas no cam-
bian de forma síncrona, sino que este cambio se produce de
forma asíncrona, y eventualmente consistente se refiere a que
debido a la naturaleza distribuida de los nodos, puede ocurrir
que en un momento determinado el sistema no sea consistente
pero con el paso del tiempo se volverá consistente.
• Las bases de datos NoSQL no tienen un esquema fijo. Se trata
de una de las principales características que las diferencian de
las bases de datos relacionales.

En el mundo relacional, lo primero que hay que hacer antes


de crear una base de datos es definir el esquema de datos que
indica cómo van a estar organizados, qué tablas se necesitan,
qué columnas tiene cada tabla y qué tipo de datos son, y como

25

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

se relacionan las diferentes tablas entre sí. Una vez definido el


esquema se pueden introducir los datos, pero no antes. El esque-
ma se podrá modificar levemente a lo largo de la existencia de
la base de datos aunque no es probable que sufra sufra muchas
variaciones, dado que se espera que los datos que se almacenen
sean uniformes y respondan a la organización representada en el
esquema.
Sin embargo, en el modelo NoSQL no existen esquemas,
sino que se pueden introducir directamente los datos y estruc-
turarse de diferentes formas (aunque siempre conforme al
modelo del tipo de base de datos NoSQL elegido). Cuando se
está en un ambiente en el que no se puede garantizar la uni-
formidad de los datos como es el caso del big data, el modelo
relacional basado en esquemas de definición estables es poco
óptimo, dado que para cada nuevo tipo de datos que no coin-
cida con la estructura inicial, habrá que ir adaptando de forma
dinámica el esquema.
El problema planteado tiene como consecuencia la introduc-
ción de anomalías tales como las denominadas tablas dispersas
(aquellas en las que existen muchas filas con columnas que con-
tienen valores nulos). Además, esta situación tiene consecuencias
directas sobre el mantenimiento propiamente dicho de la base
de datos. La no existencia de un esquema presenta tanto ventajas
como desventajas.
Una de sus principales ventajas es la flexibilidad, dado que se
adapta muy bien en proyectos en los que no se conoce a priori
toda la información que va a ser necesario almacenar o que
requiere poder ir cambiando estas necesidades de forma dinámi-
ca (tanto por adicción como por eliminación de información).
En este sentido, la no necesidad de esquema facilitará almacenar
en cada instante solo la información que se requiere.

26

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

Como principal desventaja se tiene la necesidad que existe


en las aplicaciones de conocer determinadas características de la
estructura de los datos almacenados. Esto se refiere a los nom-
bres de los campos de información o los tipos de los datos. En el
modelo relacional, toda esta información se encontraba descrita
en el esquema de datos, de manera que las aplicaciones podían
acceder a este para consultarlo.
En un modelo sin esquemas, se hace necesaria la definición
de un esquema implícito en el código de las aplicaciones, donde
quedará reflejada esta información. Esto introduce una serie
de problemas. En primer lugar, el esquema implícito será muy
sensible a cambios que se produzcan en los datos almacenados
(cualquier cambio modificará a su vez el código de las aplica-
ciones que explotan esos datos). En segundo lugar, muchas de
las tareas que realiza el sistema de gestión de bases de datos
de forma transparente al programador tales como asegurar que
los datos introducidos cumplen una serie de requisitos (por
ejemplo que los datos eran de un tipo determinado), en un
sistema sin esquemas deben ser controladas directamente por
el programador a través del código. En tercer lugar, si se desea
conocer si existen determinados tipos de datos almacenados,
será necesario consultar el esquema implícito de la aplicación
(si el esquema implícito está bien estructurado será una tarea
fácil, de lo contrario puede ser una tarea bastante compleja). En
cuarto lugar, la no existencia de un esquema en la base de datos,
hace que la tarea de saber cuál es la mejor forma de recuperar o
almacenar los datos de una forma eficiente recaiga en el progra-
mador y no en el sistema de gestión de estas. En quinto lugar, la
no existencia de esquema, complica las tareas de validación de
los datos que se introducen y se modifican en sistemas en los
cuales varias aplicaciones están explotando los mismos datos.

27

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

Esta tarea recae nuevamente en el programador. Además, en


este último caso, aparece un peligro adicional que es el cambio
del propio esquema de organización de la información.
Tal como se ha argumentado anteriormente, en los modelos
sin esquemas, aparecen esquemas implícitos en los códigos de
las aplicaciones que explotan los datos. Así, si varias aplicacio-
nes explotan los mismos datos, podría ocurrir que los cambios
producidos por una de ellas al añadir o eliminar datos influyeran
directamente en los esquemas implícitos definidos en el código
de las otras aplicaciones. El control de esta situación se vuelve
complejo, pues habría que controlar que los cambios que realizan
cada aplicación no afecta a las restantes.
Esencialmente, se puede concluir que el principal cambio que
se produce del uso al no uso de esquemas de definición de la
información es la traslación de responsabilidades. Así, muchas de
las tareas que los sistemas de gestión de bases de datos realizaban
de forma transparente al programador, ahora serán responsabi-
lidad de este. Como contrapartida, el programador consigue fle-
xibilidad en cuanto al tipo de información que puede almacenar,
libertad para realizar cambios en la estructura de la información
que almacena, y la garantía de almacenar solo aquella informa-
ción que necesita en cada momento.

4. Bases de datos NoSQL orientadas hacia


agregados

Los tipos de bases de datos NoSQL orientadas a documen-


tos, a familias de columnas y las de tipo clave-valor comparten
un modelo general de datos (aunque después cada una de ellas

28

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

presente sus diferencias que las hacen particulares). En este sen-


tido, se habla de bases de datos orientadas hacia agregados. Un
agregado, desde el punto de vista de la información, está forma-
do por datos con diferente complejidad estructural, así pueden
contener listas u otras estructuras más elaboradas como registros
relacionados de información.
Desde el punto de vista de la manipulación de los datos y la
gestión de la consistencia de la información, la base de datos
tratará a los agregados como la unidad mínima de información
que es capaz de gestionar. En este sentido, las operaciones que
se realicen sobre un agregado serán atómicas y, de hecho, la inte-
racción con la base de datos se realiza en términos de agregados
(se generan y consumen agregados en cada operación con la base
de datos).
Realmente, este concepto de agregación no es del todo nuevo,
dado que también se encuentra presente en las bases de datos
relacionales. En ellas, el agregado estaría constituido por las filas
de la tabla que almacenan la información y, de hecho, la base
datos interacciona consumiendo y generando filas. Sin embargo,
existen algunas diferencias:

1) En primer lugar, la complejidad estructural de la informa-


ción que es capaz de almacenar una fila frente a un agregado.
La fila es una colección de valores de tipos básicos, y no admite
estructuras de información complejas tales como listas, registros
o anidamiento de información.
2) Las filas de una tabla, en general, están relacionadas con
filas de otras tablas. En el caso de los agregados, aunque pudie-
ran existir relaciones con otros agregados, estas no son explí-
citas y no impiden que cada uno se pueda manipular de forma
independiente.

29

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

Este hecho tiene implicaciones importantes en cuanto a la


ejecución de las bases de datos en entornos distribuidos basados
en el uso de clústeres. En este sentido, el concepto de agregado
es utilizado como la unidad que se distribuye y se replica en
los nodos de un clúster de máquinas, puesto que tal como se
ha comentado, es autocontenido e independiente del resto de
agregados.
Se puede observar que esto no ocurre con las filas, puesto que
las relaciones de dependencia que existen entre filas de diferentes
tablas harían necesario tenerlas en cuenta cuando se distribuyera
y se replicara la información.
3) En general, la estructura de la información que se almacena
no se corresponde con una fila de una tabla. En muchos casos,
la información que se desea modelar para almacenar en una base
de datos, no se corresponde con una colección de datos de tipos
básicos (que es lo que representa una fila), sino que se correspon-
de con un conjunto de datos que están estrechamente relaciona-
dos mediante estructuras complejas de información.
Este hecho tiene dos implicaciones importantes. Por una
parte, si se utiliza el modelo relacional para almacenar la informa-
ción, el diseñador debe realizar un proceso de descomposición de
esta para eliminar la estructura que presentan los datos y poderla
describir en términos de tuplas de datos básicos, perdiendo las
relaciones directas entre ellos. Estas relaciones se reconstruyen
mediante las dependencias que existen entre las tablas que for-
man la base de datos, aunque no son explícitas. Sin embargo, en
el caso de los agregados, la modelización es prácticamente direc-
ta, pues al admitir una mayor riqueza de estructuras de datos de
diferente complejidad para almacenar la información, se facilita
el proceso de almacenamiento de la información sin tener que
descomponerla.

30

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

La segunda implicación que tiene este hecho se centra en el


tipo de consultas que se facilitan cada modelo. En el caso del
modelo relacional, la descomposición de la estructura de la infor-
mación, y el ocultamiento de las relaciones directas, hacen que la
información se represente de una forma neutral que facilita rea-
lizar consultas de cualquier tipo. Los datos no están preparados
para consultarse de una forma concreta, si no que pueden ser
consultados de diversas formas al no estar atados por las estruc-
turas que los relacionaba. En cambio, en un modelo orientado
hacia agregados, las dependencias de información se mantienen
intactas, influyendo en el tipo de consultas que se pueden reali-
zar. Así, habrá consultas que se podrán hacer de una manera más
óptima que otras. Es por ello que, desde el punto de vista del
diseño de una base de datos, se deben desarrollar los agregados
pensando en el tipo particular de consulta que se va a realizar
(con el objetivo de facilitar ese tipo de consulta). Otra implica-
ción directa de este hecho, es que en un modelo de agregados
habrá tantos tipos como tipos de consultas diferentes se quieran
realizar. No se espera resolver todos los tipos de consultas con
un único tipo de agregado. En cambio, en el modelo relacional
con un único modelo se pueden resolver todas las consultas que
se deseen (la dificultad de realizar una consulta se traslada a la
dificultad de crear la sentencia SQL correspondiente).
Con el objetivo de fijar ideas y poder comparar ambas apro-
ximaciones, se va a mostrar un ejemplo de modelización. Así,
considérese que se desea almacenar información de los clientes
de un banco y de los productos que tienen contratados. De un
cliente se desean mantener los datos personales tales como nom-
bre, apellidos, dirección, DNI, correo electrónico, etc. Asimismo
se desea conocer información sobre las sucursales del banco con
las que opera (normalmente será una pero podría darse el caso de

31

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

que fuera más de una). Por último, se desea conocer información


de todos los productos financieros que mantiene contratados
con el banco tales como tipo de producto, cantidad de dinero
asociada, plazos y sucursal en la que se ha contratado.
La información descrita podría modelarse tanto usando un
modelo relacional como usando un modelo orientado hacia
agregados. En el primer caso, haciendo un análisis simplista de la
información que se desea modelar, probablemente serían nece-
sarias las siguientes tablas. Una tabla para almacenar los datos
personales de cada cliente, otra para almacenar las direcciones,
dado que habría que contemplar el caso de que un cliente tuviera
varios domicilios, una tabla para almacenar la información de
una sucursal y una última para almacenar los productos financie-
ros contratados por los clientes. Este último caso, tendría diseños
alternativos como, por ejemplo, tablas diferentes por cada tipo
de producto que ofrece el banco, de manera que cada una solo
contuviera específicamente la información de los clientes que
han contratado determinado producto.
Tal como se puede observar en este modelo, las relaciones de
agregación entre los datos han desaparecido, se tienen por un
lado todos los datos personales, por otro lado las direcciones,
etc. En este sentido, para mantener relacionada la información en
cada una de las tablas antes mencionadas, será necesario introdu-
cir en cada una de ellas columnas que representen claves ajenas.
Sin embargo, el tipo de relación que permite establecer las claves
ajenas entre los datos no permite diferenciar entre relaciones de
agregación de información y entre relaciones de información
que no son de agregación (se puede deducir, por ejemplo, que
un cliente tiene asociadas una o más direcciones, o que un clien-
te tiene relación con una o más sucursales, pero no se puede
reconstruir como es la agregación original de la información).

32

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo I. Introducción a las bases…

En este sentido, se dice que las bases de datos relacionales son


ignorantes de las agregaciones. La principal implicación es que el
desconocimiento de cómo se encuentra agregada la información
dificulta la distribución de los datos, pero sin embargo, permite
ver los datos desde diferentes perspectivas. Por tanto es una
buena elección cuando se conoce a priori como se va a consultar
la información.
Si se optara por modelar el problema usando agregados,
existirían varios tipos de soluciones. Así, una posible solución
sería considerar dos tipos de agregados: clientes y productos.
Un agregado «cliente» podría almacenar los datos personales, las
direcciones del cliente, la información de las sucursales en las que
tiene productos contratados, así como una lista de estos produc-
tos con las particularidades de cada contrato (dinero contratado
en el producto, fecha de apertura, sucursal donde se contrató,
etc). Y un agregado «producto» podría almacenar toda la infor-
mación de un producto contratado por un cliente concreto, es
decir, datos personales, direcciones del cliente, sucursal donde se
contrató… así como toda la información particular del producto
contratado (dinero invertido, fecha de apertura, etc).
Conviene observar varios aspectos acerca de este diseño. En
primer lugar, este permite la repetición de datos (así, por ejemplo,
los datos personales o la información de las sucursales se repiten
en ambos agregados, situación que no se daría en un modelo rela-
cional). En segundo lugar, la estructura de cada agregado influye
directamente en el tipo de consulta que facilita. Así, por ejemplo,
si se consideran los agregados de tipo cliente, la consulta natural
que facilita podría ser recuperar todos los productos que tiene con-
tratado un cliente en el banco, o recuperar todas las sucursales en
las que tiene contratado un producto financiero. De igual forma,
el agregado «producto» permite recuperar fácilmente información

33

https://dogramcode.com/bases-de-datos
© Editorial UOC  Introducción a las bases de datos NoSQL

sobre  un producto  concreto contratado  por  un  cliente  en  parti-


cular.  Sin  embargo,  si  se  plantean  consultas  como,  por  ejemplo, 
recuperar toda la información de los clientes  que han contratado 
un tipo concreto de producto financiero o recuperar toda la infor-
mación de los clientes que han contratado algún producto en una 
sucursal determinada, el proceso de obtención del resultado no se 
podría hacer consultando un único agregado. 
Ambos casos requieren realizar un recorrido por cada  uno de 
los agregados para obtener la información correspondiente, lo cual 
en  términos  computacionales  lo  hace  ineficiente  (esencialmente 
habría que hacer un bucle donde se fuera comprobando en  cada 
agregado si un cliente ha contratado o no el producto). 
Esto  no  quiere  decir  que  no  se  pueda  resolver  ese  tipo  de 
consultas con un modelo de agregación, sino que cada agregado 
está preparado para facilitar un tipo de consulta concreta. Así, las 
consultas planteadas con anterioridad se podrían resolver crean-
do  un  agregado  con  la  estructura  de  la  información  adecuada 
para la  consulta (es decir,  un  agregado  de tipo  «producto»  que 
contuviera la información de todos los clientes que han contra-
tado ese tipo de producto,  de forma que en una única consulta 
del agregado se recuperaría la información buscada). 
En el  modelo  por agregación  es necesario saber  previamen-
te  cómo  se  van  a  realizar  las  consultas,  de  forma que  estos  se 
puedan  diseñar para  facilitarlas.  No existe un  único  modelo  de 
agregación que cubra todas las posibles consultas, o un modelo 
mejor que otro, todos son válidos, pero cada uno será adecuado 
para  un  caso  concreto  de  acceso  a  la  información.  Asimismo, 
hay que tener en cuenta que los agregados tienen un significado 
asociado con respecto  a la  forma en la  que las  aplicaciones los 
utilizan que va más allá de posibles relaciones lógicas que puedan 
existir entre los datos. Por otro lado, es importante destacar que 

34
© Editorial UOC Capítulo I. Introducción a las bases…

el modelo de agregación facilita la ejecución de una base de datos


en un clúster, dado que representa la información que debe ser
manipulada de forma conjunta y que, por tanto, deberá encon-
trarse en una misma máquina. Es decir, los agregados ayudan a
diseñar la estructura del clúster.
Por último, hay que tener presentes las necesidades de atomi-
cidad de las operaciones que se realizan. En este sentido, en estos
modelos solo es posible asegurar la atomicidad a nivel de agrega-
dos (si es necesario hacerlo sobre múltiples agregados entonces
habrá que hacerlo vía código). Es por ello que un criterio de
diseño de los agregados serán las necesidades de atomicidad de
las operaciones que tengan que realizarse sobre la información.

5. Bases de datos NoSQL documentales

Las bases de datos documentales son un tipo de base de datos


orientada hacia agregados donde el agregado es una estructura
que se denomina genéricamente documento. Un documento es
equivalente a alguna de las estructuras de datos que existen en
los lenguajes de programación tales como registros, diccionarios,
o tablas hash. En este sentido, ofrece una gran versatilidad para
almacenar muchos de tipos de datos.
Los documentos y sus contenidos se pueden manipular
mediante lenguajes de consultas similares a SQL. De esta forma
se pueden crear consultas en base a condiciones sobre el conte-
nido del documento, y recuperar partes del mismo. Asimismo,
es posible definir índices basados en su contenido.
Sin embargo, presenta limitaciones en cuanto a los tipos y
estructuras de datos almacenar. Así, los documentos solo admi-

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

En el  modelo relacional, las filas se utilizan como unidad  de 


almacenamiento porque aumentan el rendimiento de las escritu-
ras.  Sin  embargo, en situaciones en las que no se  van a realizar 
muchas escrituras y  lo que se  requiere son lecturas de determi-
nadas columnas con muchas filas a la vez, es más óptimo utilizar 
como unidad de almacenamiento grupos de columnas que con-
tienen las filas que deben ser leídas. 
Esta  unidad  de  almacenamiento  se  denomina  «familias  de 
columnas»,  y  las  bases  de  datos  que  lo  implementan  se  deno-
minan «bases de datos orientadas hacia columnas». Por tanto, el 
modelo subyacente a este tipo de bases de datos se fundamenta 
en almacenar datos en columnas en vez de en filas. Cada columna 
tiene que ser parte de una única familia, y la columna actúa como 

2  La opacidad  de la  información constituye  una  ventaja  si se  compara  con las 


bases  de  datos  documentales  donde  existen  limitaciones  (impuestas  por  las 
estructuras  de datos  admitidas por  el modelo)  en cuanto  a la  información  que 
puede ser almacenada. Por otro lado, estas limitaciones ofrecen como  ventaja la 
flexibilidad en el acceso a la información. 

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

En  este sentido,  se  describen sus  principales  características  y  las 


nociones básicas para poder empezar a trabajar con ella.

2. Principales características

Algunas de  las  principales  características  presentes  en  Redis 


son:

•  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

Para trabajar con los  ejemplos que  se van  a presentar  en las 


secciones siguientes, se debe ejecutar el  servidor de Redis, y los 
comandos se deberán introducir a través del cliente de 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

Una  diferencia  importante  de  Redis  con  respecto  a  otras 


bases  de datos es la imposibilidad  de plantear consultas  sobre 
el contenido de los valores asociados a una clave. El contenido 
de  los  valores  permanece  oculto  para  Redis.  En  este  sentido, 
las claves son tratadas como elementos de primer orden, dispo-
niendo para ellas de una gran variedad de posibles operaciones. 
En cambio, los valores son elementos secundarios que  solo se 
almacenan.
En Redis, todos los datos se almacenan en memoria, existen 
varias  formas  de  gestionarla.  La  primera  consiste  en  realizar 
copias  periódicas  en  disco  de  todo  lo  que  hay  almacenado 
teniendo en cuenta las claves que hayan cambiado. Para ello se 
usan directivas de la forma «Si N claves han cambiado enton-
ces  almacenar  la  base  de  datos  cada  T segundos» (de  hecho, 
por defecto, existe una directiva que indica que se debe  alma-
cenar  la base de  datos cada  60 segundos  si se han  producido 
cambios  en 1000  o más  claves).  Otro mecanismo consiste en 
actualizar un archivo en el que cada vez que una clave cambia, 
se actualiza solamente lo que haya cambiado.  Por último, otra 
opción consiste en gestionar la persistencia utilizando un nodo 
esclavo.

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

A continuación, se  van  a comentar  algunos  de  los comandos 


más utilizados. Primero nos centraremos en el comando KEYS, el 
cual devuelve todas las claves almacenadas en la base de datos que 
encajan con un patrón dado. En el ejemplo de la figura 9 se mues-
tra la invocación del comando KEYS con el símbolo *, que repre-
senta  cualquier  valor,  de  manera  que  devuelve  como  resultado 
todas las claves almacenadas en ese momento en la base de datos.

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

Figura 11. Invocación de redis-benchmark para medir el rendimiento  de 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

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.

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

Por  su  parte,  el  comando  MGET  permite  recuperar  varios 


valores  a la  vez  indicando las  claves  separadas  por espacios  tal 
como se muestra en la figura 3.

Figura 3. Uso del comando MGET

Fuente: elaboración propia

Existen  un  conjunto  de  comandos  diseñados  para  gestio-


nar  exclusivamente  contadores.  Se  trata  de  INCR,  INCRBY, 
INCRFLOATBY, DECR o DECRBY que  tienen  como función 
incrementar  o disminuir  el  valor numérico  asociado  a una  clave. 
Relacionado con el comando INCR están los comandos INCRBY 
y INCRBYFLOAT. Estos comandos, respectivamente, incremen-
tan el valor asociado a una clave por un número entero o un núme-
ro real especificado  (no tiene por qué ser 1). Al igual que INCR, 

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

Por  último,  el  comando  BITOP  permite  realizar  operacio-


nes  entre  los  claves  que  tienen  asociados  conjuntos  de  bits. 
El  comando  requiere  que  se  especifique  una  operación  entre 
conjuntos de bits, una clave de destino, y una lista de claves que 
tengan  asociado un  conjunto  de bits.  Las  operaciones  disponi-
bles son OR, AND, XOR  y NOT. En la figura 7 se muestra un 
ejemplo  donde se  realiza una  operación de  tipo OR sobre  dos 
claves que tienen asociadas conjuntos de bits.

Figura 7. Uso de BITOP

Fuente: elaboración propia

Algunos de  los  casos  donde  se  pueden  utilizar  cadenas  son 


los siguientes:

•  Implementación  de  mecanismos  de  caché  para  almacenar 


texto o datos binarios tales como páginas html, respuestas de 
API, vídeos o imágenes.

62
© Editorial UOC  Capítulo III. Estructuras de datos en Redis

•  Un sistema  de caché  con expiración automática. Para  ello se 


pueden usar cadenas que tengan asociadas claves con expira-
ción automática..
•  Implementación de contadores.

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

En  segundo  lugar,  se  encuentran  los  comandos  HGET  y 


HMGET, que  permiten respectivamente  recuperar el  valor  aso-
ciado a una clave de un hash determinado y recuperar los valores 
de un conjunto de claves especificadas separadas por espacios. En 
la figura 13 se muestra un ejemplo de uso de ambos comandos.

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

HDEL Elimina los campos especificados del hash almacenado en la clave.

HEXISTS Retorna 1 si el hash contiene el campo indicado o 0 si no lo 


contiene o la clave no existe.

HGET Retorna el valor asociado con el campo del hash almacenado.

HGETALL Retorna todos los campos y valores del hash almacenado.

HINCRBY Incrementa el número asociado al campo del hash almacenado 


por el incremento especificado. Si la clave no existe, se crea una 
nueva clave para contener al hash. Si el campo no existe, el valor 
se establece en 0 antes de que se realice la operación.

HINCRBYFLOAT Actúa igual que HINCRBY pero con incrementos reales.

HKEYS Retorna todos los nombres de los campos del hash almacenado.

HLEN Retorna el número de campos que hay en el hash almacenado.

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.

HSTRLEN Devuelve la longitud del valor asociado al campo en el hash


almacenado en la clave. Si la clave o el campo no existen, se 
devuelve 0.

HVALS Retorna todos los valores que hay en el hash almacenado en la 


clave
Fuente: elaboración propia

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.

SPOP Elimina y devuelve n elementos al azar del conjunto almacenado 


en la clave.

SRANDMEMBER Devuelve n elementos al azar del conjunto almacenado en la 


clave. Si el número es positivo, los elementos serán distintos, y si 
el número es negativo, los elementos pueden ser repetidos.

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

Algunos ejemplos  de uso  en el  que  son útiles los  conjuntos 


son los siguientes:

•  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

En  segundo  lugar,  existen  una  serie  de  comandos  que 


permiten  recuperar  elementos  de  un  conjunto  ordenado. 
Se  trata  de  los  comandos  ZRANGE,  ZRANGEBYLEX, 
ZRANGEBYSCORE, ZREVRANGE, ZREVRANGEBYLEX, 
y ZREVRANGEBYSCORE. El comando  ZRANGE, dado un 
intervalo  de  posiciones,  devuelve  los  elementos  del  conjunto 
cuyas posiciones se encuentran dentro del intervalo dado consi-
derando que los elementos se encuentran ordenados de menor a 
mayor. Los valores del intervalo empiezan en cero, y pueden ser 
números  negativos,  en  cuyo  caso  representan  desplazamientos 
desde  el  final,  siendo  -1  el  último  elemento.  Este  comando  se 
puede invocar  con la opción WITHSCORES, en este otro caso 
devolverá como resultado los elementos del conjunto selecciona-
do junto a los valores que tienen asociados. De forma similar, se 
tiene el comando ZREVRANGE, que actúa igual que ZRANGE 
pero  en  orden  inverso,  dado  que  los  elementos  se  consideran 
ordenados  de mayor a menor.  El resto de comandos tienen  un 
funcionamiento similar. En la figura 21 se muestra un ejemplo de 
uso de los comandos descritos. 

Figura 21. Uso de ZRANGE Y ZREVRANGE

Fuente: elaboración propia

75
© Editorial UOC Introducción a las bases de datos NoSQL

También es posible utilizar los valores asociados a los ele-


mentos en el proceso de recuperación. Así, se tienen el comando
ZSCORE, que retorna el valor de un elemento dado, ZRANK
que retorna la posición de un elemento dentro del conjunto
ordenado considerando que los elementos se encuentran orde-
nados de menor a mayor empezando desde 0 y, por último,
ZREVRANK que retorna la posición de un elemento dentro del
conjunto ordenado considerando que los elementos se encuen-
tran ordenados de mayor a menor empezando desde 0. En la
figura 22 se muestra un ejemplo.

Figura 22. Uso de ZSCORE, ZRANK y ZREVRANK

Fuente: elaboración propia

Por último, se puede eliminar un elemento de un conjunto


ordenado usando el comando ZREM. En la figura 23 se muestra
un ejemplo de uso de este comando.

76

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo III. Estructuras de datos en Redis

Figura 23. Uso de ZREM

Fuente: elaboración propia

En la tabla 5 se muestran los principales comandos relaciona-


dos con los conjuntos ordenados y su significado.

Tabla 5. Comandos asociados a los conjuntos ordenados


Comando Significado

ZADD Agrega los pares miembro-puntuación especificados


al conjunto ordenado. Si un miembro ya existe, la
puntuación se actualiza y el elemento se vuelve a insertar
en la posición correcta para garantizar el orden correcto.

ZCARD Devuelve la cardinalidad del conjunto ordenado

ZCOUNT Devuelve el número de elementos del conjunto ordenado


con una puntuación entre min y max. Los argumentos
min y max tienen el mismo significado que el descrito
para ZRANGEBYSCORE.

ZINCRBY Incrementa en n la puntuación del miembro especificado


en el conjunto ordenado. Si el miembro no existe en
el conjunto ordenado, entonces se agrega el incremento
como su puntuación y si la clave no existe entonces se
crea un nuevo conjunto con el miembro especificado
como su único miembro. Acepta números reales y
negativos (para disminuir la puntuación).

ZINTERSTORE Calcula la intersección entre varios conjuntos especificados


y almacena el resultado en un conjunto destino
también especificado en el comando. En el comando, es
obligatorio indicar el número de conjuntos que se desea
intersecar antes de especificar los conjuntos y el resto
de argumentos opcionales que pueden aparecer en este
comando. La puntuación resultante de un elemento es
la suma de sus puntuaciones en los conjuntos ordenados
donde existen. Las opciones WEIGHT y AGGREGATE
funcionan como en la unión.

77

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

Comando Significado

ZLEXCOUNT Devuelve el número de elementos del conjunto


ordenado con un valor entre min y max usando el orden
lexicográfico para elementos con la misma puntuación.
Los argumentos min y max tienen el mismo significado
que el descrito para ZRANGEBYLEX.

ZRANGE Devuelve los elementos del conjunto ordenado


especificados en un intervalo cerrado. Los elementos
se consideran ordenados de menor a mayor. El orden
lexicográfico se utiliza para elementos con igual
puntuación. Tanto start como stop son índices basados
en cero, y pueden ser números negativos para indicar
desplazamientos desde el final, siendo -1 el último
elemento. Los índices fuera de rango no producirán
un error. Es posible pasar la opción WITHSCORES para
devolver las puntuaciones de los elementos junto con los
elementos.

ZRANGEBYLEX Devuelve todos los elementos del conjunto ordenado


con un valor entre min y max. El argumento LIMIT se
puede usar para obtener solo un rango de los elementos
coincidentes. Se usan los caracteres «(» y «[« para indicar
inclusión o no precediento a los elementos, y los símbolos
«+» y «-« para indicar límites infinitos.

ZRANGEBYSCORE Devuelve todos los elementos del conjunto ordenado con


una puntuación entre min y max (incluyendo elementos
con una puntuación igual a min o max). Los elementos se
consideran ordenados de menor a mayor.
Los elementos que tienen la misma puntuación se
devuelven en orden lexicográfico. El argumento LIMIT
opcional se puede usar para obtener solo un rango
de los elementos coincidentes. El argumento opcional
WITHSCORES hace que el comando devuelva el
elemento y su puntuación. Min y max pueden ser -inf y
+ inf, y se puede especificar un intervalo abierto con «(»
precediendo al elemento.

ZRANK Devuelve la posición de un miembro en el conjunto


ordenado, suponiendo las puntuaciones ordenadas de
menor a mayor (se comienza desde 0)

ZREM Elimina los miembros especificados del conjunto


ordenado si existen.

ZREMRANGEBYLEX Elimina todos los elementos del conjunto ordenado


con un valor entre min y max. Los argumentos min y
max tienen el mismo significado que el descrito para
ZRANGEBYLEX.

78

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo III. Estructuras de datos en Redis

Comando Significado

ZREMRANGEBYRANK Elimina todos los elementos del conjunto ordenado


con rango entre el inicio y el fin. Tanto el inicio como
el fin son índices basados en 0 y pueden ser números
negativos que indican desplazamientos que empiezan en
el elemento con la puntuación más alta (-1 es el elemento
con la puntuación más alta) .

ZREMRANGEBYSCORE Elimina todos los elementos del conjunto ordenado con


una puntuación entre min y max (incluyendo elementos
con una puntuación igual a min o max). Los elementos se
consideran ordenados de menor a mayor.
Los elementos que tienen la misma puntuación se
devuelven en orden lexicográfico. Los argumentos min
y max tienen el mismo significado que el descrito para
ZRANGEBYSCORE.

ZREVRANGE Funciona igual que ZRANGE salvo que los elementos se


consideran ordenados de mayor a menor, y los elementos
de igual puntuación se consideran en orden lexicográfico
inverso.

ZREVRANGEBYSCORE Funciona igual que ZRANGEBYSCORE salvo que los


elementos se consideran ordenados de mayor a menor, y
los elementos de igual puntuación se consideran en orden
lexicográfico inverso.

ZREVRANK Devuelve la posición de un miembro en el conjunto


ordenado, suponiendo las puntuaciones ordenadas de
mayor a menor (se comienza desde 0).

ZSCORE Devuelve la puntuación del miembro en el conjunto


ordenado. Si el miembro no existe o la clave no existe, se
devuelve nil.

ZUNIONSTORE Calcula la intersección de los conjuntos y almacena


el resultado en el conjunto destino. Es obligatorio
proporcionar el número conjuntos a unir antes de pasar
los conjuntos y el resto de argumentos opcionales. La
puntuación resultante de un elemento es la suma de sus
puntuaciones en los conjuntos ordenados donde existen.
La opción WEIGHTS permite especificar un factor de
multiplicación para cada conjunto ordenado de entrada,
y la opción AGGREGATE permite especificar cómo se
agregan los resultados (suma, mínimo o máximo). Si el
destino ya existe, se sobreescribe.
Fuente: elaboración propia

79

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

Algunos ejemplos de uso en el que son útiles los conjuntos


ordenados son los siguientes:

• Construir una lista de espera en tiempo real para un servicio


al cliente.
• Mostrar una tabla de clasificación de un juego en línea masivo
que muestra a los mejores jugadores, usuarios con puntuacio-
nes similares o las puntuaciones de amigos.
• Construir un sistema de autocompletar usando millones de
palabras.

7. HyperLogLog

No se trata de una estructura de datos, sino de un algorit-


mo que usa aleatorización para obtener una aproximación del
número de elementos únicos que existen en un conjunto. En
este sentido, tiene un error estándar del 0.81 %. El algoritmo es
aplicable a cualquier conjunto con independencia del número de
elementos que contenga.
Existe un conjunto de comandos asociados al mismo. En pri-
mer lugar, el comando PFADD, que permite añadir una o más
elementos a un HyperLogLog devolviendo como resultado el
valor 1 si la cardinalidad ha cambiado y el valor 0 en caso contra-
rio. En la figura 24 se muestra un ejemplo.

Figura 24. Uso de PFADD

Fuente: elaboración propia

80

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo III. Estructuras de datos en Redis

En segundo lugar, el comando PFCOUNT puede recibir


como argumentos una clave o un conjunto de claves de tipo
HyperLogLog. Si recibe una única clave, entonces retorna la
cardinalidad aproximada del conjunto representado por la clave
y, si recibe un conjunto de claves, devuelve la cardinalidad apro-
ximada de la unión de todos los elementos únicos de los conjun-
tos representados por esas claves. En la figura 25 se muestra un
ejemplo de uso del comando.

Figura 25. Uso de PFADD

Fuente: elaboración propia

Por último, encontramos el comando PFMERGE, que dada


una clave destino y una o más claves de tipo HyperLogLog,
devuelve como resultado un conjunto en el que se encuentran
mezclados los elementos de ambos HyperLogLogs y le asocia el
resultado a la clave destino especificada. En la figura 26 se mues-
tra un ejemplo de su uso.

Figura 26. Uso de PFMERGE.

Fuente: elaboración propia

Algunos ejemplos de uso en el que son útiles del tipo


HyperLogLog son los siguientes:

81

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

• Contar el número de usuarios únicos que visitan un sitio web.


• Contar el número de términos distintos que fueron buscados
en un sitio web, en un momento preciso.
• Contar el número de hashtags distintos que fueron utilizados
por un usuario.
• Contar el número de palabras distintas que aparecen en un
libro.

82

https://dogramcode.com/bases-de-datos
© Editorial UOC Capítulo III. Estructuras de datos en 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. Ddocumentation. https://redis.io/documentation.

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

En este capítulo se van a tratar tres aspectos fundamentales en


la gestión de la base de datos Redis. Por una parte se comentarán
los mecanismos de aseguramiento de la persistencia que garanti-
zan la durabilidad de los datos. Y por otra parte, se trataran dos
de las características comunes a las bases de datos NoSQL: la
replicación y el particionamiento. La combinación de estas herra-
mientas asegura el acceso rápido y eficiente a los datos.

2. Persistencia

Redis almacena la información en memoria de manera que si


se produce un fallo en esta se pierden los datos. Para resolver este
problema, existen dos mecanismos de gestión de la persistencia:

2.1. Redis Database (RDB)

Un archivo .rdb es un formato binario que almacena una


instancia de Redis en un momento temporal determinado. Se
caracteriza por:

85

https://dogramcode.com/bases-de-datos
© Editorial UOC Introducción a las bases de datos NoSQL

• Su representación interna es similar a la representación en


memoria.
• Está optimizado para soportar lecturas y escrituras rápidas.
• Se puede programar la creación de estos archivos en diferen-
tes intervalos de tiempo ( horas, días, semanas o meses).
• Un único archivo .rdb permite restaurar una instancia de Redis
completa. En este sentido es útil para realizar backups y poder
restaurar cualquier conjunto de datos en cualquier momento.

Existen dos comandos para crear un archivo .rdb. El coman-


do SAVE lo crea de forma inmediata, pero bloquea el servidor
durante la creación, y el comando BGSAVE hace la misma ope-
ración, pero se ejecuta en segundo plano en un proceso secunda-
rio de manera que el servidor no queda bloqueado. En este caso
el proceso principal no realiza ninguna operación de E/S, y si se
reciben peticiones de escrituras, será el proceso hijo el encargado
de copiar los cambios producidos por estas.
La configuración de la periodicidad de la creación de los
archivos se realiza en el archivo de configuración de Redis (redis.
conf que se puede encontrar en el directorio del código fuente)
mediante la inserción de reglas del tipo:

save número_segundos número_cambios

La regla significa que si en X segundos se han producido Y ope-


raciones de escritura entonces, se creará un archivo de tipo .rdb.
Algunas características:

• Este sistema de reglas proporciona flexibilidad en cuanto a la


frecuencia en la que se crean los archivos, sin embargo no es

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

stop-writes-on- Puede tomar el valor  yes o no . Si toma el valor  yes indica que 


bgsave-error el sistema debe parar de aceptar escrituras si el último proceso 
de creación falló. El sistema acepta escrituras si el proceso de 
creación termina con éxito.

rdbcompression Indica si se debe comprimir o no el archivo rdb. Puede tomar 
el valor  yes o  no.

rdbchecksum Puede tomar el valor  yes o no Si toma el valor yes, se 


almacena una marca al final del archivo .rdb de manera que 
cuando se va a cargar el archivo se genera la misma marca y 
se comprueba si son iguales. En caso de ser iguales se permite 
la carga.

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

2.2. Append-only file (AOF)

Se trata de una alternativa al sistema de archivos .rdb. El fun-


cionamiento de AOF consiste en que cada vez que se ejecuta
un comando sobre la base de datos, este es almacenado en un
archivo no binario denominado AOF (append-only file), de manera
que si es necesario realizar una restauración de datos, lo que se
hace es ejecutar todos los comandos almacenados en el archivo
en el mismo orden para reconstruir el estado original de la base
de datos.
Algunas características:

• En caso de corrupción del archivo, este puede ser recuperado


mediante una herramienta de reparación denominada redis-
check-aof.
• Al ser un archivo no binario, su contenido puede ser editado
y leído.
• Este sistema afecta al rendimiento y al espacio en disco.
• Se puede optimizar el archivo en una versión más pequeña
usando el comando BGREWRITEAOF. En caso de pro-
blemas en la optimización, el archivo original se mantiene
intacto.

Existen un conjunto de directivas que permiten configurar los


archivos AOF tal como se muestra en la tabla 2.

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

appendonly Toma el valor  yes o  no. Sirve para habilitar 


o deshabilitar el archivo AOF. Por defecto está 
deshabilitado.

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.

no-appendfsync-on- Toma el valor  yes o  no. Si la política  appendfsync


rewrite está configurada a  everysec o  always y se está 
ejecutando el proceso fsync( ) en segundo plano o 
realizando una reescritura del archivo AOF, entonces 
se puede bloquear el sistema de entrada/salida. Solo 
se debería usar cuando existan problemas de latencia. 
Por defecto toma el valor  no.

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

maestro).  Se va  a considerar el  ejemplo anterior,  y se va  a hacer 


caer la instancia que se ejecuta en el puerto 5555. A continuación, 
se configura  una de  las instancias que  actúa como esclavo  como 
nuevo maestro y los restantes esclavo se configuran para que repli-
quen al nuevo maestro. En la figura 3 se muestra el proceso.

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

Inicialmente  Redis no  fue diseñado para distribuir  sus  datos 


entre  diferentes  instancias,  sin  embargo  hay  situaciones  donde 
un único servidor no es suficiente, como cuando la cantidad de 
datos que hay que almacenar es superior a la memoria disponible 
de Redis. 
Redis admite el particionamiento de los datos, es decir, la divi-
sión de los datos en varias instancias, donde cada una solo con-
tendrá un subconjunto de las claves definidas. Sin embargo, exis-
ten dos tipos  de particionamiento:  horizontal y vertical. En este 
contexto,  el  particionamiento horizontal significa  la distribución 

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.

b) Por  hash. Se utiliza una función hash que permite conver-


tir  las claves  en  un número  y  después  almacenar  los datos en 
diferentes instancias. Para ello se aplica la función hash a la clave 
de Redis, se divide el valor obtenido por el número de instan-
cias y  se  usa  el resto de  esa  división  como índice  de acceso  a 
aquellas disponibles. La  eficiencia de este método depende  de 
la eficiencia de la función hash que se haya elegido.  Asimismo, 
es  preferible  disponer  de  un número  de instancias  impar con 

95
© Editorial UOC  Introducción a las bases de datos NoSQL

el  objetivo  de  minimizar  colisiones.  Por  último,  este  método 


de partición  puede producir  una falta de memoria  caché  si se 
cambia el número de instancias.

La implementación  del  particionado  puede  ser  responsabili-


dad de diferentes elementos:

•  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:

•  Imposibilidad de realizar  operaciones  que requieran  de múl-


tiples  claves  (intersección  de  dos  conjuntos  almacenados  en 
diferentes instancias).
•  No  se  pueden  realizar  transacciones  que  involucren  múlti-
ples  claves. Asimismo,  la  implementación  de  estas  se  realiza 
mediante programación directa del particionamiento.
•  Cuando se usa particionamiento, la manipulación de datos es 
más compleja.
•  La granularidad de partición es la clave del particionamiento, 
por  lo  que  no  es  posible  fragmentar  un  conjunto  de  datos 
con una sola clave enorme como un conjunto ordenado muy 
grande.

96
© Editorial UOC  Capítulo IV. Persistencia, replicación y particionamiento

Redis  se puede  usar como  almacén  de datos  o como  caché, 


pero tiene implicaciones importantes:

a) Si se utiliza como almacén de datos,  una clave  dada siem-


pre debe  asignarse al mismo nodo de Redis. En este sentido, el 
número de nodos debe ser fijo y no puede variar, y en caso con-
trario será necesario un sistema que pueda rebalancear las claves 
entre los nodos cuando se agregan o eliminan los nodos.
b) Si  se  utiliza  como  caché,1 si  un  nodo  determinado  no 
está  disponible,  entonces  se  usa  un  nodo  diferente,  alterando 
el mapeo  de instancias  a claves. En este sentido, es fácil escalar 
hacia arriba o hacia abajo.

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:

•  Redis Cluster.2 Ofrece  particionamiento automático y de alta 


disponibilidad. Es una mezcla entre el sistema de enrutado de 
consultas y el particionamiento del lado del cliente.
•  Twemproxy.3 Es un proxy desarrollado por Twitter que soporta 
particionamiento  entre  múltiples  instancias  de  Redis,  con  la 
expulsión  opcional  del  nodo  si  un  nodo  no  está  disponible 
(esto cambiará el mapa de instancias de claves, por lo que debe 
usar esta función solo si está usando Redis como caché). No es 
un punto único de falla, ya que se pueden iniciar varios proxies
y  configura  los  clientes  para  que  se  conecten  al  primero  que 
acepte  la conexión.  Por  tanto, Twemproxy  es una  capa  inter-
media entre clientes e instancias de Redis que maneja de forma 
confiable la partición evitando las complejidades a los clientes.
•  Clientes  soportando  hashing consistente.  Se  trata  de  usar 
un  cliente  que  implementa  la  partición  del  lado  del  cliente 
mediante hashing consistente u otros algoritmos similares. Hay 
varios clientes  de redis  con soporte para hashing consistente, 
en particular Redis-rb4 y Predis.5

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

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.
Nelson, J. (2016). Mastering Redis. Packt Publishing Ltd.
Redis. Documentation. https://redis.io/documentation

99
© Editorial UOC  Capítulo V. Otros aspectos del uso de Redis

Capítulo V
Otros aspectos del uso de Redis

1. Introducción

En  este  capítulo  se  van  a  mostrar  otras  características  de 


las  que  dispone  Redis  tales  como  su  sistema  de  mensajería,  el 
sistema  transaccional,  el  lenguaje  de  script LuA  y  se  describirá 
brevemente  cómo  poder  acceder  a  Redis  desde  el  lenguaje  de 
programación Python.

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

cuando  se haya  cancelado la  suscripción de todos los canales y 


patrones.
A continuación, en la tabla 1, se muestran los comandos más 
importantes relacionados con el sistema de mensajería.

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.

El sistema  de  transacciones dispone  del  comando  WATCH, 


que permite mantener el seguimiento de determinadas claves, de 
manera  que si se detectan  cambios en alguna antes  de la  ejecu-
ción del comando  EXEC,  se aborta la transacción  y se retorna 
una respuesta  null indicando que la transacción falló. Este meca-
nismo es  muy útil para  gestionar condiciones  de carrera.  En  el 
siguiente ejemplo se controla la variable ejemplo:

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

valor entre la llamada a WATCH  y la llamada a EXEC,  la tran-


sacción fallaría.
Observemos que:

•  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

El funcionamiento básico de la  canalización consiste  en que 


un cliente puede enviar varias solicitudes al servidor sin esperar 
las respuestas, y al final podrá leer las respuestas en un solo paso.
Cuando se envían comandos utilizando la canalización, el ser-
vidor debe encolar las respuestas utilizando la memoria. Es por 
ello que si necesita enviar una gran cantidad de comandos con la 
canalización, es mejor hacerlo en lotes con un número razonable 
de ellos.
Observemos que:

•  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:

eval  “return  {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}”  2 


clave1 clave2 valor1 valor2
1) “clave1”
2) “clave2”
3) “valor1”
4) “valor2”

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:

•  Lua tiene un  solo tipo numérico,  números Lua.  No hay dis-


tinción  entre  enteros  y  flotadores.  Por  lo  tanto,  siempre  se 
convierte  los  números  Lua  en  enteros  eliminando  la  parte 
decimal del número, si corresponde. Para devolver un número 
real desde Lua, se debe devolver como una cadena.
•  Es  complicado  tener  valores  nulos  dentro  de  un  array Lua, 
pues  el  proceso  de  conversión  de  Redis  se  detiene  si  se 
encuentra un valor nulo. 

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:

•  redis.error_reply  (error_string) que devuelve  una tabla  con 


el campo de error que contiene una cadena especificada en la 
función.
•  redis.status_reply (status_string) devuelve una tabla con un 
campo que contiene la cadena especificada en la función.

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.

Los  scripts están  sujetos  a  un  tiempo  de  ejecución  máximo 


(cinco segundos de forma predeterminada) que se puede modi-
ficar  cambiando  el  parámetro  lua-time-limit de  configuración 
que afecta el tiempo máximo de ejecución. Para ello se utiliza el 

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.

Por  último,  observemos  que  cuando  se  ejecuta  EVALSHA 


en  el  contexto  de  una  solicitud  canalizada,  se  debe  garantizar 
el  orden  de  ejecución  de  los  comandos.  En  este  sentido,  si 
EVALSHA  devuelve  un  error  NOSCRIPT,  el  comando  no  se 
podrá volver a ejecutar nuevamente. Para evitar estos problemas, 
se recomienda:

•  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

pass  password. Una  vez configurado el  password, cada  vez que 


se vaya a ejecutar un comando será necesario utilizar el comando 
AUTH  comando.  En la  figura 3 se  muestra un ejemplo  donde 
se configura un password. A continuación, para ejecutar cualquier 
comando hay que autenticarse con el comando AUTH.

Figura 3. Configuración de un password

Fuente: elaboración propia

Se puede conocer el  password configurado  usado  el comando 


CONFIG get requirepass.

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

Si se  quiere ejecutar  la canalización en modo  no transacción 


entonces hay que desactivarlo explícitamente cuando se crea:

pipe=r.pipeline(transaction=False)

También  es  posible  usar  el  mecanismo  de  publicación/sus-


cripción. Para  ello se invoca el  método  pubsub( ), y se usan los 
métodos  subscribe(canal) y  unsubscribe( ) para  suscribirse  y 
eliminar  una  suscripción  a  un  canal  respectivamente.  Cuando 
se  está  suscrito  a  un  canal  se  pueden  recuperar  los  mensajes 
mediante el método get_message( ). El mensaje recuperado está 
formado por la siguiente información:

•  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:

•  Usando  el  método  get_message integrado  en  un  bucle.  De 


esta manera, si hay datos disponibles para leer, get_message ( )

125
© Editorial UOC  Introducción a las bases de datos NoSQL

los  leerá, formateará  el  mensaje  y  lo  devolverá.  Y si  no hay 


datos  para  leer,  get_message  ( ) devolverá  inmediatamente 
Ninguno. 

while True:
mensaje= p.get_message( )
if mensaje:
# Hacer algo con el mensaje

•  Usando el método  listen ( ). Se  trata de un generador  que se 


bloquea hasta que un mensaje esté disponible. 

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

Para  implementar  una  red  social  del  tipo  propuesto  será 


necesario  gestionar  información  de  unas  determinadas  enti-
dades.  En primer lugar,  se necesita  almacenar información  de 
cada  usuario  registrado  en  la red y  de  la actividad  que  lleva a 
cabo  en  esta. De  igual  forma,  se  necesitará  almacenar  toda  la 
información  acerca  de  un  mensaje  publicado,  como  quién  lo 
publicó,  cuándo,  y  otros  datos.  Una  información  básica  que 
es necesaria gestionar son  los mensajes que han publicado  los 
usuarios  a  los  que  estamos  siguiendo.  Cuando  un  usuario  se 
conecta  a  su cuenta,  lo  que  espera  ver  es  la  lista  de  mensajes 

129
© Editorial UOC  Introducción a las bases de datos NoSQL

más  recientes  publicados  por  los  usuarios  a  los  que  sigue. 


Igualmente querrá  ver  los  últimos mensajes  que  ha publicado 
él mismo y se deberán mantener  las relaciones de seguimiento 
(seguidores y seguidos) entre usuarios.
A continuación, se van a discutir las necesidades de persisten-
cia  de cada  una de las  entidades mencionadas, cuál  es el  mejor 
tipo  de  datos  para  almacenar  la  información  asociada  a  dicha 
entidad y cómo se puede implementar  la creación de estas enti-
dades y su almacenamiento en Redis utilizando como lenguaje de 
programación Python.

2.1.  Usuario

En  general,  sería  interesante  almacenar  la  siguiente  infor-


mación  sobre un  usuario de una  red social  similar a  Twitter: el 
usuario, un nombre, el número de seguidores, el número de per-
sonas a las que sigue, el número de mensajes que ha publicado, 
un  identificador  y  cuándo  se  registró  (podría  almacenarse  más 
información de la que aparece aquí listada). 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 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( ))

Al  recuperar  los  mensajes  almacenados  en  la  clave  ZSET, 


estos  se obtienen en orden  cronológico  inverso a  como fueron 
introducidos.
De  forma  similar,  cuando  un  usuario  visita  el  perfil  de  otro, 
espera encontrarse  con  los mensajes más  recientes  enviados  por 
este.  Se trata  de un  caso particular del  que  estamos  tratando. Es 
por ello que, para resolverlo, se utiliza el mismo tipo de clave y la 
misma función que se ha implementado. Sin embargo la función 
se invocará con el valor «mensajespropios» para el argumento de 
«mensajesrecientes»  que  representan  los  mensajes  más  recientes 
que han sido publicados por dicho usuario. Hay que tener en cuen-
ta que el problema de gestionar los dos conjuntos de mensajes, se 
resuelve nombrando cada conjunto con valores de clave diferente, 
«recientesseguidores» para los mensajes más recientes  de las per-
sonas que son seguidas, y «recientespropios» para hacer referencia 
a los mensajes más recientes de un usuario.

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

#Se  añade  la  relación de  seguir al  otro usuario  en el 


correspondiente ZSET
pipeline.zadd(fkey1, otro_uid, tiempo)
#Se añade la relación de ser seguido por el usuario al 
correspondiente ZSET
pipeline.zadd(fkey2, uid, tiempo)
#Se recupera el tamaño de los ZSETs correspondiente
pipeline.zcard(fkey1)
pipeline.zcard(fkey2)
#Se  recupera  los  1000  mensajes  más  recientes  del 
nuevo usuario seguido.
pipeline.zrevrange(‘profile:%s’%otro_uid,0,999, 
withscores =True) 
#Se ejecuta la canalización.
siguiendo,  seguidores,  idmensajes_marcatemporal  = 
pipeline.execute( )[-3:]
#Se  actualizan  el  contador  del  número  de  usuarios 
seguidos en el HASH
pipeline.hset(‘user:%s’%uid, ‘siguiendo’, siguiendo)
#Se  actualizan  el  contador  del  número  de  usuarios 
seguidores en el HASH
pipeline.hset(‘user:%s’%otro_uid,  ‘seguidores’, 
seguidores)
#Se  comprueba  si  la  lista  de  pares  identificadores de 
mensajes y marcas temporales 
#recuperados del usuario que se sigue no es vacia
if idmensajes_marcatemporal:
#Se  guarda  en  la  lista  de  mensajes  recientes  de 
seguidores, los pares recuperados
pipeline.zadd(‘home:%s’%uid, **dict(contadores))

136
© Editorial UOC  Capítulo VI. Ejemplo de uso de Redis

#Se  actualizan  los  mensajes  de  la  lista  de  mensajes 


más recientes del usuario con los 
#1000 primeros mensajes más recientes
pipeline.zremrangebyrank(‘home:%s’%uid, 0, -900)
#Se ejecuta la canalización
pipeline.execute( )
return True

Observemos  que  la  función  realiza  las  siguientes  operacio-


nes:  añadir  los  identificadores  de  los  usuarios  a  los  conjuntos 
ZSET  de seguidores,  obtener  los  tamaños  de  los  conjuntos  de 
seguidores  y  de personas  seguidas,  recuperar  los  mensajes  más 
recientes  de  los  usuarios  seguidos  por  un  usuario,  actualizar la 
información del usuario almacenada en una clave de tipo HASH, 
y  actualizar  la  lista  de  mensajes  más  recientes  de  las  personas 
seguidas  por  un  usuario  con  los  mensajes  más  recientes  del 
nuevo usuario seguido.
De igual forma, cuando se deja de seguir a alguien habrá que 
deshacer  las  operaciones  realizadas:  eliminar  los  identificado-
res  de las  listas  de seguidores  y  personas  seguidas,  eliminar los 
mensajes más  recientes  del  usuario que  se  va  a  dejar  de  seguir 
de  la  lista  de  mensajes más  recientes  de  usuarios  seguidos por 
un usuario  y actualizar los contadores  de la  información de los 
usuarios  involucrados.  En  la  siguiente  función  se  implementan 
estas acciones.

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

#Se  comprueba que  el  usuario que  va a  dejar de  ser 


seguid, está en la lista de 
#usuarios seguidos.
if not conex.zscore(fkey1, otro_uid):
return None
#Se declara una canalización.
pipeline = conex.pipeline(True)
#Se  elimina  el  usuario que  se  estaba  siguiendo de  la 
lista de seguidos del usuario.
pipeline.zrem(fkey1, otro_uid)
#Se elimina el usuario seguidor de la lista de usuarios 
que siguen a un usuario.
pipeline.zrem(fkey2, uid)
#Se recupera el tamaño de los ZSETs correspondiente
pipeline.zcard(fkey1)
pipeline.zcard(fkey2)
#Se  recuperan  los  mi0  mensajes  más  recientes  del 
usuario que se va a dejar de ser 
#seguido.
pipeline.zrevrange(‘perfil:%s’%otro_uid,0, 999)
#Se ejecuta la canalización.
siguiendo,  seguidores,  mensajes  =  pipeline.execute( )
[-3:]
#Se  actualizan  el  contador  del  número  de  usuarios 
seguidos en el HASH
pipeline.hset(‘user:%s’%uid, ‘siguiendo’, siguiendo)
#Se  actualizan  el  contador  del  número  de  usuarios 
seguidores en el HASH
pipeline.hset(‘user:%s’%other_uid,  ‘seguidores’, 
seguidores)

138
© Editorial UOC  Capítulo VI. Ejemplo de uso de Redis

#Se  comprueba  si  la  lista  de  pares  identificadores de 


mensajes y marcas temporales 
#recuperados del usuario que se sigue no es vacia
if mensajes:
#Se  eliminan,  en  la  lista  de  mensajes  recientes  de 
seguidores, los pares recuperados
pipeline.zrem(‘home:%s’%uid, *mensajes)
#Se ejecuta la canalización.
pipeline.execute( )
return True

2.5. Almacenar mensajes de los seguidores

En las  funciones anteriores se  han consultado  los conjuntos 


de mensajes más recientes de los usuarios seguidos y del propio 
usuario.  Sin  embargo,  no  se  ha  descrito  como  mantener  estos 
conjuntos. A continuación se va a considerar esta situación. 
Cuando  un  usuario crea  un  mensaje,  éste se  almacena  tanto 
en el  conjunto  de mensajes más recientes  del usuario  como  en 
el  conjunto  de  mensajes  más  recientes  de  usuarios  seguidores. 
El primer caso no supone ningún problema computacional, sin 
embargo, en  el  segundo caso, habrá que  estudiar el  número  de 
seguidores que tiene un usuario, pues puede dar lugar a proble-
mas  de  eficiencia  y  de  procesamiento.  En  este  sentido,  según 
estudios estadísticos realizados por Twitter, solo un  1 % de sus 
usuarios  tienen  más de  mil seguidores.  Es  por  ello que  se  van 
a  tratar  dos  casos,  aquellos  usuarios  que  tienen  mil  seguidores 
o menos  y  aquellos que tienen  más de  mil seguidores.  Para los 
primeros, la actualización del conjunto de mensajes más recientes 

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

En  la  siguiente  función  se  implementa  la  actualización  del 


conjunto de mensajes más recientes de los usuarios seguidos por 
los seguidores.

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

Otra acción habitual que un  usuario de una  red social como 


Twitter  realizará  es  la  eliminación  de  mensajes.  Para  hacerlo, 
habrá que eliminarlo de los valores de la clave de tipo HASH que 
los almacena y se deberá actualizar el número de mensajes pos-
teados por un usuario, así como los conjuntos de mensajes más 
recientes tanto  del usuario como  de los usuarios  que lo siguen. 
En  la  siguiente  función  se  muestra  como  se  implementa  está 
operación.

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

En  este capítulo  se  ha presentado  un  ejemplo  de  aplicación 


de Redis. Tal como se ha mostrado, la riqueza de tipos de clave 
que ofrece permite, de una manera fácil y simple, implementar el 
modelo de datos que una red social como Twitter requiere para 
poder  funcionar.  Si  se  compara  en  líneas  de  código,  este  sería 
bastante más elevado si se utilizara como sistema de persistencia 
una  base  de  datos  relacional.  Por  ejemplo,  el  almacenamiento 
ordenado de la información,  o simplemente la  recuperación  de 
los datos requeriría de costosas consultas sobre las tablas.
Por otro lado, se puede observar que en el ejemplo expuesto 
se  han  implementado  las  funciones  más  básicas,  sin  embargo, 

143
© Editorial UOC  Introducción a las bases de datos NoSQL

existen  algunas  funciones  que  no  se  han  considerado  y  que 


podrían implementarse de una manera similar tales como:

•  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.

Cualquiera de estas  funciones podrían  ser implementadas  de 


una manera  simple usando funciones  y estructuras de informa-
ción semejantes.
En  la  siguiente  dirección  de  la  documentación  de  Redis, 
http://cort.as/-F2xX,  se puede  encontrar  otra implementación 
similar de la  red social Twitter  utilizando el  lenguaje PHP.  Esta 
red se denomina retwis, y existe tanto una demo online de demos-
tración en la dirección http://cort.as/-F2xb como el acceso libre 
al código PHP que implementa la red en la dirección http://cort.
as/-F2xe.

144
© Editorial UOC  Capítulo VI. Ejemplo de uso de Redis

Bibliografía

Carlson, J. L. (2013). Redis in action. Manning Publications Co.

145
© Editorial UOC  Conclusión

Conclusión

En  este  libro  se  ha  pretendido  realizar  una  introducción  a 


los  principales  conceptos  de  las  bases  de  datos  NoSQL,  y  su 
ilustración en un tipo concreto de la llamada familia de bases de 
datos de clave-valor. Este tipo de bases de datos se engloba  en 
las  denominadas  bases  de datos  orientadas hacia  agregados. Se 
caracterizan porque la unidad de almacenamiento es una entidad 
denominada  agregado  que  representa  una  estructura  de  datos 
compleja parecida a las estructuras que se gestionan en los len-
guajes de programación. 
En el caso concreto de las bases de datos de tipo clave-valor, 
el agregado es un valor opaco en el sentido de que su contenido 
no es accesible desde la propia base de datos. Es necesario recu-
perar el valor almacenado en esta a partir de una clave asociada 
al agregado, y ya desde fuera se puede acceder a dicho contenido. 
Este mecanismo puede parecer limitado en algún aspecto, como 
la imposibilidad de realizar consultas basadas en los contenidos 
de los agregados. Sin embargo presenta como ventaja la riqueza 
de  posibles  valores que  pueden  ser  almacenados.  Esta  caracte-
rística  permite  usar esta  base  de datos  en  muchos  ámbitos.  Es 
importante  destacar la  semejanza que tienen  este  tipo de bases 
de datos con las bases de datos documentales, las cuales pueden 
simular el  comportamiento de una base de datos de tipo clave-
valor aunque con la principal diferencia de que en las documen-
tales sí  se pueden  plantear  consultas  basadas en los  contenidos 
de los agregados.

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.

Con este libro aprenderás sobre:

bases de datos NoSQL; Redis; big data; análisis de datos;


bases de datos orientadas a agregados; particionamiento;
replicación; bases de datos clave-valor; Lua scripting;
almacenamiento no tradicional

Antonio Sarasa

Doctor en Informática por la Universidad

Complutense de Madrid, donde imparte

docencia. Sus áreas de investigación se

centran en la aplicación de las técnicas

de procesadores de lenguajes y compiladores

al desarrollo de aplicaciones.

https://dogramcode.com/bases-de-datos

También podría gustarte