纵有疾风起
人生不言弃

Redis使用Lua脚本

1. 基本用法

1.1 EVAL script numkeys key [key …] arg [arg …] 

numkeys 是key的个数,后边接着写key1 key2…  val1 val2….,举例

127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 val1 val21) "key1"2) "key2"3) "val1"4) "val2"

 

1.2 SCRIPT LOAD script 

把脚本加载到脚本缓存中,返回SHA1校验和。但不会立马执行,举例

127.0.0.1:6379> SCRIPT LOAD "return 'hello world'""5332031c6b470dc5a0dd9b4bf2030dea6d65de91"

 

1.3 EVALSHA sha1 numkeys key [key …] arg [arg …] 

根据缓存码执行脚本内容。举例

127.0.0.1:6379> SCRIPT LOAD "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" "a42059b356c875f0717db19a51f6aaca9ae659ea"127.0.0.1:6379> EVALSHA "a42059b356c875f0717db19a51f6aaca9ae659ea" 2 key1 key2 val1 val21) "key1"2) "key2"3) "val1"4) "val2"

 

1.4 SCRIPT EXISTS script [script …] 

通过sha1校验和判断脚本是否在缓存中

 

1.5 SCRIPT FLUSH 

清空缓存

127.0.0.1:6379> SCRIPT LOAD "return 'hello jihite'""3a43944275256411df941bdb76737e71412946fd"127.0.0.1:6379> SCRIPT EXISTS "3a43944275256411df941bdb76737e71412946fd"1) (integer) 1127.0.0.1:6379> SCRIPT FLUSHOK127.0.0.1:6379> SCRIPT EXISTS "3a43944275256411df941bdb76737e71412946fd"1) (integer) 0

 

1.6 SCRIPT KILL 

杀死目前正在执行的脚本

2. 主要优势

减少网络开销:多个请求通过脚本一次发送,减少网络延迟

原子操作:将脚本作为一个整体执行,中间不会插入其他命令,无需使用事务

复用:客户端发送的脚本永久存在redis中,其他客户端可以复用脚本

可嵌入性:可嵌入JAVA,C#等多种编程语言,支持不同操作系统跨平台交互

3. 实战

直接在redis-cli中直接写lua脚本,这样非常不方便编辑,通常情况下我们都是把lua script放到一个lua文件中,然后执行这个lua脚本,

示例:活跃用户判断:判断一个游戏用户是否属于活跃用户,如果符合标准,则活跃用户人数+1

if redis.call("EXISTS",KEYS[1]) == 1 then     return redis.call("INCRBY",KEYS[1],ARGV[1])   else     return nil   end

存储位置:

/Users/jihite/activeuser.lua

执行

$ redis-cli --eval /Users/jihite/activeuser.lua user , 1(integer) 1127.0.0.1:6379> get user"1"127.0.0.1:6379> exit$ redis-cli --eval /Users/jihite/activeuser.lua user , 1(integer) 2$ redis-cli 127.0.0.1:6379> get user"2"127.0.0.1:6379> exit$ redis-cli --eval /Users/jihite/activeuser.lua user , 4(integer) 6

4. 脚本的安全性

如生成随机数这一命令,如果在master上执行完后,再在slave上执行会不一样,这就破坏了主从节点的一致性

为了解决这个问题, Redis 对 Lua 环境所能执行的脚本做了一个严格的限制 —— 所有脚本都必须是无副作用的纯函数(pure function)。所有刚才说的那种情况压根不存在。Redis 对 Lua 环境做了一些列相应的措施:

  • 不提供访问系统状态状态的库(比如系统时间库)
  • 禁止使用 loadfile 函数
  • 如果脚本在执行带有随机性质的命令(比如 RANDOMKEY ),或者带有副作用的命令(比如 TIME )之后,试图执行一个写入命令(比如 SET ),那么 Redis 将阻止这个脚本继续运行,并返回一个错误。
  • 如果脚本执行了带有随机性质的读命令(比如 SMEMBERS ),那么在脚本的输出返回给 Redis 之前,会先被执行一个自动的字典序排序,从而确保输出结果是有序的。
  • 用 Redis 自己定义的随机生成函数,替换 Lua 环境中 math 表原有的 math.random 函数和 math.randomseed 函数,新的函数具有这样的性质:每次执行 Lua 脚本时,除非显式地调用 math.randomseed ,否则 math.random 生成的伪随机数序列总是相同的。

参考

https://www.runoob.com/redis/redis-scripting.html    (基本使用)

https://www.cnblogs.com/Don/articles/5731856.html   (实例)

https://www.cnblogs.com/huangxincheng/p/6230129.html 

https://redisbook.readthedocs.io/en/latest/feature/scripting.html#lua  (安全性)

 

文章转载于:https://www.cnblogs.com/kaituorensheng/p/11098194.html

原著是一个有趣的人,若有侵权,请通知删除

未经允许不得转载:起风网 » Redis使用Lua脚本
分享到: 生成海报

评论 抢沙发

评论前必须登录!

立即登录