Skip to main content
 首页 » 数据库

介绍Redis中lua脚本应用

2022年07月19日124开发

介绍Redis中lua脚本应用

Redis即使从redis-cli客户端也可以实现神奇的事情,当然选择特定语言对应客户端一样可以。但是有时在C/S架构下有些功能不能有效或安全地实现————其逻辑需要在数据库层执行,这是就需要引入lua脚本。Lua是Redis中集成的脚本语言,使用lua可以自动执行一段代码,无需在客户端与服务器端之间传输。

示例需求

我们需要给hash结构中的字段追加值。我们知道Redis可以很容易使用append命名给字符串类型变量追价值,但没有相应命令给hash结构中的字段追加值。我们需要分步实现,首先从客户端获取字段值,然后追加新的内容给该值,最后从新设置hash字段值,这不是好办法。因为每一步都不是原子的,

no Client #1 Client #2
1 HGET myhash myfield – “hello”
2 [client appends “ world” to “hello”] HSET myhash myfield goodbye – 0
3 HSET myhash myfield “hello world” – 0
4 HGET myhash myfield – “hello world”

我们看到第二行更新字段值为"goodbye"丢失了。我们可以使用lua脚本助手解决该问题,并消除从客户端发送和接收信息的传输负载。

lua脚本实现

在文本编辑器中输入下列脚本,并命名为happend.lua:

local original = redis.call('HGET',KEYS[1],ARGV[1]) 
return redis.call('HSET',KEYS[1], ARGV[1], original .. ARGV[2]) 

第一行我们声明了局部变量original用于存储hash字段的当前值,通过keys[1]指定键,argv[1]指定字段名称。这里需要理解lua脚本中键与非键之间的执行差异。

第二行我们在相同的键和字段上执行HSET命令,并连接原来的值和传入的参数值:ARGV[2],然后返回Redis,所以,我们会保留HSET的返回值。

执行脚本

可以使用eval命令直接执行,这种方式比较麻烦且低效。redis内置脚本缓存机制,预加载脚本后通过对脚本执行SHA1摘要进行引用。下面代码使用cat和redis-cli加载脚本:

$ redis-cli -a yourRedisPassword SCRIPT LOAD "$(cat ./happend.lua)" 
"d30c7f6d0c23fcfe6d4630b11f4e3db4cb2db099" 

注:即使脚本只有一个字符差异,生成的摘要脚本值会完全不同。

现在可以在redia-cli中使用evalsha执行脚本实现追加功能:

> HSET mynewhash greeting "Hello" 
(integer) 1 
> EVALSHA d30c7f6d0c23fcfe6d4630b11f4e3db4cb2db099 1 mynewhash greeting " world" 
(integer) 0 
> HGET mynewhash greeting 
"Hello world" 

让我们详细讲解下evalsha命令。

第一个参数是前面我们使用script load命令创建脚本的sha1摘要信息。
第二个参数表示键的数量,本例中只有一个键,所以设置为1。
第三个参数是我们需要操作的键,第四个参数时我们想修改的字段。
最后一个参数是我们追加字段的值。

因为追加在lua脚本中运行,属于原子的、完全同时执行的,因此上述描述的场景不会发生。

总结

虽然Lua非常有用、能解决很多问题,但应该谨慎使用。脚本运行实会阻塞服务器,并可能导致数据库无响应。在分片的情况下,脚本尝试将所有操作保存在一个服务器上,以避免跨批错误。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/91443529