Redis从2.6版本开始引入对Lua脚本的支持,通过在服务器中嵌入Lua环境,Redis客户端可以使用Lua脚本,直接在服务端原子的执行多个Redis命令。
lua脚本的好处:
  减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延
  原子操作。redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无需使用事务。
  复用。客户端发送的脚步会永久存在redis中,这样,其他客户端可以复用这一脚本而不需要使用代码完成相同的逻辑。
 

1.在redis里使用EVAL和EVALSHA

可以使用EVAL命令对输入的脚本进行接受结果
  如:   Eval "return 1+1" 0
  ——>(integer)2
而使用evalsha 命令则可以根据脚本的SHA1校验和对接受脚本的结果,但这个命令要求校验和对应的脚本必须至少执行过一次或者这个校验和对应的脚本被scriptload加载过。
 
  如:
  script load "return 1+2" // 会返回一个sha校验
  ->"e13c398af9f2658ef7050acf3b266f87cXXXXXX"
  ->evalsha "e13c398af9f2658ef7050acf3b266f87cXXXXXX" 0
  ->(integer) 3
在脚本比较长的情况下,如果每次调用脚本都需要将整个脚本传给Redis会占用较多的带宽。为了解决这个问题,Redis提供了EVALSHA命令,允许开发者通过脚本内容的SHA1摘要来执行脚本,该命令的用法和EVAL一样,只不过是将脚本内容替换成脚本内容的SHA1摘要。
 
 

2.伪客户端

因为执行Redis命令必须有相应的客户端状态,所以为了执行Lua脚本中包含的Redis命令,Redis服务器专门为Lua环境创建了一个伪客户端,并由这个伪客户端负责处理Lua脚本中包含的所有Redis命令。
Lua脚本使用redis.call函数或者redis.pcall函数执行一个Redis命令,需要完成以下步骤:
  (1).Lua环境将redis.call函数或者redis.pcall函数想要执行的命令传给伪客户端。
  (2).伪客户端将脚本想要执行的命令传给命令执行器。
  (3).命令执行器执行伪客户端传给它的命令,并将命令的执行结果返回给伪客户端。
  (4).伪客户端接收命令执行器返回的命令结果,并将这个命令结果返回给Lua环境。
  (5).Lua环境在接收到命令结果以后,将该结果返回给redis.call函数或者redis.pcall函数。
  (6).接收到结果的redis.call函数或者redis.pcall函数会将命令结果作为函数返回值给脚本中的调用者。

3.lua_scripts字典

除了伪客户端之外,Redis服务器伪Lua环境创建了另一个协作组件是lua_scripts字典,这个字典的键为某个Lua脚本的SHA1校验和(checksum),而字典的值则是SHA1校验和对应的Lua脚本:
如:
  script load "retrun 1+1"
  -> "e13c398af9f2658ef7050acf3b266f87cXXXXXX"
 
这个返回值和载入的脚本是一一对应关系,这个校验值会存在script字典里。服务器会将所有被eval命令执行过的lua脚本,以及被scriptload载入过的脚本保存在字典里。
 
lua_script字典的两个作用
  (1).一个是实现script exists命令
  (2).实现脚本复制功能。
 

4.EVAL命令的实现

EVAL命令的执行过程可以分为以下三个步骤:
  (1)根据客户端给定的Lua脚本,在Lua环境中定义一个Lua函数。
  (2)将客户端给定的脚本保存到lua_scripts字典,等待将来进一步说明。
  (3)执行刚刚才Lua环境中定义的函数,以此来执行客户端给定的Lua脚本。

5.Redis管理Lua脚本

  (1).script load 
  此命令用于将Lua脚本加载到Redis内存中 
  (2).script exists 
  scripts exists sha1 [sha1 …] 
  此命令用于判断sha1是否已经加载到Redis内存中 
  (3).script flush 
  此命令用于清除Redis内存已经加载的所有Lua脚本,在执行script flush后,sha1不复存在。 
  (4).script kill 
  此命令用于杀掉正在执行的Lua脚本。
  6.redis.call和pcall

6.redsi编写lua脚本

语法:
  $ redis-cli --eval path/to/redis.lua KEYS[1] KEYS[2] , ARGV[1] ARGV[2] ...
  --eval,告诉redis-cli读取并运行后面的lua脚本
  path/to/redis.lua,是lua脚本的位置
  KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取
  ARGV[1] ARGV[2],参数,在lua脚本中通过ARGV[1], ARGV[2]获取。
注意:
  KEYS和ARGV中间的 ',' 两边的空格,不能省略。
 
如:
  redis.call('set', 'foo', 'bar')
  local value=redis.call('get', 'foo') --value的值为bar
redis.pcall函数,功能与redis.call相同,唯一的区别是当命令执行出错时,redis.pcall会记录错误并继续执行,而redis.call会直接返回错误,不会继续执行。
 
 
 

在redis里面使用lua的更多相关文章

  1. Redis进阶实践之十九 Redis如何使用lua脚本

    一.引言               redis学了一段时间了,基本的东西都没问题了.从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何平台上,也可以嵌入 ...

  2. 在redis中使用lua脚本

    在实际工作过程中,可以使用lua脚本来解决一些需要保证原子性的问题,而且lua脚本可以缓存在redis服务器上,势必会增加性能. 不过lua也会有很多限制,在使用的时候要注意. 在Redis中执行Lu ...

  3. redis中使用lua脚本

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

  4. 新姿势!Redis中调用Lua脚本以实现原子性操作

    背景:有一服务提供者Leader,有多个消息订阅者Workers.Leader是一个排队程序,维护了一个用户队列,当某个资源空闲下来并被分配至队列中的用户时,Leader会向订阅者推送消息(消息带有唯 ...

  5. Redis中的原子操作(2)-redis中使用Lua脚本保证命令原子性

    Redis 如何应对并发访问 使用 Lua 脚本 Redis 中如何使用 Lua 脚本 EVAL EVALSHA SCRIPT 命令 SCRIPT LOAD SCRIPT EXISTS SCRIPT ...

  6. 在redis中使用lua脚本让你的灵活性提高5个逼格

    在redis的官网上洋洋洒洒的大概提供了200多个命令,貌似看起来很多,但是这些都是别人预先给你定义好的,但你却不能按照自己的意图进行定制, 所以是不是感觉自己还是有一种被束缚的感觉,有这个感觉就对了 ...

  7. StackExchange.Redis加载Lua脚本进行模糊查询的批量删除和修改

    前言 使用StackExchange.Redis没有直接相关的方法进行模糊查询的批量删除和修改操作,虽然可以通过Scan相关的方法进行模糊查询,例如:HashScan("hashkey&qu ...

  8. Php+Redis 实现Redis提供的lua脚本功能

    <?php require_once "predis-0.8/autoload.php"; $config['schema'] = 'tcp'; $config['host' ...

  9. python redis客户端使用lua脚本

    有一个需求,为一个key设置一个field存储时间戳,每当有新数据,判断新数据时间戳是否大于之前的时间戳,如果是,更新时间戳,由于依赖中间执行结果,所以使用lua减少客户端和服务端通信次数. #!/u ...

随机推荐

  1. Robot Framework xpath定位不到元素

    不要使用Click Button关键字-严格来说,该关键字适用于该<button>类型的html元素. 而是使用Click Element-您的目标元素是<a>,然后Click ...

  2. centos7安装dockers

    安装Docker我是虚拟机装的Centos7,linux 3.10 内核,docker官方说至少3.8以上,建议3.10以上(ubuntu下要linux内核3.8以上, RHEL/Centos 的内核 ...

  3. [深度学习] R-CNN系论文略读

    总结: 一.R-CNN 摘要: 在对象检测方面,其性能在前几年就达到了一个比较稳定的状态.性能最好的方法是一种复杂的整体系统,它将多个图片的低级特征通过上下文组合起来. 本文提出了一种简单.可扩展的算 ...

  4. 好多坑的升级 phpStudy 中 MySQL 版本至 5.7.17

      由于本地用的集成环境是 phpStudy 2016,没有找到升级 MySQL 版本的选项,所以自己升级一下. 从官网上下载高版本的 MySQL :https://dev.mysql.com/dow ...

  5. 手动升级 Confluence 6 - 升级问题解决

    升级失败了? 如果你需要对你的升级进行回退,你必须首先恢复你老的 Confluence 备份.不要尝试再次进行升级,也不要尝试再次对升级失败的 Confluence 进行再次启动.  在升级过程中遇到 ...

  6. ABI与ARM,X86的概念

    Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2 ...

  7. JavaWeb_客户端相对/绝对路径和服务器端路径

    客户端的绝对路径和相对路径 相对路径:相对与某个基准目录的路径,在同一根目录下各子目录文件之间的相互引用, 绝对路径:指目录下的绝对位置,直接到的目标位置 @charset "UTF-8&q ...

  8. JIRA7.13版本创建项目:工作流(二)

    工作流 在上一篇文章中,我们新建了一个问题类型,并且增加到问题类型方案里了,同时又关联到我们的这个项目中.那么这些问题我们需要如何设置流程走向来表示问题的处理过程呢?这就需要设定一个流程,并将这个流程 ...

  9. XFF和referer

    XFF构造来源IP Refer构造来源浏览器

  10. akka 的集群访问方式

    akka  中采用startProxy分区代理 访问 ,跟使用shardRegion 来访问的区别 这两种访问方式是不是重了呢. 而另外这是一个单例代理 private fun startUniver ...