您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

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

2024/10/13 18:30:28发布31次查看
redis提供了通过eval命令来执行lua脚本。下面通过几个小例子来讲述如何在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 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             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) 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批量删除的命令。
--[[
pattern delete key
keys[1]:pattern
--]]
redis.log(redis.log_notice, call keys ..keys[1]);
local keys=redis.call(keys, keys[1]);
local count = 0;
if(keys and (table.maxn(keys) > 0)) then
    for index, key in ipairs(keys) do
        redis.log(redis.log_notice, del ..key);
        count = count +  redis.call(del, key);
    end
end
return count;
需要注意的是场景二可以作为一种思路,通过lua脚本组合redis内置命令来实现特定功能的命令。而这里的模式key批量删除并未一个好的命令,因为如果key的数量很大时,将会有比较严重的性能问题。redis默认限制lua脚本执行时间最大为5秒,如果超过5秒将继续接受来自客户端的请求,并简单的返回busy结果。这时候则需要script kill或者shutdown nosave命令做相应的处理。因此应该尽力保证脚本的执行速度极快。
场景三:生成随机数
对于redis而且,脚本执行在相同数据集,相同参数下执行写命令具有一致性的。其不依赖与隐式的数据集,脚本执行过程中不同执行时期的状态变化,也不依赖外部i/o设备的输入。
要符合redis服务执行的脚本条件,需要注意的地方比较多,可以参见:                       
下面是实现随机数列表的lua脚本:
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product