searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

redis使用lua脚本

2023-05-11 01:37:20
6
0

减少交互

原生接口支持丰富的数据结构,但对有些操作支持的不够好。

比如在对key进行设置时,可以同时写入超时时间。这样在一条指令中就可以完成。

如果是incr操作,原生没有提供超时时间参数,需要调用两次接口实现。

可能产生的问题是,一是如果第一条操作后程序出现问题,导致超时时间没有设置,则会造成redis内存无法释放。二是多了一次网络交互,会增加业务的响应延迟。

因此在使用lua脚本把两条操作合并,可以达到减少交互的作用。

实现原子操作

redis本身是单线程执行,可以实现原子操作,但对于抢锁这样的业务,则无法用原生接口实现。

比如实现一个分布式锁,加锁过程可以使用set命令实现

red:set(key, name, "NX", "EX", ttl)

但是解锁过程却不能简单使用del删除,因为锁有过期时间,过期后被其它人获取到,再进行释放就产生了bug。

所以先判断是否自己再进行删除

if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
例可重入锁的实现:
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('setex', KEYS[1], ARGV[2], ARGV[1]) else return redis.call('set', KEYS[1], ARGV[1], 'ex', ARGV[2], 'nx') end

实现复杂逻辑

下面例子用zset实现时间戳队列,更新超时时间的算法。当用两次操作取出再放入时,会有丢数据风险,因此用脚本实现

redis.call('zrangebyscore', KEYS[1], ARGV[1], ARGV[2], 'limit', ARGV[3], ARGV[4])\
if #ret > 0 then\
local val = {}\
for i = 1, #ret do\
val[2 * i - 1] = ARGV[5]\
val[2 * i] = ret[i]\
end\
redis.call('zadd',KEYS[1],unpack(val))\
end\
0条评论
0 / 1000
张****东
8文章数
0粉丝数
张****东
8 文章 | 0 粉丝
张****东
8文章数
0粉丝数
张****东
8 文章 | 0 粉丝
原创

redis使用lua脚本

2023-05-11 01:37:20
6
0

减少交互

原生接口支持丰富的数据结构,但对有些操作支持的不够好。

比如在对key进行设置时,可以同时写入超时时间。这样在一条指令中就可以完成。

如果是incr操作,原生没有提供超时时间参数,需要调用两次接口实现。

可能产生的问题是,一是如果第一条操作后程序出现问题,导致超时时间没有设置,则会造成redis内存无法释放。二是多了一次网络交互,会增加业务的响应延迟。

因此在使用lua脚本把两条操作合并,可以达到减少交互的作用。

实现原子操作

redis本身是单线程执行,可以实现原子操作,但对于抢锁这样的业务,则无法用原生接口实现。

比如实现一个分布式锁,加锁过程可以使用set命令实现

red:set(key, name, "NX", "EX", ttl)

但是解锁过程却不能简单使用del删除,因为锁有过期时间,过期后被其它人获取到,再进行释放就产生了bug。

所以先判断是否自己再进行删除

if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
例可重入锁的实现:
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('setex', KEYS[1], ARGV[2], ARGV[1]) else return redis.call('set', KEYS[1], ARGV[1], 'ex', ARGV[2], 'nx') end

实现复杂逻辑

下面例子用zset实现时间戳队列,更新超时时间的算法。当用两次操作取出再放入时,会有丢数据风险,因此用脚本实现

redis.call('zrangebyscore', KEYS[1], ARGV[1], ARGV[2], 'limit', ARGV[3], ARGV[4])\
if #ret > 0 then\
local val = {}\
for i = 1, #ret do\
val[2 * i - 1] = ARGV[5]\
val[2 * i] = ret[i]\
end\
redis.call('zadd',KEYS[1],unpack(val))\
end\
文章来自个人专栏
直播
8 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0