Redis Lua脚本编写快速指南

Redis Lua脚本编写快速指南

在这里插入图片描述

Redis是一种基于内存的用于进程间通信和数据存储的软件工具。您可能听说过它可以运行Lua脚本,但是您仍然不确定怎么使用。那么请继续阅读本文。

1、前置条件

您应该在系统上安装Redis才能运行本文中的例子。阅读本文时对照Redis命令参考可能会更有帮助。

2、为什么需要Lua脚本?

简而言之:性能提升。您在Redis中执行的大多数任务都涉及许多步骤。您可以使用Lua在Redis内部进行操作,而不必使用应用程序语言来执行这些步骤。

  • 这可能会导致更好的性能。
  • 同样,脚本中的所有步骤都以原子方式执行。执行脚本时,无法运行其他Redis命令。

例如,我使用Lua脚本改变存储在Redis的JSON字符串。我将在本文后半部分对此进行详细描述。

3、可是我什么都不知道

在这里插入图片描述

一个不认识Lua的人

别担心,Lua并不是很难理解。如果您了解C语言系列中的任何语言,那么您应该很容易上手Lua。另外,我在本文中提供了代码示例。

4、给我看个例子

让我们开始通过redis-cli运行脚本。从以下内容开始:

redis-cli

现在运行以下命令:

eval “redis.call(‘set’, KEYS[1], ARGV[1])” 1 key:name value

EVAL命令就是告诉Redis的运行下面的脚本。该”redis.call(‘set’, KEYS[1], ARGV[1])” 字符串是我们的脚本,其功能与Redis的set命令相同。脚本文本后面跟随三个参数:

  1. 键的个数
  2. 键名
  3. 键值

脚本参数分为两类:KEYSARGV

我们用紧随其后的数字指定脚本需要多少个键。在我们的示例中,该值为1。在此编号之后,我们需要立即接这些key。它们可以作为脚本中的KEYS表访问。在我们的例子中,它key:name在索引1处包含一个值。

注意,Lua索引表从索引 1开始,而不是0

我们可以在键之后提供任意数量的参数,这些参数可以在Lua中作为ARGV表使用。在此示例中,我们提供了一个ARGV参数:string value。您已经猜到了,上面的命令将键设置key:name为value value

提供脚本使用的key作为KEYS以及提供所有其他参数作为ARGV是一种好习惯。因此,您不应该将KEYS指定为0,然后在ARGV表中提供所有key。

现在让我们检查脚本是否成功完成。我们将通过运行另一个从Redis获取密钥的脚本来做到这一点:

eval “return redis.call(‘get’, KEYS[1])” 1 key:name

输出应该为”value”,这意味着先前的脚本成功设置了键值 “key:name”`。

5、你能解释一下脚本吗?

在这里插入图片描述

我们的第一个脚本包含一个语句:redis.call函数:

redis.call('set',KEYS [1],ARGV [1])

使用redis.call它可以执行任何Redis命令。第一个参数是此命令的名称,后跟其参数。对于set命令,这些参数是keyvalue。支持所有Redis命令。根据文档

Redis使用相同的Lua解释器来运行所有命令

我们的第二个脚本不仅仅运行一个命令,它还返回一个值:

eval “return redis.call(‘get’, KEYS[1])” 1 key:name

脚本返回的所有内容都发送到调用过程。在我们的情况下,此过程为redis-cli,您将在终端窗口中看到结果。

6、还有更复杂的东西吗?

我曾经使用Lua脚本以特定顺序从哈希映射中返回元素。顺序是存储在有序集order键中。

首先,通过在redis-cli中运行以下命令来设置数据:

hmset hkeys key:1 value:1 key:2 value:2 key:3 value:3 key:4 value:4 key:5 value:5 key:6 value:6
zadd order 1 key:3 2 key:1 3 key:2

这条命令处创建了一个名为:hkeys的哈希映射,filed名为:key:XXX ,order其中包含hkeys按特定顺序从中选择filed。

您可能需要查看hmsetzadd命令参考以获取详细信息。

让我们运行以下脚本:

eval “local order = redis.call(‘zrange’, KEYS[1], 0, -1); return redis.call(‘hmget’,KEYS[2],unpack(order));” 2 order hkeys

您应该看到以下输出:

“value:3”
“value:1”
“value:2”

这意味着我们以正确的顺序获得了所需hash filed的值。

7、是否必须指定完整的脚本文本才能运行它?

Redis允许您使用SCRIPT LOAD命令将脚本预加载到内存中:

script load “return redis.call(‘get’, KEYS[1])”

您应该看到如下输出:

“4e6d8fc8bb01276962cce5371fa795a7763657ae”

这是您需要提供给EVALSHA命令以运行脚本的脚本的唯一哈希:

evalsha 4e6d8fc8bb01276962cce5371fa795a7763657ae 1 key:name

注意:您应该使用SCRIPT LOAD命令返回的实际SHA1哈希,上面的哈希只是一个示例。

8、更改JSON的内容

有时人们在Redis中存储JSON对象。可以查看我前面一篇文章的讲解《Redis使用字符串和hash存储JSON,那个更高效?》。

如果必须在此JSON对象中更改key,则需要从Redis中获取key的value值,然后对其进行解析,更改key的value值,然后进行序列化并将其设置回Redis。这种方法存在两个问题:

  1. 并发。另一个过程可以在我们的get和set操作之间更改此JSON。在这种情况下,更改将丢失。
  2. 性能。如果您经常进行这些更改,并且json对象很大,则可能成为应用程序的瓶颈。您可以通过在Lua中实现此逻辑来提高一些性能。

让我们在key下的Redis中添加一个测试JSON字符串obj

set obj ‘{“a”:”foo”,”b”:”bar”}’

现在运行脚本:

EVAL ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(.. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’ 1 obj b bar2

现在我们将在key下具有以下对象obj

{“ a”:“ foo”,“ b”:“ bar2”}

您可以使用SCRIPT LOAD命令来加载此脚本,然后像这样运行它:

EVALSHA <your_script_sha> 1 obj b bar2

一些注意事项:

  • 脚本中..是Lua中字符串连接运算符。
  • 我们使用RegEx模式来匹配键并替换其值。
  • Lua RegEx风味与大多数其他风格的不同之处在于,我们%同时将它们用作RegEx特殊符号的回溯标记和转义字符。

9、我应该一直使用Lua脚本吗?

不。我建议仅在可以证明它可以带来更好的性能时才使用它们。首先都要做基准测试,确定性能会提高才需要使用lua脚本。如果您只需要原子性,则应改为检查Redis事务

另外,您的脚本不应太长。请记住,脚本运行时,其他所有内容都在等待脚本完成。如果您的脚本需要花费一些时间,则可能会导致瓶颈,而不是提高性能。脚本在达到超时(默认为5秒)后停止。有关Lua的更多信息,请访问lua.org

感谢您阅读本文。欢迎评论和转发。更多相关编程信息请关注我

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值