Redis中使用Lua脚本的开发思路

Redis提供了通过eval命令来执行Lua脚本。下面通过几个小例子来讲述如何在Redis服务端执行Lua脚本。

1. 执行Lua脚本的几个命令如下:

命令格式   说明   对应Jedis客户端Jedis对象的方法之一(有更多重载方法)  
EVAL script numkeys key [key ...] arg [arg ...]   执行Lua脚本  

public Object eval(String script, int keyCount, String... params)

 
EVALSHA sha1 numkeys key [key ...] arg [arg ...]   根据给定的 sha1 校验码,对缓存在服务器中的脚本进行求值   public Object evalsha(String sha1, int keyCount, String... params)  
SCRIPT LOAD script   将给定的脚本缓存,不执行,并返回sha1校验值   public String scriptLoad(String script)  
SCRIPT EXISTS sha1 [sha1 ...]   给定一个或多个脚本的 SHA1 校验和,返回一个包含 0 和 1 的列表,表示校验和所指定的脚本是否已经被保存在缓存当中   public List<Boolean> scriptExists(String... sha1)   
SCRIPT FLUSH    清除所有 Lua 脚本缓存      
SCRIPT KILL   杀死当前正在运行的 Lua 脚本,当且仅当这个脚本没有执行过任何写操作时,这个命令才生效(如果已经执行了写操作,则需要通过shutdown nosave命令来处理)  

2.通过redis-cli客户端执行Lua脚本
   
redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3

需要注意的是用逗号来分割key和参数,这里与在交互式模式下执行evel命令有所不同。

3.实际案例

场景一:对一个特定请求1秒钟只允许访问10次,当符合请求访问条件时,返回True,否则返回False。
  Java客户端操作Redis服务,实现代码如下:
   
/**
    * 访问控制
    * 
    * 1秒内最多可访问10次
    * 
    * @param key
    * @return
    */
    public boolean isAccess(String key) {
        String rkey = "acc:" + key;
        long value = jedis.incr(rkey);
        if (value == 1) {
            jedis.expire(rkey, 1);
            return true;
        } else {
            boolean rs = value <= 10;
            return rs;
        }
    }

INCR命令作为计数器,如果rkey存在,则增加1返回最终值,否则初始化值为0,然后加1。如上程序,如果访问rkey不存在,则表示第一次请求,这时对其rkey设置过期时间为1秒,否则比较其值是否超过制定请求数的阀值10.
 
用Lua脚本来完成这一操作:
 
--[[
Judge status 
KEYS[1]:key
ARGV[1]:request numbers
ARGV[2]:expires times seconds
--]]
 
local key, rqn, exp  = KEYS[1], ARGV[1], ARGV[2];
local value=redis.call("incr", key);
redis.log(redis.LOG_NOTICE, "incr "..key);
if(tonumber(value) == 1)then
  redis.call("expire", key,  exp);
  redis.log(redis.LOG_NOTICE, "expire "..key.." "..exp)
  return true;
else
  return tonumber(value) <= tonumber(rqn);
end

通过Java客户端代码实现该功能存在一定缺陷,比如每1秒就需要操作1个incr和expire命令,并且该命令是由客户端通过网络发起的,而使用Lua脚本则既可以保证操作的原子性,又能使每次操作只需要一个key即可在服务器端完成相应的判断操作。可以通过SCRIPT LOAD的方式将脚本缓存到服务器,通过sha1校验值+参数(Key,ARG)来执行,减轻网络传输,也对该功能做到较好的封装。

场景二:指定模式key批量删除
    redis目前提供的删除命令del仅支持删除指定数量的key,并不能通过指定模式key来进行删除,比如:del *user 删除以user结尾的key。
   
  在redis中提供了keys命令,该命令可以通过指定模式key来获取key列表,下面通过keys和del命令组合实现一个指定模式key批量删除的命令。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/e4400caa7fe26e77c02afae55c108ad6.html