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. thinkphp5权限仿制

    权限列表 流程 thinkphp5封装好的权限模块 RBAC还有auth and then .......管理员表,可以依据auth.php搭建所有的权限表

  2. 开始PHP,常量/变量与内存间的关系--传值

    一.常见的PHP代码嵌入式方式,与html结合 要注意:文件名后缀必须形如xxx.php否则html将无法解析 二.php脱离html代码独立工作,没有其他代码 不需要借助Apache工作,只需要ph ...

  3. Spark入Hbase的四种方式效率对比

    一.方式介绍 本次测试一种采用了四种方式进行了对比,分别是:1.在RDD内部调用java API.2.调用saveAsNewAPIHadoopDataset()接口.3.saveAsHadoopDat ...

  4. npoi 导入

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CusImport.aspx ...

  5. OpenCV笔记(2)(高斯平滑、腐蚀和膨胀、开闭运算、礼帽和黑帽、Sobel及其他算子)

    一.高斯平滑(模糊) def gaussian_blur(image): # 设置ksize来确定模糊效果 img = cv.GaussianBlur(image, (5, 5), 0) cv.ims ...

  6. TTTTTTTTTTTTTTTT POJ 2723 楼层里救朋友 2-SAT+二分

    Get Luffy Out Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8211   Accepted: 3162 Des ...

  7. codevs2370 小机房的树 x

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond   题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号 ...

  8. Hedera: Dynamic Flow Scheduling for Data Center Networks

    摘要: 当今的数据中心为成千上万台计算机的群集提供了巨大的聚合带宽, 但是即使在最高端的交换机中,端口密度也受到限制,因此数据中心拓扑通常由多根树组成,这些树在任何给定的主机对之间都具有许多等价路径. ...

  9. Hibernate持久化类规则

    注意事项: 提供无参的构造方法,因为在hibernate需要使用反射生成类的实例 提供私有属性,并对这些属性提供公共的setting和getting方法,因为在hibernate底层会将查询到的数据进 ...

  10. HashMap如何实现序列化

    /** * Save the state of the <tt>HashMap</tt> instance to a stream (i.e., * serialize it) ...