structures hmset hkeys hget data commands data-structures redis time-complexity atomicity

data structures - hmset - ¿Muestra valores atómicos de la estructura de datos de Redis atómicamente?



redis hmset (6)

Use LRANGE con LTRIM en una tubería . La tubería se ejecutará como una transacción atómica. Su preocupación sobre WATCH , EXEC no será aplicable aquí porque está ejecutando el LRANGE y LTRIM como una transacción sin la capacidad de que cualquier otra transacción de otros clientes se interponga entre ellos. Pruébalo.

¿Hay una estructura de datos Redis, que permita la operación atómica de popping (obtener + eliminar) múltiples elementos, que contiene?

Hay conocidos SPOP o RPOP, pero siempre devuelven un solo valor. Por lo tanto, cuando necesito primero N valores de set / list, necesito llamar al comando N-times, que es caro. Digamos que el conjunto / lista contiene millones de elementos. ¿Hay algo así como SPOPM "setName" 1000 , que devolvería y eliminaría 1000 elementos aleatorios del conjunto o RPOPM "listName" 1000 , que devolvería 1000 elementos de la lista más a la derecha?

Sé que hay comandos como SRANDMEMBER y LRANGE, pero no eliminan los elementos de la estructura de datos. Se pueden eliminar por separado. Sin embargo, si hay más clientes leyendo desde la misma estructura de datos, algunos elementos se pueden leer más de una vez y algunos se pueden borrar sin leer. Por lo tanto, mi pregunta es acerca de la atomicidad.

Además, estoy bien si la complejidad del tiempo para tal operación es más costosa. Dudo que sea más costoso que emitir N (digamos 1000, N del ejemplo anterior) solicitudes separadas al servidor de Redis.

También sé sobre soporte de transacciones por separado. Sin embargo, esta frase de los documentos de Redis me desanima a usarla para procesos paralelos que modifican el conjunto (lectura destructiva de él):
Al usar WATCH, EXEC ejecutará comandos solo si las claves observadas no se modificaron, lo que permite un mecanismo de verificación y configuración.


Creo que deberías ver el apoyo de LUA en Redis. Si escribe un script LUA y lo ejecuta en redis, se garantiza que es atómico (porque Redis tiene un subproceso único). No se realizarán consultas antes del final de su secuencia de comandos LUA (es decir: no puede implementar una tarea grande en LUA o Redis se volverá lenta).

Por lo tanto, en esta secuencia de comandos agrega su SPOP y RPOP, puede agregar los resultados de cada comando redis en una matriz LUA, por ejemplo, y luego devolver la matriz a su cliente redis.

Lo que dice la documentación acerca de MULTI es que es un bloqueo optimista, lo que significa que volverá a intentar hacer lo múltiple con WATCH hasta que el valor observado no se modifique. Si tiene muchas escrituras en el valor observado, será más lento que el bloqueo "pesimista" (como muchas bases de datos SQL: POSTGRESQL, MYSQL ...) que de alguna manera "detiene el mundo" para que la consulta se ejecute primero . El bloqueo pesimista no se implementa en redis, pero puede implementarlo si lo desea, pero es complejo y tal vez no lo necesite (no hay tantas escrituras en este valor: optimista debería ser suficiente).


Probablemente puedas probar un script lua (script.lua) como este:

local result = {} for i = 0 , ARGV[1] do local val = redis.call(''RPOP'',KEYS[1]) if val then table.insert(result,val) end end return result

puedes llamarlo de esta manera:

redis-cli eval "$(cat script.lua)" 1 "listName" 1000


si quieres un script lua, esto debería ser rápido y fácil.

local result = redis.call(''lrange'',KEYS[1],0,ARGV[1]-1) redis.call(''ltrim'',KEYS[1],ARGV[1],-1) return result

entonces no tienes que repetir.

actualización: Intenté hacer esto con srandmember (en 2.6) con el siguiente script:

local members = redis.call(''srandmember'', KEYS[1], ARGV[1]) redis.call(''srem'', KEYS[1], table.concat(table, '' '')) return members

pero me sale un error:

error: -ERR Error running script (call to f_6188a714abd44c1c65513b9f7531e5312b72ec9b): Write commands not allowed after non deterministic commands

No sé si la versión futura permitirá esto, pero supongo que no. Creo que sería un problema con la replicación.



Para ampliar la respuesta de Eli con un ejemplo completo de colecciones de listas, usando lrange ltrim lrange y ltrim en lugar de Lua:

127.0.0.1:6379> lpush a 0 1 2 3 4 5 6 7 8 9 (integer) 10 127.0.0.1:6379> lrange a 0 3 # read 4 items off the top of the stack 1) "9" 2) "8" 3) "7" 4) "6" 127.0.0.1:6379> ltrim a 4 -1 # remove those 4 items OK 127.0.0.1:6379> lrange a 0 999 # remaining items 1) "5" 2) "4" 3) "3" 4) "2" 5) "1" 6) "0"

Si quisieras hacer la operación atómica, envolverías el lrange y el ltrim en los comandos multi y exec .

También como se señaló en otra parte, probablemente debería ltrim el número de artículos devueltos, no la cantidad de artículos que solicitó. por ejemplo, si lrange a 0 99 pero lrange a 0 99 50 elementos, obtendrías ltrim a 50 -1 no ltrim a 100 -1 .

Para implementar semántica de cola en lugar de una pila, reemplace lpush con rpush .