1.Redis 脚本
Redis 脚本使用 Lua 解释器来执行脚本。 Redis 2.6 版本通过内嵌支持 Lua 环境。执行脚本的常用命令为 EVAL。
下表列出了 redis 脚本常用命令:
序号 | 命令及描述 |
---|---|
1 | EVAL script numkeys key [key ...] arg [arg ...] 执行 Lua 脚本。 |
2 | EVALSHA sha1 numkeys key [key ...] arg [arg ...] 执行 Lua 脚本。 |
3 | SCRIPT EXISTS script [script ...] 查看指定的脚本是否已经被保存在缓存当中。 |
4 | SCRIPT FLUSH 从脚本缓存中移除所有脚本。 |
5 | SCRIPT KILL 杀死当前正在运行的 Lua 脚本。 |
6 | SCRIPT LOAD script 将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。 |
2.lua 文件编写和执行
ip_limit.lua
:
-- IP限流,对某个IP频率进行限制 ,1分钟访问10次 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
执行 ip_limit.lua
脚本:
./redis-cli --eval "ip_limit.lua" app:ip:limit:192.168.1.15 , 6000 10
(integer) 1
注意
1) app:ip:limit:192.168.1.15 是key值 ,后面是参数值,中间要加上一个空格 和 一个逗号,再加上一个 空格 。即:./redis-cli –eval [lua脚本] [key…]空格,空格[args…]
2) 多个参数之间用一个 空格 分割 。
3.evalsha 的基本使用
每次使用 eval 执行很长的脚本其实没什么必要, redis可以将脚本缓存起来,生成一个脚本的 SHA1 ,标记这个这个脚本,然后 使用时传 SHA1 和key value 的值即可。
92:0>script load "return redis.call('set',KEYS[1],ARGV[1])" # 这段脚本 生成了SHA1 值,来标记其唯一性 "c686f316aaf1eb01d5a4de1b0b63cd233010e63d" 92:0>evalsha c686f316aaf1eb01d5a4de1b0b63cd233010e63d 1 AA BB # 使用 evalsha 命令 和 SHA1 值来执行脚本 "OK" 92:0>get AA # 验证数据存储是否成功 "BB"
4.redis 和 java 整合
jedis.scriptLoad方法将script 脚本添加到脚本缓存中,如果脚本没有加载过,那么进行加载,这样就会返回一个sha1编码。
jedis.evalsha() 根据sha1编码 和 key value值执行脚本,返回结果。
依赖:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.0</version> </dependency>
代码如下,
Jedis连接池:
public class JedisPoolUtils { private static JedisPool jedisPool; public static JedisPool getInstance() { if (jedisPool == null) { synchronized (JedisPoolUtils.class) { if (jedisPool == null) { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(20); jedisPoolConfig.setMaxIdle(10); jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379, 4000, "123456"); } } } return jedisPool; } }
测试实现类:
public class LuaDemo{ @Test public void testScriptLoad() { JedisPool jedisPool = JedisPoolUtils.getInstance(); Jedis jedis = jedisPool.getResource(); System.out.println(jedis); String lua = "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 "; String scriptLoad=jedis.scriptLoad(lua); System.out.println(scriptLoad); } @Test public void testEvalsha() { JedisPool jedisPool = JedisPoolUtils.getInstance(); Jedis jedis = jedisPool.getResource(); try { String scriptLoad ="5ae1f63a19ef16ea0d8c0268d01c5fa01312b7e6"; //来自上面的 testScriptLoad()的值 Object result = jedis.evalsha(scriptLoad , Arrays.asList("localhost"), Arrays.asList("10000", "2")); System.out.println("aaa:"+result); }catch (Exception e){ e.printStackTrace(); }finally { if(jedis != null){ try { jedis.close(); }catch (Exception e){ e.printStackTrace(); } } } } @Test public void script() throws InterruptedException { JedisPool jedisPool = JedisPoolUtils.getInstance(); Jedis jedis = jedisPool.getResource(); List<String> keys = new ArrayList<>(); List<String> vals = new ArrayList<>(); // 测试1、 基本测试 Object eval = jedis.eval("return 1", keys, vals); System.out.println(eval); // 测试2、 eval 里面也可以是一个文件 keys.add("kk"); Object eval2 = jedis.eval("local tab={} for i=1,#KEYS do tab[i] = redis.call('get',KEYS[i]) end return tab", keys, vals); System.out.println(eval2); // 测试3、 scriptLoad //好处:这样可以缓存到服务器,不用每次把lua脚本的内容传过去 String lua = "local tab={} for i=1,#KEYS do tab[i] = redis.call('get',KEYS[i]) end return tab"; String scriptLoad = jedis.scriptLoad(lua); System.out.println(scriptLoad); Object evalsha = jedis.evalsha(scriptLoad, keys, vals); System.out.println(evalsha); } }
参考:
https://zixuephp.net/manual-redis-2328.html
https://blog.csdn.net/xiaojin21cen/article/details/88621540
https://blog.csdn.net/weixin_38070406/article/details/78246786