Redis使用Lua脚本

Redis使用Lua脚本

Redis使用lua脚本的优点

  1. 减少网络开销:将原来多次请求的逻辑封装为脚本在服务器上执行,只需1次请求就能完成,减少了网络往返时延;
  2. 原子操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入;
  3. 复用性:客户端发送的脚本会永久保存在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值累加

  1. 编写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
    
  2. 将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
posted @   还是做不到吗  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示