介绍
在这个实验中,你将探索 Redis Lua 脚本,重点是在 Redis 中直接执行 Lua 脚本,以高效地执行复杂的操作。本实验涵盖使用 EVAL 命令执行脚本、将参数传递给脚本、使用 SCRIPT LOAD 加载脚本以及使用 EVALSHA 运行已加载的脚本。
我们将从执行一个简单的 Lua 脚本开始,该脚本使用 EVAL 递增 Redis 计数器,演示如何指定脚本、它访问的键的数量以及键名。然后,我们将学习如何将脚本加载到 Redis 中,并使用其 SHA1 哈希值执行它们,从而通过避免重复的脚本传输来提高性能。
使用 EVAL 执行 Lua 脚本
在此步骤中,我们将探索如何使用 EVAL 命令直接在 Redis 中执行 Lua 脚本。这允许你在单个请求中对数据执行复杂的操作,从而减少网络延迟并提高性能。
在我们开始之前,让我们了解 EVAL 的基础知识。 EVAL 命令接受两个主要参数:
- Lua 脚本本身,作为一个字符串。
- 脚本将访问的键的数量,后跟实际的键名和你想要传递给脚本的任何其他参数。
这是一个简单的示例,可帮助你入门。我们将创建一个 Lua 脚本,该脚本递增 Redis 计数器并返回新值。
打开你的终端并使用 Redis 命令行界面 (
redis-cli) 连接到 Redis 服务器。redis-cli现在,让我们使用
EVAL执行 Lua 脚本。此脚本将递增名为mycounter的计数器,并返回递增后的值。EVAL "local current = redis.call('INCR', KEYS[1]); return current" 1 mycounter让我们分解一下这个命令:
EVAL "local current = redis.call('INCR', KEYS[1]); return current":这是 Lua 脚本本身。它使用redis.call('INCR', KEYS[1])递增KEYS[1]中指定的键的值。KEYS数组包含传递给脚本的键名。最后,它返回递增后的值。1:这表示脚本将访问一个键。mycounter:这是脚本将访问的键的名称。
你应该看到类似于以下的输出:
(integer) 1如果再次运行相同的命令,你将看到计数器递增:
EVAL "local current = redis.call('INCR', KEYS[1]); return current" 1 mycounter输出:
(integer) 2让我们使用
GET命令验证mycounter键的值:GET mycounter输出:
"2"正如你所看到的,Lua 脚本成功地递增了计数器。
现在,让我们尝试另一个例子。这次,我们将创建一个脚本,如果某个键尚不存在,则将其设置为特定值。
EVAL "if redis.call('EXISTS', KEYS[1]) == 0 then redis.call('SET', KEYS[1], ARGV[1]); return 1 else return 0 end" 1 mykey myvalue在此命令中:
EVAL "if redis.call('EXISTS', KEYS[1]) == 0 then redis.call('SET', KEYS[1], ARGV[1]); return 1 else return 0 end":这是 Lua 脚本。它检查键KEYS[1]是否存在。如果不存在,它会将键设置为值ARGV[1]并返回1。否则,它返回0。1:这表示脚本将访问一个键。mykey:这是键的名称。myvalue:如果键不存在,则设置为该值。
你应该看到类似于以下的输出:
(integer) 1这表示键
mykey已设置为myvalue。让我们检查
mykey的值:GET mykey输出:
"myvalue"如果再次运行
EVAL命令:EVAL "if redis.call('EXISTS', KEYS[1]) == 0 then redis.call('SET', KEYS[1], ARGV[1]); return 1 else return 0 end" 1 mykey myvalue输出:
(integer) 0这次,脚本返回
0,因为该键已存在。退出
redis-cli。这对于记录更改非常重要。exit
使用 EVAL 向脚本传递参数
在上一步中,我们学习了如何使用 EVAL 执行 Lua 脚本并访问键。现在,让我们探索如何将参数传递给这些脚本。这允许创建更动态和可重用的脚本。
回想一下,EVAL 命令接受以下参数:
- Lua 脚本本身,作为一个字符串。
- 脚本将访问的键的数量。
- 键名。
- 你想要传递给脚本的任何其他参数。这些参数在 Lua 脚本中使用
ARGV数组访问。
让我们从一个例子开始。我们将创建一个 Lua 脚本,该脚本将一个值添加到 Redis 计数器。计数器的键和要添加的值将作为参数传递。
使用 Redis 命令行界面 (
redis-cli) 连接到 Redis 服务器。redis-cli现在,让我们使用
EVAL执行一个 Lua 脚本,该脚本将计数器递增指定的量。EVAL "local current = redis.call('INCRBY', KEYS[1], ARGV[1]); return current" 1 mycounter 5让我们分解一下这个命令:
EVAL "local current = redis.call('INCRBY', KEYS[1], ARGV[1]); return current":这是 Lua 脚本。它使用redis.call('INCRBY', KEYS[1], ARGV[1])将KEYS[1]中指定的键的值递增ARGV[1]中指定的量。1:这表示脚本将访问一个键。mycounter:这是脚本将访问的键的名称。5:这是将传递给脚本并作为ARGV[1]访问的参数。
你应该看到类似于以下的输出(假设
mycounter从上一步开始为 2):(integer) 7该脚本将
mycounter键递增了 5。让我们使用
GET命令验证mycounter键的值:GET mycounter输出:
"7"现在,让我们尝试另一个带有字符串参数的示例。我们将创建一个脚本,该脚本将一个键设置为一个值,其中键和值都作为参数传递。
EVAL "redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]" 1 mynewkey mynewvalue在此命令中:
EVAL "redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]":这是 Lua 脚本。它将键KEYS[1]设置为值ARGV[1]并返回值。1:这表示脚本将访问一个键。mynewkey:这是键的名称。mynewvalue:这是要设置的值。
你应该看到类似于以下的输出:
"mynewvalue"让我们检查
mynewkey的值:GET mynewkey输出:
"mynewvalue"该脚本成功地将键
mynewkey设置为值mynewvalue。你可以将多个参数传递给脚本。例如,让我们创建一个脚本,该脚本连接作为参数传递的两个字符串,并将结果设置为一个键。
EVAL "local result = ARGV[1] .. ARGV[2]; redis.call('SET', KEYS[1], result); return result" 1 combinedkey hello world在此命令中:
EVAL "local result = ARGV[1] .. ARGV[2]; redis.call('SET', KEYS[1], result); return result":这是 Lua 脚本。它使用..运算符连接ARGV[1]和ARGV[2],将键KEYS[1]设置为结果,并返回结果。1:这表示脚本将访问一个键。combinedkey:这是键的名称。hello:这是第一个字符串参数。world:这是第二个字符串参数。
你应该看到类似于以下的输出:
"helloworld"让我们检查
combinedkey的值:GET combinedkey输出:
"helloworld"退出
redis-cli。这对于记录更改非常重要。exit
使用 SCRIPT LOAD 加载脚本
在之前的步骤中,我们使用 EVAL 命令直接执行 Lua 脚本。虽然这对于简单的脚本很有用,但对于更大、更复杂的脚本来说,它可能会变得很麻烦。Redis 提供了 SCRIPT LOAD 命令,用于将脚本加载到 Redis 服务器的脚本缓存中。这允许你多次执行脚本,而无需每次都发送整个脚本,从而提高性能。
SCRIPT LOAD 命令接受一个参数:Lua 脚本本身。它返回脚本的 SHA1 哈希值,然后你可以使用该哈希值通过 EVALSHA 命令执行脚本(我们将在下一步中介绍)。
让我们看看它是如何工作的。
使用 Redis 命令行界面 (
redis-cli) 连接到 Redis 服务器。redis-cli现在,让我们使用
SCRIPT LOAD加载一个 Lua 脚本。我们将使用与上一步中相同的脚本,该脚本将计数器递增指定的量。SCRIPT LOAD "local current = redis.call('INCRBY', KEYS[1], ARGV[1]); return current"此命令会将脚本加载到 Redis 服务器的脚本缓存中,并返回脚本的 SHA1 哈希值。你应该看到类似于以下的输出:
"6b1e8dd2999cb08546e74339c0c9489f9f89a84b"这是脚本的 SHA1 哈希值。记下此哈希值,因为你将在下一步中需要它。确切的哈希值可能会有所不同。
现在,让我们加载将键设置为值的脚本,其中键和值都作为参数传递。
SCRIPT LOAD "redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]"你应该看到类似于以下的输出:
"a8b2b3648969459a8198262a9166e945e890987c"同样,记下此哈希值。
让我们加载连接作为参数传递的两个字符串并将结果设置为键的脚本。
SCRIPT LOAD "local result = ARGV[1] .. ARGV[2]; redis.call('SET', KEYS[1], result); return result"你应该看到类似于以下的输出:
"d2a800a974ca96849295220424f9a0664a495345"也记下此哈希值。
你可以使用
SCRIPT EXISTS命令验证脚本是否已加载。此命令接受一个或多个 SHA1 哈希值作为参数,并返回一个由 0 和 1 组成的数组,其中 1 表示已加载具有相应哈希值的脚本,而 0 表示未加载。例如,要检查我们加载的第一个脚本是否仍然加载,请使用以下命令,将哈希值替换为你从步骤 2 中获得的哈希值:
SCRIPT EXISTS 6b1e8dd2999cb08546e74339c0c9489f9f89a84b输出:
1) (integer) 1这表示已加载该脚本。
如果你尝试检查未加载的脚本:
SCRIPT EXISTS 0000000000000000000000000000000000000000输出:
1) (integer) 0这表示未加载该脚本。
退出
redis-cli。这对于记录更改非常重要。exit
使用 EVALSHA 运行已加载的脚本
在上一步中,我们学习了如何使用 SCRIPT LOAD 命令将 Lua 脚本加载到 Redis 服务器的脚本缓存中。现在,我们将学习如何使用 EVALSHA 命令执行这些已加载的脚本。
EVALSHA 命令接受以下参数:
- 已加载脚本的 SHA1 哈希值。
- 脚本将访问的键的数量。
- 键名。
- 你想要传递给脚本的任何其他参数。
当你需要多次执行同一脚本时,使用 EVALSHA 比 EVAL 更有效,因为它避免了每次都将整个脚本发送到服务器。
让我们看看它是如何工作的。
使用 Redis 命令行界面 (
redis-cli) 连接到 Redis 服务器。redis-cli现在,让我们使用
EVALSHA执行将计数器递增指定量的 Lua 脚本。还记得你在上一步中获得的脚本local current = redis.call('INCRBY', KEYS[1], ARGV[1]); return current的 SHA1 哈希值吗?如果没有,你需要使用SCRIPT LOAD再次加载该脚本。在此示例中,我们假设哈希值为6b1e8dd2999cb08546e74339c0c9489f9f89a84b。EVALSHA 6b1e8dd2999cb08546e74339c0c9489f9f89a84b 1 mycounter 5让我们分解一下这个命令:
EVALSHA 6b1e8dd2999cb08546e74339c0c9489f9f89a84b:这指定我们要执行 SHA1 哈希值为6b1e8dd2999cb08546e74339c0c9489f9f89a84b的脚本。1:这表示脚本将访问一个键。mycounter:这是脚本将访问的键的名称。5:这是将传递给脚本并作为ARGV[1]访问的参数。
你应该看到类似于以下的输出(假设
mycounter从上一步开始为 7):(integer) 12该脚本将
mycounter键递增了 5。让我们使用
GET命令验证mycounter键的值:GET mycounter输出:
"12"现在,让我们使用
EVALSHA执行将键设置为值的脚本。还记得你在上一步中获得的脚本redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]的 SHA1 哈希值吗?如果没有,你需要使用SCRIPT LOAD再次加载该脚本。在此示例中,我们假设哈希值为a8b2b3648969459a8198262a9166e945e890987c。EVALSHA a8b2b3648969459a8198262a9166e945e890987c 1 anotherkey anothervalue你应该看到类似于以下的输出:
"anothervalue"让我们检查
anotherkey的值:GET anotherkey输出:
"anothervalue"如果你尝试使用无效的 SHA1 哈希值执行脚本,你将收到一个错误:
EVALSHA 0000000000000000000000000000000000000000 1 mykey myvalue输出:
(error) NOSCRIPT No matching script. Please use EVAL.这表示未加载具有指定 SHA1 哈希值的脚本。
退出
redis-cli。这对于记录更改非常重要。exit
总结
在这个实验中,你探索了 Redis Lua 脚本,重点是使用 EVAL 命令直接执行脚本。我们了解到 EVAL 接受 Lua 脚本作为字符串、访问的键的数量以及键名本身作为参数。我们练习了在 EVAL 中使用 Lua 脚本递增 Redis 计数器,观察了脚本如何访问和修改指定的键。
此外,我们还学习了如何将参数传递给 Lua 脚本,如何使用 SCRIPT LOAD 将脚本加载到 Redis 中,以及如何使用 EVALSHA 执行已加载的脚本。请记住在每个步骤之后退出 redis-cli,以确保正确记录你的命令。这允许更有效地执行复杂的脚本。


