三、Lua脚本

Redis中使用lua脚本

我们在使用redis时,会面临一些问题,比如
原子性问题
redis是单一线程的,但是仍然会存在线程安全问题,当然,这个线程安全问题不是来源于Redis服务器内部,而是redis作为数据服务器,是提供给客户端使用的,多个客户端的操作就相当于同一进程下的多个线程,如果多个客户端之间没有做好数据同步策略,就会产生数据不一致的问题,举个简单的例子,多个客户端的命令之间没有做请求同步,导致实际执行顺序可能会不一致,最终的结果也就无法满足原子性了。
效率问题
redis本身的吞吐量时非常高的,因为它首先是基于内存的数据库,在实际使用过程中,有一个非常重要的因素影响redis的吞吐量,那就是网络,我们在使用redis实现某些特定功能的时候,很可能需要多个命令或者多个数据类型的交互才能完成,那么这种多次网络请求对性能影响比较大,当然redis也做了一些优化,比如提供了pupeline管道操作,但是它有一定的局限性,就是执行的多个命令和响应之间是不存在相互依赖关系的,所有我们需要一种机制能够编写一些具有业务逻辑的命令,减少网络请求;

Lua

Redis中内嵌了对Lua环境的支持,允许开发者使用Lua语言编写脚本传到Redis中,Redis客户端可以使用Lua脚本直接在服务端原子的执行多个Redis命令
使用脚本的好处:
1.减少网络开销,在Lua脚本中可以把多个命令放在同一个脚本中允许,
2.原子操作,redis会将整个脚本作为一个整体执行,中间不会被其他命令插入,换句话说,编写脚本的过程中无需担心会出现竞态条件
3.复用性,客户端发送的脚本会永远存在redis中,这意味着其他客户端可以复用者已脚本来完成同样的逻辑。

Lua是一个高效的轻量级的脚本语言,用标准C语言编写并以源代码形式开放,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Redis和Lua

在Lua脚本中调用Redis命令
在Lua脚本中调用Redis命令,可以使用redis.call函数调用,比如我们调用string类型的命令

redis.call('set','hello','world')
local value = redis.call('get','hello')

redis.call函数的返回值就是redis命令的执行结果,前面我们介绍过redis的五种类型的数据返回的值也都不一样,redis.call函数会将这五种类型的返回值转化对应的Lua的数据类型

从Lua脚本中获取返回值
在很多情况下,我们都需要脚本可以有返回值,毕竟这个脚本也会一个我们所编写的命令集,我们可以像调用其他redis内置命令一样调用我们自己写的脚本,所有同样redis会自动将脚本返回值得Lua数据类型转换为Redis的返回值类型,在脚本中可以使用return预计将值返回给redis客户端,通过return语句来执行,如果没有执行return默许返回为null

EVAL命令的格式是

[EVAL][脚本内容][key参数的数量][key...][arg...]

可以通过key和arg这两个参数向脚本中传递数据,他们的值可以在脚本中分别使用KEYS和ARGV这两个类型的全局变量访问,比如我们通过脚本实现set命令,通过redis客户端中调用,那么执行的语句是:

return redis.call('set',KEYS[1],ARGV[1])//KEYS和ARGV必须大写
eval “return redis.call('set',KEYS[1],ARGV[1])" 1 lua1 hello

注意:EVAL命令是根据key参数的数量,也就是上面例子中的1来将后面所有参数分别存入脚本中的KEYS和ARGV两个表类型的全局变量,当脚本不需要任何参数时也不能省略这个参数,如果没有参数就为0

eval "return redis.call('get','lual') 0

EVALSHA 命令
考虑到我们通过eval执行lua脚本,脚本比较长的情况下,每次调用脚本都需要把整个脚本传给redis,比较占用带宽。为了解决这个问题,redis提供了EVALSHA命令允许开发者通过脚本内容的SHA1摘要来执行脚本。该命令的用法和EVAL一样,只不过是将脚本内容替换成脚本内容的SHA1摘要

  1. Redis在执行EVAL命令时会计算脚本的SHA1摘要并记录在脚本缓存中
  2. 执行EVALSHA命令时Redis会根据提供的摘要从脚本缓存中查找对应的脚本内容,如果找到了就执行脚本,否则返回“NOSCRIPT No matching script,Please use EVAL”
    通过以下案例来演示EVALSHA命令的效果
script load "return redis.call('get','lua1')" 将脚本加入缓存并生成sha1命令
evalsha "a5a402e90df3eaeca2ff03d56d99982e05cf6574" 0

我们在调用eval命令之前,先执行evalsha命令,如果提示脚本不存在,则再调用eval命令

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值