Redis执行Lua脚本,以及Java代码演示

2019-01-11  本文已影响23人  小波同学

人生格言:不敢冒险,才是风险!

Redis在2.6推出了脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行。使用脚本的好处如下:

实现一个访问频率控制,某个ip在短时间内频繁访问页面,需要记录并检测出来,就可以通过Lua脚本高效的实现

在redis客户端机器上,新建一个文件ip_limit.lua,内容如下

--限流 对某个ip的访问频率进行限制,1分钟内访问十次
local num=redis.call('incr',KEYS[1])
if tonumber(num)==1 then
    redis.call('expire',KEYS[1],ARGV[1])
    return 1
elseif tonumber(num)>tonumber(ARGV[2]) then
    return 0
else 
    return 1
end

在redis客户端机器上,如何测试这个脚本呢?如下:

./redis-cli --eval "ip_limit.lua" ip:limit:127.0.0.1 , 6000 10

--eval参数是告诉redis-cli读取并运行后面的Lua脚本,ip_limit.lua是脚本的位置,后面跟着是传给Lua脚本的参数。其中","前的ip:limit:127.0.0.1是要操作的键,可以再脚本中用KEYS[1]获取,","后面的6000和10是参数,在脚本中能够使用ARGV[1]和ARGV[2]获得。注:","两边的空格不能省略,否则会出错

结合脚本的内容可知这行命令的作用是将访问频率限制为每10秒最多3次,所以在终端中不断的运行此命令会发现当访问频率在10秒内小于或等于3次时返回1,否则返回0。

测试运行如下:

image.png

在Java上演示:

通过RedisManager获取到Jedis

public class RedisManager {

    private static JedisPool jedisPool;

    static{
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20);
        jedisPoolConfig.setMaxIdle(10);
        jedisPool = new JedisPool(jedisPoolConfig,"127.0.0.1",6379);
    }

    public static Jedis getJedis(){
        if(null != jedisPool){
            return jedisPool.getResource();
        }
        throw new RuntimeException("JedisPool was not init!");
    }
}

Redis集合Lua的Java演示代码

public class LuaDemo {

    private final static 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";
    /**
     * 这是将脚本提取到外面为常量,用 jedis.evalsha()加载
     */
    public static void main(String[] args) {
        Jedis jedis = RedisManager.getJedis();
        List<String> keys = new ArrayList<>();
        keys.add("ip:limit:127.0.0.1");
        List<String> arggs = new ArrayList<>();
        arggs.add("6000");
        arggs.add("10");
        String luaLoad = jedis.scriptLoad(lua);
        System.out.println(luaLoad);
        Object obj = jedis.evalsha(luaLoad,keys,arggs);
        System.out.println(obj);
    }

    /**
     * 这是直接将脚本写死在代码中,用 jedis.eval()
     */
    public static void method(){
        Jedis jedis = RedisManager.getJedis();
        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";
        List<String> keys = new ArrayList<>();
        keys.add("ip:limit:127.0.0.1");
        List<String> arggs = new ArrayList<>();
        arggs.add("6000");
        arggs.add("10");
        Object obj = jedis.eval(lua,keys,arggs);
        System.out.println(obj);
    }
}

补充:

现在Lua脚本用在很多游戏上,主要是Lua脚本做到可以嵌入到其他程序中运行,游戏升级的时候,可以直接升级脚本,而不用重新安装游戏。比如游戏的很多关卡,只需要增加lua脚本,在游戏中嵌入Lua解释器,游戏团队线上更新Lua脚本,然后游戏自动下载最新的游戏关卡。例如之前很多的游戏《愤怒的小鸟》就是用Lua语言实现的关卡。

摘自《Redis入门指南》

此文章为本人原创,代码都是笔者手动敲出来的,如和其他大神博客有相同之处还望见谅!

上一篇下一篇

猜你喜欢

热点阅读