Unas notas sencillas sobre publicación-suscripción en Redis, es la implementación de Redis de este patrón usando canales y clientes.
En Redis existen lo que se llama patrones de suscripción, que es una forma de suscribirse a varios canales a la vez que cumplan un patrón, este patrón está basado en el nombre (estilo glob), se soportan los siguientes:
? Para un solo carácter
* Para múltiples caracteres
[…] Caracteres alternos (h[ae]llo funciona con hello y hallo)
Publica el mensaje message a los N suscriptores del canal channel que se hayan suscrito a los M patrones de suscripción, devolverá el numero de clientes que han recibido el mensaje
Aunque KEYS y SCAN sirven para lo mismo (devolver todas las claves) tienen algunas diferencias.
KEYS
SCAN
Bloque hasta que termina
Usa un cursor para iterar, útil para producción
No es para producción
Devuelve una referencia a un grupo
Útil para depuración
Devolverá 0 o más claves por llamada
Keys vs Scan
Ejemplos
SET claves:ejemplo:clave1 valor_nuevo – Crea una clave de nombre claves:ejemplo:clave1 con valor valor_nuevo al no tener Redis espaciones de nombres suele ser interesante separar los elementos con «:» del elemento más general al específico SET claves:ejemplo:clave1 valor_nuevo NX – Crea la clave solo si no existía previamente (NX=No exist) SET claves:ejemplo:clave1 valor_nuevo XX – Crea la clave solo si exístia previamente SET claves:ejemplo:clave1 valor_nuevo EX 7200 – Crea la clave claves:ejemplo:clave1 que expirará en 7200 segundos SET claves:ejemplo:clave1 PX 50000 – Crea una clave que expirará en 50000 ms SET claves:ejemplo:clave1 EX 50 – Crea una clave que expirará en 50 s (igual que el anterior)
GET claves:ejemplo:clave1 – Devuelve el valor de esta clave, en este caso valor_nuevo
KEYS claves:ejemplo:cl* – Devuelve todas las claves que empiecen por cl*
SCAN 0 MATCH claves:ejemplo:cl* – Devuelve todas las claves que empiecen por cl* empezando desde el princpio 0 devolverá un nuevo valor que se usará para la siguiente llamada, por ejemplo la salido puede ser: 1) «14848» Entonces la siguiente llamada sería: SCAN 14848 MATCH claves:ejemplo:1* SCAN 14848 MATCH claves:ejemplo:1* 1000 – Indicamos que queremos buscar en bloques más grandes (1000)
Rendimiento
O(1): HDEL cuando borra un solo elemento, UNLINK, SCAN en una llamada O(N): HDEL cuando borra varios elementos, siendo N el número de elementos, UNLINK en su hilo siendo N el número de elementos, SCAN para la iteración completa siendo N el número de elementos en la colección O(M): HDEL cuando la clave eliminada contiene una estructura como lista, conjunto, conjunto ordenado o Hash, siendo M el número de elementos dentro de la esctructura
Hashes
Conjuntos de campos clave/valor.
Así como existe un comando para borrar campos (HDEL) no existe uno para añadir, tanto la creación como la adición de campos se hace con HSET
HMGET recomendado para pocas claves, si van a recuperarse muchas es mejor HSCAN
HSCAN hash:full 0 MATCH claves:ejemplo:cl* – Tiene el mismo efecto que SCAN para claves pero sobre el hash hash:full
Rendimiento
O(1): HSCAN en una llamada O(N): HGETALL (siendo n el número de campos), HSCAN para la iteración completa siendo N el número de elementos en la colección
Listas
Se pueden implentar como colas o como pilas añadiendo (PUSH) y quitando (POP) elementos de los extremos. Admite hasta 4 billones de elementos.
Devuelve los N elementos de la lista list desde el índice start (S) hasta stop(índice basado en 0) empezando por la izquierda si stop es negativo empezará desde la derecha
Elimina los N elementos de la lista list excepto los contenidos entre los índices start y stop (índice basado en 0) empezando por la izquierda y si stop es negativo contará desde la derecha
Elimina las count (M) primeras ocurrencias del elemento element en la lista de tamaño N key
O(M+N)
Lists
Ejemplos
Teniendo una lista a,b,c,d,e,f llamada list LTRIM list 0 4 Devuelve todos los elementos desde a hasta e LTRIM list 1 -2 Devuelve los elementos b,c,d,e (f es el elemento -1 y e es el elemento -2) LRANGE list 0 -1 Devuelve todos los elementos de la lista
Rendimiento
O(1): LPOP, RPUSH, LLEN O(s+n): LRANGE (donde s es la distancia al primer elemento y n el número total de elementos)
Teniendo un conjunto A = {A, b, C} y B = {a, b, C}: SDIFF A B – Devolverá la diferencia de conjuntos, los elementos que están en A y no están en en B, es decir «A» SSCAN set:full 0 MATCH claves:ejemplo:cl* – Tiene el mismo efecto que SCAN para claves pero sobre el hash hash:full
Rendimiento
O(N*M): SINTER, siendo N la cardinalidad del conjunto pequeño y M el número de conjuntos O(N): SDIFF y SUNION donde N es el número total de elementos de todos los conjuntos
Conjuntos ordenados
Una colección ordenada de elementos únicos, para ordenarlos a cada elemento se le asocia una puntuación (score) que será el valor usado para la ordenación. Si esta puntuación es igual se realiza un orden lexicográfico basado en el nombre del key. Útil para:
Elimina M elementos de key (tamaño N) entre los índices start y stop (índice basado en 0) empezando por la izquierda y si stop es negativo contará desde la derecha
Elimina M elementos de key (tamaño N) en el rango lexicográfico entre start y stop (índice basado en 0) empezando por la izquierda y si stop es negativo contará desde la derecha
Elimina M elementos de key (tamaño N) cuya puntuación esté entre start y stop (índice basado en 0) empezando por la izquierda y si stop es negativo contará desde la derecha
Realiza la union de numkeys conjuntos key1… y almacena el valor en destination
O(N)+O(M log(M))
Sorted Sets
Ejemplos
ZREMRANGEBYRANK list:cash9 -1 – Elimina desde el elemento 9 hacia la derecha, es decir, el último (j) ZRANGEBYSCORE list:cash (3 +inf – Devuelve los elementos que tenga un score superior a 3 (3 hasta el final de la lista +inf ZADD claves:ejemplo:clave1 30 value1 NX – Crea la clave solo si no existía previamente (NX=No exist) ZADDclaves:ejemplo:clave1 30 value1 XX – Actualiza la clave solo si exístia previamente ZADD claves:ejemplo:clave1 30 value1 CH – Devuelve solo los elementos que hayan cambiado, por defecto devuelve los creados ZADD claves:ejemplo:clave1 30 value1 INC – Se comporta como ZINCRBY ZRANGE claves:ejemplo 10 20 BYLEX – Devuelve los elementos con score entre 10 y 20, los que tengan el mismo score estarán ordenados lexicograficamente ZRANGE claves:ejemplo 10 20 REV – Devuelve los elementos en orden inverso ZRANGE claves:ejemplo 10 20 LIMIT 1 9 – Devuelve los elementos desde el 1 hasta el 19 (si count es negativo devuelve todos los elementos desde offset).
Rendimiento
O(N*K)+O(M*log(M)): ZINTERSTORE siendo N el conjunto más pequeño, K el número de conjuntos y M el número de elementos en el conjunto resultante
Bit data
Conjuntos de de bits, el offset se entiende como el desplazamiento dentro del mapa de bits de tamaño, por ejemplo un offset de 9 indicaría la novena columna de la primera fila quedando así 0000 0001 en un caso más general usaremos la fórmula offset = Y * MAX_WIDTH + X por lo que si quisiéramos marcar la primera fila de la novena columna en un mapa de tamaño N (=MAX_WIDTH) tendríamos: (suponemos un tamaño de N=20) offset = 1 * 20 + 9 = 29 y el y el mapa de bits sería 0000 0000 0000 0000 0000 000 0000 1, si juntamos las dos coordenadas (9,0) y (9,1) y lo apilamos en líneas de 20 (N) queda:
00000000000100000000 00000000000100000000
Offset se puede indicar también usando # en este caso Redis calcula la posición del bit dependiendo del tamaño del tipo, por ejemplo #1 para u8 sería el elemento 8*1 de esta forma se tiene un número de elementos cada uno con un valor y tamaño fijo.
Devuelve el número de bits a 1 en el mapa key a partir de offset
O(N)
BITFIELD key [get|set|incrby] type offset value [overflow wrap| sat|fail]
Devuelve (get) se establece (set) o incrementa (incrby) un valor value a un elemento type, definido como u para unsigned e i para signed seguido del tamaño en bits, por ejemplo u5, los comandos get and set se puede acumular en la misma instrucción bitfield
Busca en key el valor 0 o 1 según se indique, si se especifican dos valores indica un intervalo a buscar, en este caso el valor 0.
O(N)
Mapa de bits
Datos geoespaciales
Permite guardar datos usando coordenadas (latitud, longitud), se almacenan codificados en GeoHash (52 bits), se almacenan como un sorted set donde GeoHash es el score por lo que los mismos comandos de sorted set se pueden usar también aquí.
GEOADD key longitude1 latitude1 member … [longitudeN latitudeN]
Añade una ubicación name al conjunto key de N elementos usando la longitud y latitud especificada, si se le llama con los mismos datos actualizará la posición existente.
Devuelve los N sitios en el radio (byradius) o caja (bybox) indicado de los M existentes, usando como centro la longitud y latitud especificada o el ancho y alto, WITHDIST devuelve la distancia, WITHCOORD devuelve también las coordenadas, usando ASC se devolverán los resultados en orden empezando por la más cercana o viceversa usando DESC, se puede limitar el número de resultados a devolver con COUNT, unit es la unidad de medida a devolver: m (metros) km (kilometros) mi (millas) ft (pies).
Este comando es como GEOSEARCH pero almacena los resultados en el store indicado, si se usa la opción STOREDIST almacena los resultados en un conjunto ordenado con la distancia al centro desde el círculo o caja.
Hay varias opciones de instalar Redis, tanto en la nube como en local, así como un par de opciones interesantes de clientes para acceder a hacer consultas.
Cloud: Se puede usar cualquier proveedor cloud Azure, Amazon, etc.. o directamente el sistema de Redis que proporciona una opción gratuita.
Linux: Se puede compilar o instalar directamente, instrucciones aquí.
Docker: Como no podía ser de otra forma Redis también proporciona imágenes Docker.
Comandos de sistema
Una pequeña lista de comandos básicos de sistema:
DBSIZE
Devuelve el número de keys en la base de datos seleccionada
OBJECT ENCODING KEY
Devuelve el tipo de dato de key
Comandos básicos
Transacciones
Manejo de transacciones en Redis, Redis cumple ACID.
Detalles:
No se permiten transacciones anidadas.
DISCARD no ejecuta ningún comando, no existe el concepto de rollback porque la cola de comandos no se ejecuta hasta usar EXEC.
Redis implementa concurrencia optimista.
MULTI
Comienzo de una transacción
EXEC
Ejecuta la cola de comandos
DISCARD
Descarta los comandos
WATCH key
Observa una key, si esta cambia entonces no se ejecuta la transacción, este comando se ejecuta antes de MULTI, este comando es local no afecta a transaccciones de otros procesos
UNWATCH key
Deja de observar todas las keys, si la transacción es correcta se ejecuta un UNWATCH automático de todas las keys que se estuvieran observando