嗨客网搜索
Redis-cli命令
Redis脚本教程

Redis脚本教程

从 Redis 2.6.0 版本开始,通过 Redis 内置的 Lua 解释器,可以实现在 Redis 中运行 Lua 脚本。

Lua 脚本功能是 Reids 2.6 版本的最大亮点, 通过内嵌对 Lua 环境的支持, Redis 解决了长久以来不能高效地处理 CAS (check-and-set)命令的缺点, 并且可以通过组合使用多个命令, 轻松实现以前很难实现或者不能高效实现的模式。

Redis脚本主要优势

优势 描述
减少网络开销 多个请求通过脚本一次发送,减少网络延迟。
原子操作 将脚本作为一个整体执行,中间不会插入其他命令,无需使用 事务
复用 客户端发送的脚本永久存在 Redis 中,其他客户端可以复用脚本。
可嵌入性 可嵌入 JAVA,C# 等多种编程语言,支持不同操作系统跨平台交互。

脚本的原子性

Redis 使用单个 Lua 解释器去运行所有脚本,并且 Redis 也保证脚本会以原子性(atomic)的方式执行:当某个脚本正在运行的时候,不会有其他脚本或 Redis 命令被执行。这和使用 MULTI / EXEC 包围的事务很类似。在其他别的客户端看来,脚本的效果(effect)要么是不可见的(not visible),要么就是已完成的(already completed)。

另一方面,这也意味着,执行一个运行缓慢的脚本并不是一个好主意。写一个跑得很快很顺溜的脚本并不难,因为脚本的运行开销(overhead)非常少,但是当你不得不使用一些跑得比较慢的脚本时,请小心,因为当这些蜗牛脚本在慢吞吞地运行的时候,其他客户端会因为服务器正忙而无法执行命令。

脚本的安全性

如生成随机数这一命令,如果在 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 生成的伪随机数序列总是相同的。

脚本缓存

Redis 保证所有被运行过的脚本都会被永久保存在脚本缓存当中,这意味着,当 EVAL 命令在一个 Redis 实例上成功执行某个脚本之后,随后针对这个脚本的所有 EVALSHA 命令都会成功执行。

刷新脚本缓存的唯一办法是显式地调用 SCRIPT FLUSH 命令,这个命令会清空运行过的所有脚本的缓存。通常只有在云计算环境中,Redis 实例被改作其他客户或者别的应用程序的实例时,才会执行这个命令。

缓存可以长时间储存而不产生内存问题的原因是,它们的体积非常小,而且数量也非常少,即使脚本在概念上类似于实现一个新命令,即使在一个大规模的程序里有成百上千的脚本,即使这些脚本会经常修改,即便如此,储存这些脚本的内存仍然是微不足道的。

事实上,用户会发现 Redis 不移除缓存中的脚本实际上是一个好主意。比如说,对于一个和 Redis 保持持久化链接(persistent connection)的程序来说,它可以确信,执行过一次的脚本会一直保留在内存当中,因此它可以在流水线中使用 EVALSHA 命令而不必担心因为找不到所需的脚本而产生错误(稍候我们会看到在流水线中执行脚本的相关问题)。

Redis Lua脚本相关命令

命令 描述
EVAL script numkeys key [key …] arg [arg …] 执行 Lua 脚本
EVALSHA sha1 numkeys key [key …] arg [arg …] 执行 Lua 脚本
SCRIPT EXISTS script [script …] 查看指定的脚本是否已经被保存在缓存当中
SCRIPT FLUSH 从脚本缓存中移除所有脚本
SCRIPT KILL 杀死当前正在运行的 Lua 脚本
SCRIPT LOAD script 将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本

案例

Redis Lua 脚本的使用

127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 name age haicoder 109 1) "name" 2) "age" 3) "haicoder" 4) "109"

我们使用 EVAL 执行了一个 Lua 脚本。

Redis脚本总结

从 Redis 2.6.0 版本开始,通过 Redis 内置的 Lua 解释器,可以实现在 Redis 中运行 Lua 脚本。

嗨客网顶部