• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

08-Redis的Lua脚本

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

01、使用Lua脚本来执行Redis命令的好处

  1. 一次发送多个命令,减少网络开销。
  2. Redis会将整个脚本作为一个整体执行,不会被其他请求打断,保持原子性。
  3. 对于复杂的组合命令,我们可以放在文件中,可以实现程序之间的命令集复用。

02、Redis中调用Lua脚本

使用eval方法,语法格式如下:

  • eval代表执行Lua语言的命令。
  • lua-script代表Lua语言脚本内容。
  • key-num表示参数中有多少个key,需要注意的是Redis中key是从1开始的,如果没有key的参数,那么写0。
  • [key1key2key3...]是key作为参数传递给Lua语言,也可以不填,但是需要和key-num的个数对应起来。 
  • [value1value2value3....]这些参数传递给Lua语言,它们是可填可不填的。

示例,返回一个字符串,0个参数:

03、在Lua脚本中调用Redis命令

使用redis.call(command,key[param1,param2...])进行操作。语法格式如下:

  • command是命令,包括set、get、del等。
  • key是被操作的键。
  • param1,param2...代表给key的参数。 

【1】、在Redis中调用Lua脚本执行Redis命令

以上命令等价于setgupao2673。

【2】、Redis中调用Lua脚本文件中的命令,操作Redis

创建Lua脚本文件:

Lua脚本内容,先设置,再取值:

在Redis客户端中调用Lua脚本 

得到返回值:

【3】、案例 对IP进行限流

需求:在X秒内只能访问Y次。

设计思路:用key记录IP,用value记录访问次数。

拿到IP以后,对IP+1。如果是第一次访问,对key设置过期时间(参数1)。否则判断次数,超过限定的次数(参数2),返回0。如果没有超过次数则返回1。超过时间,key过期之后,可以再次访问。

KEY[1]是IP,ARGV[1]是过期时间X,ARGV[2]是限制访问的次数Y。

6秒钟内限制访问10次,调用测试(连续调用10次):

app:ip:limit:192.168.8.111是key值,后面是参数值,中间要加上一个空格和一个逗号,再加上一个空格。 

即:./redis-cli–eval [lua脚本] [key...] 空格,空格[args...]

多个参数之间用一个空格分割。

03、缓存Lua脚本

【1】、为什么要缓存

在脚本比较长的情况下,如果每次调用脚本都需要把整个脚本传给Redis服务端,会产生比较大的网络开销。

【2】、如何缓存

Redis提供了EVALSHA命令,允许开发者通过脚本内容的SHA1摘要来执行脚本。

Redis在执行scriptload命令时会计算脚本的SHA1摘要并记录在脚本缓存中,执行EVALSHA命令时Redis会根据提供的摘要从脚本缓存中查找对应的脚本内容,如果找到了则执行脚本,否则会返回错误:"NOSCRIPT No matching script.Please use EVAL."

【3】、案例 自乘案例

自乘的运算,让它乘以后面的参数:

把这个脚本变成单行,语句之间使用分号隔开 

 script load  '命令'

 返回

"be4f93d8a5379e5e5b768a74e77c8a4eb0434441"

调用:

127.0.0.1:6379>set num 2

OK

127.0.0.1:6379>evalsha be4f93d8a5379e5e5b768a74e77c8a4eb0434441 1 num 6

 (integer)12

04、脚本超时

为了防止某个脚本执行时间过长导致Redis无法提供服务,Redis提供了lua-time-limit参数限制脚本的最长运行时间,默认为5秒钟。

lua-time-limit 5000(redis.conf配置文件中)

Redis提供了一个script kill的命令来中止脚本的执行。新开一个客户端:

 

 如果当前执行的Lua脚本对Redis的数据进行了修改(SET、DEL等),那么通过scriptkill命令是不能终止脚本运行的。

因为要保证脚本运行的原子性,如果脚本执行了一部分终止,那就违背了脚本原子性的要求。最终要保证脚本要么都执行,要么都不执行。

127.0.0.1:6379>script kill

(error)UNKILLABLE Sorry the script already executed write commands against the dataset.You can either wait the script terminationor kill the server in a hard way using the SHUTDOWN NOSAVE command.

遇到这种情况,只能通过shutdown nosave命令来强行终止redis。 

05、java调用案例

public class LuaTest {
    public static void main(String[] args) {
        Jedis jedis = getJedisUtil();
        jedis.eval("return redis.call('set',KEYS[1],ARGV[1])", 1,"test:lua:key","qingshan2673lua");
        System.out.println(jedis.get("test:lua:key"));
        for(int i=0; i<10; i++){
            limit();
        }
    }


    /**
     * 10秒内限制访问5次
     */
    public static void limit(){
        Jedis jedis = getJedisUtil();
        // 只在第一次对key设置过期时间
        String lua = "local num = redis.call('incr', KEYS[1])\n" +
                "if tonumber(num) == 1 then\n" +
                "\tredis.call('expire', KEYS[1], ARGV[1])\n" +
                "\treturn 1\n" +
                "elseif tonumber(num) > tonumber(ARGV[2]) then\n" +
                "\treturn 0\n" +
                "else \n" +
                "\treturn 1\n" +
                "end\n";
        Object result = jedis.evalsha(jedis.scriptLoad(lua), Arrays.asList("localhost"), Arrays.asList("10", "5"));
        System.out.println(result);
    }

    private static Jedis getJedisUtil() {
        String ip = ResourceUtil.getKey("redis.host");
        int port = Integer.valueOf(ResourceUtil.getKey("redis.port"));
        String password = ResourceUtil.getKey("redis.password");
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        JedisPool pool = new JedisPool(jedisPoolConfig, ip, port, 10000, password);
        return pool.getResource();
    }

}

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Lua的编辑和调试--- InteliJ+EmmyLua发布时间:2022-07-22
下一篇:
redis lua 使用 及lua安装发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap