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. PHP preg_match正则表达式

    行定位符 ^表示开始 $表示结束 preg_match(模式,待搜索的字符串,$matches) 其中matches为可选参数,一旦匹配上,可以返回匹配结果 举个例子: $pattern = '/#\ ...

  2. matplotlib动画

    注意:要有动画效果,必须独立窗口:独立窗口的设置方法:https://www.cnblogs.com/liming19680104/p/10614070.html import matplotlib. ...

  3. k8s配置文件模板

    一,deployment Deployment为Pod和Replica Set下一代Replication Controller)提供声明式更新 1,配置示例 apiVersion: apps/v1 ...

  4. BZOJ 4668: 冷战 并查集启发式合并/LCT

    挺好想的,最简单的方法是并查集启发式合并,加暴力跳父亲. 然而,这个代码量比较小,比较好写,所以我写了 LCT,更具挑战性. #include <cstdio> #include < ...

  5. Protocol Buffers 开发者指南

    欢迎来到 protocol buffers 的开发者指南.protocol buffers 是一个语言中立,平台中立针对通讯协议,数据存储和其他领域中对结构化数据进行序列化的扩展方法. 本文档主要针对 ...

  6. HGOI20190813 省常中互测6

    Problem A 蛋糕 将$n \times m $大小的蛋糕切成每块为$1 \times 1$大小的$n\times m$块. 交换任意两块蛋糕的切割顺序的方案算作一种. 对于$100 \%$的数 ...

  7. 学习sklearn聚类使用

    学习利用sklearn的几个聚类方法: 一.几种聚类方法 1.高斯混合聚类(mixture of gaussians) 2.k均值聚类(kmeans) 3.密度聚类,均值漂移(mean shift) ...

  8. SQLMAP自注入--INJECTION TECGBUQUES FINGERPRINT

    -p参数 指定扫描的参数 ,使--level失效 -p“user-agent,refer”这些参数也可以通过-p来指定 sqlmap.py -u "http://127.0.0.1/muti ...

  9. Spring boot之配置server信息

    知识点: 1.修改端口号 2.修改context-path 3.其它配置说明 配置端口号: Spring boot 默认端口是8080, 如果想要进行更改的话, 只需要修改applicatoin.pr ...

  10. STS热部署方法(springboot)

    sts热部署,即是在项目中修改代码不用重新启动服务,提高效率.   方法如下: 1.在pom文件中引入  devtools  依赖: <dependency> <groupId> ...