Redis与Lua脚本

Redis与Lua脚本

EVAL/EVALSHA命令实现

EVAL命令

通过执行redis的eval命令,可以运行一段lua脚本。

EVAL script numkeys key [key ...] arg [arg ...]
  • script参数:是一段Lua脚本程序,它会被运行在Redis服务器上下文中,这段脚本不必(也不应该)
    定义为一个Lua函数。
  • numkeys参数:用于指定键名参数的个数。
  • key [key …]参数: 从EVAL的第三个参数开始算起,使用了numkeys个键(key),表示在脚本中
    所用到的那些Redis键(key),这些键名参数可以在Lua中通过全局变量KEYS数组,用1为基址的形
    式访问( KEYS[1] , KEYS[2] ,以此类推)。
  • arg [arg …]参数:可以在Lua中通过全局变量ARGV数组访问,访问的形式和KEYS变量类似(
    ARGV[1] 、 ARGV[2] ,诸如此类)。
eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second

lua脚本中调用Redis命令

  • redis.call():
    返回值就是redis命令执行的返回值
    如果出错,则返回错误信息,不继续执行
  • redis.pcall():
    返回值就是redis命令执行的返回值
    如果出错,则记录错误信息,继续执行
  • 注意事项
    在脚本中,使用return语句将返回值返回给客户端,如果没有return,则返回nil

EVALSHA

EVAL 命令要求你在每次执行脚本的时候都发送一次脚本主体(script body)。

Redis 有一个内部的缓存机制,因此它不会每次都重新编译脚本,不过在很多场合,付出无谓的带宽来
传送脚本主体并不是最佳选择。

为了减少带宽的消耗, Redis 实现了 EVALSHA 命令,它的作用和 EVAL 一样,都用于对脚本求值,但
它接受的第一个参数不是脚本,而是脚本的 SHA1 校验和(sum);

SCRIPT命令

SCRIPT FLUSH

清除所有脚本缓存

SCRIPT EXISTS

根据给定的脚本校验和,检查指定的脚本是否存在于脚本缓存

SCRIPT LOAD

将一个脚本装入脚本缓存,返回SHA1摘要,但并不立即运行它

SCRIPT KILL

杀死当前正在运行的脚本

脚本管理命令实现

使用redis-cli直接执行lua脚本
脚本内容:

return redis.call('set',KEYS[1],ARGV[1])

脚本执行

./redis-cli -h 127.0.0.1 -p 6379 --eval my.lua name:1 jiabin

利用Redis整合Lua,主要是为了性能以及事务的原子性。因为redis帮我们提供的事务功能太差。

脚本复制

Redis 传播 Lua 脚本,在使用主从模式和开启AOF持久化的前提下,当执行lua脚本时,Redis 服务器有两种模式:脚本传播模式和命令传播模式。

脚本传播模式

脚本传播模式是 Redis 复制脚本时默认使用的模式

Redis会将被执行的脚本及其参数复制到 AOF 文件以及从服务器里面。

执行以下命令:

eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 name1 name2 jiabin1 jiabin2

主服务器将向从服务器发送完全相同的 eval 命令

  • 在这一模式下执行的脚本不能有时间、内部状态、随机函数(spop)等。执行相同的脚本以及参数
    必须产生相同的效果。在Redis5,也是处于同一个事务中。

命令传播模式

处于命令传播模式的主服务器会将执行脚本产生的所有写命令用事务包裹起来,然后将事务复制到 AOF
文件以及从服务器里面。

因为命令传播模式复制的是写命令而不是脚本本身,所以即使脚本本身包含时间、内部状态、随机函数
等,主服务器给所有从服务器复制的写命令仍然是相同的。

为了开启命令传播模式,用户在使用脚本执行任何写操作之前,需要先在脚本里面调用以下函数:

redis.replicate_commands()

redis.replicate_commands() 只对调用该函数的脚本有效:在使用命令传播模式执行完当前脚本之后,
服务器将自动切换回默认的脚本传播模式。

执行以下命令:

eval "redis.replicate_commands();redis.call('set',KEYS[1],ARGV[1]);redis.call('set',K EYS[2],ARGV[2])" 2 name1 name2 jiabin1 jiabin2

管道(pipeline),事务和脚本(lua)三者的区别

  • 三者都可以批量执行命令
  • 管道无原子性,命令都是独立的,属于无状态的操作
  • 事务和脚本是有原子性的,其区别在于脚本可借助Lua语言可在服务器端存储的便利性定制和简化操作
  • 脚本的原子性要强于事务,脚本执行期间,另外的客户端 其它任何脚本或者命令都无法执行,脚本的执
    行时间应该尽量短,不能太耗时的脚本
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

果丶果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值