Redis使用Lua脚本
Redis使用lua脚本的优点
- 减少网络开销:将原来多次请求的逻辑封装为脚本在服务器上执行,只需1次请求就能完成,减少了网络往返时延;
- 原子操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入;
- 复用性:客户端发送的脚本会永久保存在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 添加到脚本缓存中,但并不立即执行这个脚本。 |
示例
Hash对象中field对应value值累加
-
编写Lua脚本(keyOpt.lua):
# keyOpt.lua 39bf38f32e2ca17550d789091a8d5d2635f5d3c0 if redis.call('EXISTS', KEYS[1]) == 1 then local res =redis.call(ARGV[4],KEYS[1],ARGV[1],ARGV[2]) return res else local res =redis.call(ARGV[4], KEYS[1],ARGV[1],ARGV[2]) redis.call('EXPIRE', KEYS[1],ARGV[3]) return res end
-
将Lua脚本加载到redis服务器
redis-cli script load "$(cat keyOpt.lua)"
![img](file:///D:/Users/Documents/SuningImFiles/sn23070650/picRec/202401/20240129170421099.png)
执行成功后会返回sha码,客户端使用EVALSHA sha1 numkeys key [key ...] arg [arg ...] 命令即可执行此脚本。
使用hset存储每人的id,len+1=新id
# getSeq.lua 6ba13ea07df8502ac7e64097243d9c7ada0da3af
local seq= redis.call('HGET',KEYS[1],ARGV[1])
if(seq) then
return seq
else
if redis.call('EXISTS', KEYS[1]) == 1 then
local len= redis.call('HLEN',KEYS[1])+1
redis.call('HSET',KEYS[1],ARGV[1],len)
return len
else
redis.call('HSET',KEYS[1],ARGV[1],1)
redis.call('EXPIRE', KEYS[1],ARGV[2])
return 1
end
end
cd nm 一次存10个
# hmset.lua 56695193392ef6e730563f93008e0390f6c37416
local isext=redis.call('EXISTS', KEYS[1])
local i=1
while(i <= (ARGV[2]-0)) do
if ARGV[2]-i+1>=10 then
redis.call('HMSET',KEYS[1],ARGV[i*2+1],ARGV[i*2+2],ARGV[i*2+3],ARGV[i*2+4],ARGV[i*2+5],ARGV[i*2+6],ARGV[i*2+7],ARGV[i*2+8],ARGV[i*2+9],ARGV[i*2+10],ARGV[i*2+11],ARGV[i*2+12],ARGV[i*2+13],ARGV[i*2+14],ARGV[i*2+15],ARGV[i*2+16],ARGV[i*2+17],ARGV[i*2+18],ARGV[i*2+19],ARGV[i*2+20])
i=i+10
else
redis.call('HSET',KEYS[1],ARGV[i*2+1],ARGV[i*2+2])
i=i+1
end
end
if isext~=1 then
redis.call('EXPIRE', KEYS[1],ARGV[1])
end
return 'OK'
保存uid 一次存10个
# sadd.lua ccf4438961c6a4f8568cf91e02c989d714d5a54f
a892a3d41922c56bd3201de672fdca7df2c1cf08
local isext=redis.call('EXISTS', KEYS[1])
local res=0
local i=1
while(i<=(ARGV[2]+0)) do
if ARGV[2]-i+1>=10 then
res =res+ redis.call('SADD', KEYS[1],ARGV[i+2],ARGV[i+3],ARGV[i+4],ARGV[i+5],ARGV[i+6],ARGV[i+7],ARGV[i+8],ARGV[i+9],ARGV[i+10],ARGV[i+11])
i=i+10
else
res =res+ redis.call('SADD', KEYS[1],ARGV[i+2])
i=i+1
end
end
if isext ~= 1 then
redis.call('EXPIRE', KEYS[1],ARGV[1])
end
return res
HLL 去重计算
# setHll.lua 122144b94eba6eaedbb203fefa67096c9969702d
local res = 0
local isext1 = redis.call('EXISTS', KEYS[1])
local isext2 = redis.call('EXISTS', KEYS[2])
local i = 1
while(i <= (ARGV[5] + 0)) do
if ARGV[5]-i+1 >= 10 then
redis.call('PFADD', KEYS[1],ARGV[i+5],ARGV[i+6],ARGV[i+7],ARGV[i+8],ARGV[i+9],ARGV[i+10],ARGV[i+11],ARGV[i+12],ARGV[i+13],ARGV[i+14])
i = i+10
else
redis.call('PFADD', KEYS[1],ARGV[i+5])
i = i+1
end
end
local uvCount = redis.call('PFCOUNT',KEYS[1])
if ARGV[1] ~= 'ZADD' then
res = redis.call(ARGV[1],KEYS[2],ARGV[4],uvCount)
else
res = redis.call(ARGV[1],KEYS[2],uvCount,ARGV[4])
end
if isext1 ~= 1 then
redis.call('EXPIRE', KEYS[1],ARGV[2])
end
if isext2 ~= 1 then
redis.call('EXPIRE', KEYS[2],ARGV[3])
end
return res
访问频率控制
local times = redis.call('incr',KEYS[1])
if times == 1 then
redis.call('expire',KEYS[1], ARGV[1])
end
if times > tonumber(ARGV[2]) then
return 0
end
return 1
标签:脚本,end,KEYS,Redis,redis,ARGV,Lua,call,local
From: https://www.cnblogs.com/coke0914/p/18017742