redis
从2.6版本开始内置支持Lua
解释器,解释器提供了3个函数来处理redis
的命令redis.call()
redis.pcall()
和 redis.log
,同时redis
也保证脚本会以原子性的方式执行。这是一个很重要的因素。
本文涉及到的命令有 EVAL
EVALSHA
SCRIPT LOAD
SCRIPT FLUSH
SCRIPT EXISTS
SCRIPT KILL
redis.call(), redis.pcall() 函数的区别就是处理错误异常的情况不同,其他的功能是一样的 具体使用哪个看需求而论
redis.call()
执行命令的过程中发生错误时,脚本会停止执行,并返回一个脚本错误redis.pcall()
执行命令的过程中发生错误时,脚本会继续执行,但是会记录错误信息 返回一个带 err 域的 Lua 表(table)redis.log(loglevel, message)
触发redis
记录日志 日志级别有 redis.LOG_DEBUG redis.LOG_VERBOSE redis.LOG_NOTICE redis.LOG_WARNING
EVAL
EVAL
命令对 Lua
脚本进行执行求值。
语法:EVAL script numkeys key [key …] arg [arg …]
script
lua脚本内容 注意的是脚本不应该是Lua
函数。
numkeys
表示指定键名参数的个数。
key [key ...]
表示脚本对应的key
值列表 在脚本中可以使用KEYS[1]
KEYS[2]
KEYS[3]
KEYS[n]
n从1开始 。
arg [arg ...]
命名行中传递的参数列表 在脚本中可以使用ARGV[1]
ARGV[2]
ARGV[3]
ARGV[n]
n从1开始 。
一个示例胜过千言万语的解释
eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 id name 3 mytest |
执行上面脚本返回
1) "id" |
EVALSHA
此命令和EVAL
的区别是EVAL
每次都需要传入脚本的主体内容,对网络带宽不是很友好。而EVALSHA
命令正好可以解决这个问题。
语法: EVALSHA sha1 numkeys key [key …] arg [arg …]
sha1
缓存中的sha
值 这个值可以利用SCRIPT LOAD
生成
numkeys
表示指定键名参数的个数。
key [key ...]
表示脚本对应的key
值列表 在脚本中可以使用KEYS[1]
KEYS[2]
KEYS[3]
KEYS[n]
n从1开始 。
arg [arg ...]
命名行中传递的参数列表 在脚本中可以使用ARGV[1]
ARGV[2]
ARGV[3]
ARGV[n]
n从1开始 。
> SCRIPT LOAD "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" |
1、首先利用SCRIPT LOAD
把脚本的主体缓存在redis
中,会返回一个sha的key
2、EVALSHA
执行命令 把sha带上 其他的和eval没有区别。
脚本缓存
redis
保证了所有运行过的脚本都能缓存起来 前面也提到过使用SCRIPT LOAD
也能将脚本缓存并返回sha值,那么也能使用SCRIPT FLUSH
清空脚本缓存
SCRIPT LOAD
加载脚本到缓存中SCRIPT FLUSH
清除所有 Lua 脚本缓存。SCRIPT EXISTS
判断sha值是否已经缓存好了,返回值为 0 和 1 ,后者表示存在于缓存中,在程序开发中非常有用 比如redis
出现了什么异常情况后,脚本缓存被清空了,或者被人为执行了SCRIPT FLUSH
命令,这个时候就可以优先尝试一下SCRIPT EXISTS
命令如果返回0表示不存在 就需要先执行SCRIPT LOAD
先把脚本加载到缓存中之后再执行
SCRIPT KILL
杀死当前正在运行的 Lua
脚本,当且仅当这个脚本没有执行过任何写操作时,这个命令才生效
。
SCRIPT KILL
执行成功返回OK,其他情况返回错误信息
业务场景案例
- spring-cloud-gateway springc cloud 网关限流
- 需要原子操作的零散逻辑
- 分布式限流
- ….