Las instancias de Tair (Redis OSS-compatible) admiten comandos Lua. Puede utilizar scripts Lua para gestionar operaciones de comparación e intercambio (CAS) de forma eficiente, mejorar el rendimiento de la instancia e implementar patrones que serían difíciles o ineficientes de lograr por otros medios. Este tema describe la sintaxis básica y las directrices de uso para scripts Lua.
Sintaxis básica
Optimización del rendimiento
Optimizar la memoria y la sobrecarga de red
Almacenar en caché una gran cantidad de scripts funcionalmente repetitivos consume mucha memoria e incluso puede desencadenar un error de falta de memoria (OOM). A continuación se muestra un ejemplo de uso incorrecto:
EVAL "return redis.call('set', 'k1', 'v1')" 0
EVAL "return redis.call('set', 'k2', 'v2')" 0
Solución:
-
Para reducir el desperdicio de memoria, evite codificar argumentos como constantes dentro del script Lua.
# Achieves the same functionality as the incorrect example but only caches the script once. EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 k1 v1 EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 k2 v2 -
Para mayor eficiencia, se recomienda el siguiente enfoque con el fin de reducir tanto el uso de memoria como la sobrecarga de red.
SCRIPT LOAD "return redis.call('set', KEYS[1], ARGV[1])" # After execution, Redis returns "55b22c0d0cedf3866879ce7c854970626dcef0c3". EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k1 v1 EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k2 v2
Liberar memoria de scripts Lua
La caché de scripts Lua consume memoria de la instancia, lo cual contribuye a la métrica used_memory. Si el uso de memoria de la instancia se acerca o supera el valor de maxmemory, puede producirse un error de falta de memoria (OOM). A continuación se muestra un ejemplo de error:
-OOM command not allowed when used memory > 'maxmemory'.
Solución:
Ejecute el comando SCRIPT FLUSH desde un cliente para borrar la caché de scripts Lua. El método recomendado depende de la versión de su instancia:
-
Limpieza asíncrona (recomendada): Las versiones de open source Redis 7.0 o posteriores y Tair (Enterprise Edition) 6.0 o posteriores admiten el comando
SCRIPT FLUSH ASYNC. Este comando borra la caché de scripts Lua en segundo plano sin bloquear la instancia, lo que minimiza el impacto en sus servicios.SCRIPT FLUSH ASYNC -
Limpieza síncrona: En versiones anteriores, el comando
SCRIPT FLUSHfunciona de manera síncrona. Si la instancia tiene una gran cantidad de scripts Lua en caché, este comando puede bloquearla durante un periodo prolongado y dejarla no disponible. Utilice este comando con precaución, preferiblemente fuera de las horas pico.SCRIPT FLUSH
Hacer clic en Purge Data en la consola solo borra los datos y no limpia la caché de scripts Lua.
Además, evite escribir scripts Lua excesivamente grandes para prevenir un alto consumo de memoria. No realice escrituras masivas de datos dentro de un script Lua, ya que esto puede causar un aumento repentino en el uso de memoria y derivar en un error OOM. Si su lógica de negocio lo permite, se recomienda habilitar la evicción de datos (habilitada de forma predeterminada con la directiva volatile-lru) para ahorrar espacio en memoria. Sin embargo, la instancia no desaloja la caché de scripts Lua, independientemente de si la evicción de datos está habilitada.
Gestión de errores
Error NOSCRIPT
Cuando utiliza el comando EVALSHA, si el script correspondiente al valor sha1 no está almacenado en la caché de la instancia, esta devuelve un error NOSCRIPT. A continuación se muestra un ejemplo:
(error) NOSCRIPT No matching script. Please use EVAL.
Solución:
Utilice el comando EVAL o SCRIPT LOAD para almacenar el script en la caché de la instancia y vuelva a intentarlo. No obstante, la instancia no garantiza la persistencia ni la replicación de los scripts Lua. En algunos escenarios, como una migración de instancia o un cambio de configuración, la caché de scripts Lua puede borrarse. Por lo tanto, su aplicación cliente debe ser capaz de gestionar este error. Para obtener más información, consulte Persistence and replication issues.
La siguiente demostración en Python muestra un ejemplo de cómo gestionar un error NOSCRIPT. Esta demostración utiliza un script Lua para realizar una operación de anteposición de cadenas.
También puede utilizar la biblioteca redis-py para Python con el fin de gestionar este tipo de error. La biblioteca proporciona una clase Script que encapsula la lógica de bajo nivel para la creación de scripts Lua en Redis, como la captura de errores NOSCRIPT.
import redis
import hashlib
# This function takes a Lua script as a string and returns its SHA1 digest.
def calcSha1(strin):
sha1_obj = hashlib.sha1()
sha1_obj.update(strin.encode('utf-8'))
sha1_val = sha1_obj.hexdigest()
return sha1_val
class MyRedis(redis.Redis):
def __init__(self, host="localhost", port=6379, password=None, decode_responses=False):
redis.Redis.__init__(self, host=host, port=port, password=password, decode_responses=decode_responses)
def prepend_inLua(self, key, value):
script_content = """\
local suffix = redis.call("get", KEYS[1])
local prefix = ARGV[1]
local new_value = prefix..suffix
return redis.call("set", KEYS[1], new_value)
"""
script_sha1 = calcSha1(script_content)
if self.script_exists(script_sha1)[0]: # Check if the script is cached in Redis.
return self.evalsha(script_sha1, 1, key, value) # If cached, run the script with EVALSHA.
else:
return self.eval(script_content, 1, key, value) # Otherwise, run the script with EVAL, which also caches it. Alternatively, you could use SCRIPT LOAD and then EVALSHA.
r = MyRedis(host="r-******.redis.rds.aliyuncs.com", password="***:***", port=6379, decode_responses=True)
print(r.prepend_inLua("k", "v"))
print(r.get("k"))
Errores de tiempo de espera en scripts Lua
-
Dado que los scripts Lua se ejecutan de forma atómica, un script lento puede bloquear la instancia. Si un script se ejecuta durante más de 5 segundos, la instancia devuelve un error
BUSYpara todos los demás comandos hasta que finaliza la ejecución del script.BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.Solución:
Puede utilizar el comando
SCRIPT KILLpara finalizar el script Lua o esperar a que se complete.NotaEl comando
SCRIPT KILLno surte efecto durante los primeros 5 segundos de ejecución de un script lento porque la instancia está bloqueada.Al escribir scripts Lua, estime su tiempo de ejecución y compruebe que no existan problemas como bucles infinitos. Esto ayuda a evitar que los scripts de larga duración bloqueen la instancia y dejen el servicio no disponible. Si es necesario, divida los scripts largos en otros más pequeños.
-
Si el script Lua actual ya ejecutó un comando de escritura, el comando
SCRIPT KILLno funcionará. A continuación se muestra un ejemplo de error:(error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.Solución:
En la consola, vaya a la página Instances y haga clic en restart para la instancia correspondiente.
Problemas de persistencia y replicación
La instancia almacena en caché los scripts Lua ejecutados de forma indefinida, a menos que se reinicie o se invoque el comando SCRIPT FLUSH. Sin embargo, en ciertas situaciones, como una migración de instancia, un cambio de configuración, una actualización de versión o un failover de alta disponibilidad (HA), la instancia no garantiza la persistencia de los scripts Lua ni su replicación a otros nodos.
Solución:
Dado que la instancia no garantiza la persistencia ni la replicación de scripts, debe almacenar todos los scripts Lua localmente. Cuando sea necesario, utilice el comando EVAL o SCRIPT LOAD para volver a almacenar los scripts en la caché de la instancia. Esto evita errores NOSCRIPT que pueden ocurrir si la caché de scripts se borra durante operaciones como un reinicio de instancia o un failover de HA.
Restricciones especiales en arquitectura de clúster
Restricciones de la arquitectura de clúster
Para garantizar la atomicidad, un script Lua no se puede dividir y debe ejecutarse en un solo shard dentro de una arquitectura de clúster. La instancia suele utilizar una clave para determinar a qué shard enrutar el comando. Por lo tanto, debe especificar como mínimo una clave al ejecutar un script Lua en un clúster. Si un script accede a varias claves, todas deben pertenecer al mismo slot; de lo contrario, el script fallará o devolverá resultados incorrectos. Los comandos sin claves, como
KEYS,SCANyFLUSHDB, pueden ejecutarse, pero solo devolverán datos de un único shard. Estas limitaciones son inherentes a la arquitectura de Redis Cluster.Ejecutar el comando
SCRIPT LOADen un solo nodo no garantiza que el script se almacene en los demás nodos.
Códigos de error en modo proxy
El proxy realiza comprobaciones de sintaxis para identificar proactivamente los casos en los que las claves abarcan varios slots. Esto ayuda a detectar problemas temprano para facilitar la resolución. El método de comprobación del proxy difiere del de la máquina virtual Lua, lo que genera restricciones adicionales al ejecutar comandos Lua en modo proxy. Por ejemplo, el comando UNPACK no es compatible, y los comandos EVAL, EVALSHA y los de la serie SCRIPT no se pueden utilizar dentro de transacciones MULTI/EXEC.
También puede deshabilitar algunas de las comprobaciones de sintaxis Lua del proxy al desactivar el parámetro script_check_enable.
Adicionalmente, para una instancia con división de lectura/escritura, si el parámetro readonly_lua_route_ronode_enable está habilitado, el proxy comprueba si un script Lua contiene únicamente comandos de solo lectura para determinar si se puede reenviar a un nodo de solo lectura. Esta lógica de comprobación impone limitaciones en la sintaxis Lua.
Deshabilitar el parámetro script_check_enable tiene los siguientes efectos:
Para instancias de open source Redis 5.0 (versiones menores anteriores a 5.0.8) o Redis 4.0 y anteriores, no se recomienda deshabilitar este parámetro. Hacerlo puede provocar que un script devuelva un mensaje de éxito incluso cuando se ejecuta incorrectamente.
Para otras versiones, deshabilitar este parámetro detiene la comprobación de sintaxis Lua por parte del proxy, pero los nodos de datos seguirán realizando sus comprobaciones de sintaxis normales.
A continuación se detallan los códigos de error específicos y sus causas.
Limitaciones de la arquitectura Redis Cluster
-
Código de error:
-ERR for redis cluster, eval/evalsha number of keys can't be negative or zero\r\nDescripción: Debe especificar como mínimo una clave al ejecutar un script Lua. El proxy utiliza la clave para determinar a qué shard reenviar el script.
# Correct example EVAL "return redis.call('get', KEYS[1])" 1 fooeval # Incorrect example EVAL "return redis.call('get', 'foo')" 0 -
Código de error:
-ERR 'xxx' command keys must in same slotDescripción: Todas las claves en un script Lua deben pertenecer al mismo slot.
# Correct example: EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar # Incorrect example: EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo foobar
Restricciones de sintaxis Lua del proxy
Puede evitar las comprobaciones adicionales de sintaxis Lua del proxy al disabling el parámetro script_check_enable.
-
Código de error:
-ERR bad lua script for redis cluster, nested redis.call/redis.pcallDescripción: No se admiten llamadas anidadas a Redis. Utilice variables locales como alternativa.
# Correct example EVAL "local value = redis.call('GET', KEYS[1]); redis.call('SET', KEYS[2], value)" 2 foo bar # Incorrect example EVAL "redis.call('SET', KEYS[1], redis.call('GET', KEYS[2]))" 2 foo bar -
Código de error:
-ERR bad lua script for redis cluster, first parameter of redis.call/redis.pcall must be a single literal stringDescripción: El comando invocado dentro de redis.call/pcall debe ser una cadena literal.
# Correct example eval "redis.call('GET', KEYS[1])" 1 foo # Incorrect example eval "local cmd = 'GET'; redis.call(cmd, KEYS[1])" 1 foo
Problemas de permisos de lectura/escritura
-
Código de error:
-ERR Write commands are not allowed from read-only scriptsDescripción: Los scripts Lua enviados con el comando
EVAL_ROno pueden contener comandos de escritura. -
Código de error:
-ERR bad write command in no write privilegeDescripción: Los scripts Lua enviados desde una cuenta de solo lectura no pueden contener comandos de escritura.
Comandos no compatibles
-
Código de error:
-ERR script debug not supportDescripción: Actualmente, el proxy no admite el comando
SCRIPT DEBUG. -
Código de error:
-ERR bad lua script for redis cluster, redis.call/pcall unkown redis command xxxDescripción: El script Lua contiene un comando que no es compatible con el proxy. Para obtener más información, consulte Command restrictions on cluster and read/write splitting instances.
Errores de sintaxis Lua
-
Código de error:
-ERR bad lua script for redis cluster, redis.call/pcall expect '('o-ERR bad lua script for redis cluster, redis.call/redis.pcall definition is not complete, expect ')'Nota: Se trata de un error de sintaxis Lua porque la función
redis.calldebe ir seguida de un par completo de paréntesis:(y). -
Código de error:
-ERR bad lua script for redis cluster, at least 1 input key is needed for ZUNIONSTORE/ZINTERSTOREDescripción: El parámetro
numkeysde los comandosZUNIONSTOREyZINTERSTOREdebe ser mayor que 0. -
Código de error:
-ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE key count < numkeysDescripción: La cantidad real de claves para el comando
ZUNIONSTOREoZINTERSTOREes menor que el valornumkeysespecificado. -
Código de error:
-ERR bad lua script for redis cluster, xread/xreadgroup command syntax errorDescripción: La sintaxis del comando
XREADoXREADGROUPes incorrecta. Compruebe la cantidad de parámetros. -
Código de error:
-ERR bad lua script for redis cluster, xread/xreadgroup command syntax error, streams must be specifiedDescripción: Los comandos
XREADyXREADGROUPdeben incluir el parámetrostreams. -
Código de error:
-ERR bad lua script for redis cluster, sort command syntax errorDescripción: La sintaxis del comando
SORTes incorrecta.
Preguntas frecuentes
-
P: ¿Puedo ejecutar scripts Lua en Data Management (DMS)?
R: La consola de Data Management (DMS) actualmente no admite comandos relacionados con Lua. Para utilizar scripts Lua, conéctese a su instancia mediante un cliente o redis-cli.