Redis es una cuadrícula en memoria popular que se utiliza para la comunicación entre procesos y el almacenamiento de datos. Es posible que haya escuchado que le permite ejecutar scripts de Lua, pero aún no está seguro de por qué. Si esto te suena, sigue leyendo.

Prerrequisitos
Debería tener Redis instalado en su sistema para seguir esta guía. Puede ser útil consultar la referencia de comandos de Redis mientras lee.
¿Por qué necesito Lua Scripts?
En resumen: aumento de rendimiento. La mayoría de las tareas que realiza en Redis implican muchos pasos. En lugar de realizar estos pasos en el idioma de su aplicación, puede hacerlo dentro de Redis con Lua.
- Esto puede resultar en un mejor rendimiento.
- Además, todos los pasos dentro de un script se ejecutan de forma atómica. Ningún otro comando de Redis puede ejecutarse mientras se ejecuta un script.
Por ejemplo, utilizo scripts de Lua para cambiar cadenas JSON almacenadas en Redis. Describo esto en detalle más cerca del final de este artículo.
Pero no conozco a ninguna Lua

No te preocupes, Lua no es muy difícil de entender. Si conoce algún idioma de la familia C, debería estar de acuerdo con Lua. Además, proporciono ejemplos prácticos en este artículo.
Muestrame un ejemplo
Comencemos ejecutando scripts a través de redis-cli . Empiece con:
redis-cli
Ahora ejecute el siguiente comando:
eval “redis.call(‘set’, KEYS[1], ARGV[1])” 1 key:name value
El comando EVAL es lo que le dice a Redis que ejecute el script que sigue. La ”redis.call(‘set’, KEYS[1], ARGV[1])”
cadena es nuestro script que es funcionalmente idéntico al set
comando de Redis . Tres parámetros siguen al texto del guión:
- El número de claves proporcionadas
- Nombre clave
- Primer argumento
Los argumentos del script se dividen en dos grupos: KEYS y ARGV .
Especificamos cuántas claves requiere el script con el número inmediatamente siguiente. En nuestro ejemplo, es 1 . Inmediatamente después de este número, debemos proporcionar estas claves, una tras otra. Son accesibles como tabla KEYS dentro del script. En nuestro caso, contiene un valor único key:name
en el índice 1 .
Tenga en cuenta que las tablas indexadas de Lua comienzan con el índice 1, no con 0 .
Podemos proporcionar cualquier número de argumentos después de las claves, que estarán disponibles en Lua como la tabla ARGV . En este ejemplo, proporcionamos un único ARGV -argument: string value
. Como ya adivinó, el comando anterior establece la clave key:name
en valor value
.
Se considera una buena práctica proporcionar claves que el script usa como CLAVES y todos los demás argumentos como ARGV . Por lo tanto, no debe especificar KEYS como 0 y luego proporcionar todas las claves dentro de la tabla ARGV .
Comprobemos ahora si el script se completó correctamente. Vamos a hacer esto ejecutando otro script que obtiene la clave de Redis:
eval “return redis.call ('get', KEYS [1])” 1 clave: nombre
La salida debería ser ”value”
, lo que significa que la secuencia de comandos anterior estableció correctamente la clave “key:name”
.
¿Puedes explicar el guión?

Nuestro primer script consta de una sola declaración: la redis.call
función:
redis.call(‘set’, KEYS[1], ARGV[1])
Con redis.call
puedes ejecutar cualquier comando de Redis. El primer argumento es el nombre de este comando seguido de sus parámetros. En el caso del set
comando, estos argumentos son clave y valor . Todos los comandos de Redis son compatibles. Según la documentación:
Nuestro segundo script hace un poco más que ejecutar un solo comando, también devuelve un valor:
eval “return redis.call(‘get’, KEYS[1])” 1 key:name
Todo lo que devuelve el script se envía al proceso de llamada. En nuestro caso, este proceso es redis-cli y verá el resultado en la ventana de su terminal.
¿Algo más complejo?

Una vez usé scripts de Lua para devolver elementos de un mapa hash en un orden particular. El orden en sí fue especificado por claves hash almacenadas en un conjunto ordenado.
Primero configuremos nuestros datos ejecutando estos comandos en redis-cli :
hmset hkeys key:1 value:1 key:2 value:2 key:3 value:3 key:4 value:4 key:5 value:5 key:6 value:6 zadd order 1 key:3 2 key:1 3 key:2
Estos comandos crean un mapa hash en la clave hkeys
y un conjunto ordenado en la clave order
que contiene las claves seleccionadas hkeys
en un orden específico.
Es posible que desee consultar la referencia de los comandos hmset y zadd para obtener más detalles.
Ejecutemos el siguiente script:
eval “local order = redis.call(‘zrange’, KEYS[1], 0, -1); return redis.call(‘hmget’,KEYS[2],unpack(order));” 2 order hkeys
Debería ver el siguiente resultado:
“value:3” “value:1” “value:2”
Which means that we got values of the keys we wanted and in the correct order.
Do I have to specify full script text to run it?
No! Redis allows you to preload a script into memory with the SCRIPT LOAD command:
script load “return redis.call(‘get’, KEYS[1])”
You should see an output like this:
“4e6d8fc8bb01276962cce5371fa795a7763657ae”
This is the unique hash of the script which you need to provide to the EVALSHA command to run the script:
evalsha 4e6d8fc8bb01276962cce5371fa795a7763657ae 1 key:name
Note: you should use actual SHA1 hash returned by the SCRIPT LOAD command, the hash above is only an example.
What did you mention about changing JSON?
Sometimes people store JSON objects in Redis. Whether it is a good idea or not is another story, but in practice, this happens a lot.
If you have to change a key in this JSON object, you need to get it from Redis, parse it, change the key, then serialize and set it back to Redis. There are a couple of problems with this approach:
- Concurrency. Another process can change this JSON between our get and set operations. In this case, the change will be lost.
- Performance. If you do these changes often enough and if the object is rather big, this might become the bottleneck of your app. You can win some performance by implementing this logic in Lua.
Let’s add a test JSON string to Redis under key obj
:
set obj ‘{“a”:”foo”,”b”:”bar”}’
Now let’s run our script:
EVAL ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’ 1 obj b bar2
Now we will have the following object under key obj
:
{“a”:”foo”,”b”:”bar2"}
You can instead load this script with the SCRIPT LOAD command:
SCRIPT LOAD ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’
and then run it like this:
EVALSHA 1 obj b bar2
Some notes:
- The
..
is the string concatenation operator in Lua. - We use a RegEx pattern to match key and replace its value. If you don’t understand this Regular Expression, you can check my recent guide.
- One difference of the Lua RegEx flavor from most other flavors is that we use
%
as both backreference mark and escape character for RegEx special symbols. - We still escape
”
with\
and not%
because we escape Lua string delimiter, not RegEx special symbol.
Should I always use Lua scripts?
No. I recommend only using them when you can prove that it results in better performance. Always run benchmarks first.
If all you want is atomicity, then you should check Redis transactions instead.
Also, your script shouldn’t be too long. Remember that while a script is running, everything else is waiting for it to finish. If your script takes quite some time, it can cause bottlenecks instead of improving performance. The script stops after reaching a timeout (5 seconds by default).

Last Word
For more information on Lua check lua.org.
You can check my node.js library on GitHub for some examples of Lua scripts (see src/lua
folder). You can also use this library in node.js to change JSON objects without writing any Lua scripts yourself.
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Thank you for reading this article. Questions and comments are much appreciated. You are also welcome to follow me on Twitter.