Introducción a la base de datos NoSQL Redis

Escrito por picodotdev el .
blog-stack gnu-linux planeta-codigo planeta-linux programacion
Comentarios

Redis es una de las bases de datos NoSQL en este caso de tipo clave-valor. Los valores pueden ser de diferentes tipos y tiene una amplia colección de operaciones disponibles para usar según el tipo de datos asociado a la clave.

Redis

Redis es una de las bases de datos para almacenar información de los conocidas como NoSQL. Almacena los datos en memoria por lo que es muy rápido y es usada como base de datos, como cache o broker de mensajes. Los datos no se almacenan en tablas como en los sistemas relacionales tradiciones RDBMS como PostgreSQL o MySQL sino en estructuras de datos como cadenas, hashes, listas, conjuntos, conjuntos ordenado con rangos, bitmaps, hyperloglogs e índices geoespaciales. Incorpora replicación, scripting con LUA, desalojo LRU, transacciones, diferentes niveles de persistencia en disco y alta disponibilidad con Redis Sentinel y paticionamiento con Redis Cluster.

El punto más crítico en el rendimiento en una aplicación suele estar en la base de datos relacional, dado que han de garantizar las propiedades ACID y almacenan grandes cantidades de datos en disco son lentas (comparativamente) además de presentar dificultades para escalar horizontalmente. Redis almacena los datos en memoria por lo que es significativamente más rápida que una base de datos relacional aunque con la limitación de no poder almacenar las grandes cantidades de datos medidos hoy en día en terabytes o TiB (1024 GiB) que podría almacenar una base de datos relacional. Para la necesidad de acceder datos de forma rápida, de cachear datos a los que acceder rápido, datos a los que se acceden frecuentemente, datos precalculados, hay grandes cantidades de escrituras o necesidad de escalar Redis es una opción a tener en cuenta.

Redis es un sistema de datos clave-valor en el que cada clave tiene asociado un tipo de datos y unos datos que almacena. Según el tipo de datos de la clave se pueden realizar diferentes operaciones o comandos de consulta.

Usando Docker se puede iniciar una instancia de Redis con un archivo descriptor del contenedor en formato yml y el comando docker-compose up. Redis al igual que otras bases de datos posee un shell de linea de comandos, redis-cli. Iniciada la instancia del contenedor y el servicio de Redis se puede iniciar una sesión de sh y con ella el shell.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$ docker-compose up
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
1f1ad19d64ce        redis:alpine        "docker-entrypoint..."   17 seconds ago      Up 15 seconds       0.0.0.0:6379->6379/tcp   redis_redis_1
$ docker exec -it 1f1ad19d64ce sh
/data # redis-cli 
127.0.0.1:6379> set string 'Hello World!'
OK
127.0.0.1:6379> get string
"Hello World!"
127.0.0.1:6379> sadd set string1 string2 string3
(integer) 3
127.0.0.1:6379> smembers set
1) "string3"
2) "string2"
3) "string1"
127.0.0.1:6379> zadd sortedSet 1 string1 2 string2 3 string3
(integer) 3
127.0.0.1:6379> zrange sortedSet 0 -1
1) "string1"
2) "string2"
3) "string3"
127.0.0.1:6379> rpush list string1 string2 string3
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "string1"
2) "string2"
3) "string3"
127.0.0.1:6379> hmset hash property1 string1 property2 string2 property3 string3
OK
127.0.0.1:6379> hgetall hash
1) "property1"
2) "string1"
3) "property2"
4) "string2"
5) "property3"
6) "string3"
127.0.0.1:6379> rename string hello
OK
127.0.0.1:6379> expire hello 10
(integer) 1
127.0.0.1:6379> type set
set
127.0.0.1:6379> keys *
1) "sortedSet"
2) "set"
3) "hash"
4) "list"
127.0.0.1:6379>
1
2
3
4
redis:
    image: redis:alpine
    ports:
        - 6379:6379

Hay multitud de clientes para los lenguajes de programación más populares y otros menos usados, en Java uno de los clientes más conocidos es Jedis. En el siguiente ejemplo un cliente Java se conecta a la instancia de Redis y lanza los varios comandos para almacenar cadenas, un set, set ordenados, lista, hash y algunas operaciones sobre claves. Este ejemplo desde Java realiza las mismas operaciones que las realizadas en el shell de Redis anterior.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package io.github.picodotdev.blogbitix.holamundoredis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import redis.clients.jedis.Jedis;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

@SpringBootApplication
public class Main implements CommandLineRunner {

    @Autowired
    private Jedis jedis;

    @Bean
    public Jedis buildJedis() {
        return new Jedis("localhost");
    }

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        jedis.del("string", "set", "sortedSet", "list", "hash", "hello");

        // Strings
        jedis.set("string", "Hello World!");
        System.out.printf("String: %s%n", jedis.get("string"));

        // Sets
        jedis.sadd("set", "string1", "string2", "string3");
        System.out.printf("Set: %s%n", jedis.smembers("set"));

        // Sorted sets
        Map<String, Double> sortedSet = new HashMap<>();
        sortedSet.put("string1", 1d);
        sortedSet.put("string2", 2d);
        sortedSet.put("string3", 3d);
        jedis.zadd("sortedSet", sortedSet);
        System.out.printf("SortedSet: %s%n", jedis.zrange("sortedSet", 0, -1));

        // Lists
        jedis.rpush("list", "string1", "string2", "string3");
        System.out.printf("List: %s%n", jedis.lrange("list", 0, -1));

        // Hashes
        Map<String, String> hash = new HashMap<>();
        hash.put("property1", "string1");
        hash.put("property2", "string2");
        hash.put("property3", "string3");
        jedis.hmset("hash", hash);
        System.out.printf("Hash: %s%n", jedis.hgetAll("hash"));

        // Keys
        jedis.rename("string", "hello");
        jedis.expire("hello", 10);
        System.out.printf("Type: %s%n", jedis.type("set"));
        jedis.del("hello");
        System.out.printf("Keys: %s%n",jedis.keys("*"));
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'

description = 'HolaMundoRedis'
version = '0.1'
sourceCompatibility = 1.8
targetCompatibility = 1.8

mainClassName = 'io.github.picodotdev.blogbitix.holamundoredis.Main'

buildscript {
    ext {
        springBootVersion = '1.5.4.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter'
    compile 'redis.clients:jedis:2.9.0'
}
1
2
3
4
5
6
7
String: Hello World!
Set: [string3, string2, string1]
SortedSet: [string1, string2, string3]
List: [string1, string2, string3]
Hash: {property2=string2, property1=string1, property3=string3}
Type: set
Keys: [sortedSet, set, list, hash]

Cada comando de Redis tiene una complejidad de tiempo ejecución, para obtener el mejor rendimiento hay que analizar los datos para almacenarlos en la estructura de datos adecuada de las que ofrece Redis junto con los comandos que son utilizados y su complejidad indicada en la documentación del comando en notación Big O. Redis solo es uno de los sistemas NoSQL, hay otros conocidos con MongoDB orientado a documentos o Cassandra híbrido entre clave-valor y tabular.

Para un conocimiento mucho más detallado de las posibilidades de esta base de datos el libro Mastering Redis o Redis in Action son un buen inicio.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando docker-compose up, ./gradlew run.