共计 3020 个字符,预计需要花费 8 分钟才能阅读完成。
lua-redis
简介
在 Redis 中应用 Lua 脚本在业务开发中是比拟常见的事件,应用 Lua 的长处
有以下几点。
- 对于与屡次 redis 指令的发送,应用 Lua 脚本能够
缩小网络的开销
。当网络传输慢或者响应要求高的场景中尤为要害。
Lua 脚本能够将多个申请通过脚本模式一次进行解决,缩小网络的相干时延。Redis 还提供了 Pipeline 来解决这个问题,
然而在后面指令会影响前面指令逻辑的场景下,Pipeline 并不能满足。 - 原子操作。在 Lua 脚本中会将整个脚本作为一个整体来执行,两头
不会被其余指令而打断
,因而保障了原子性
。
因而在咱们写 Lua 脚本时,无需思考竞争而导致的整体数据状态不统一
的问题,并且无需应用事务。并且因为此个性,
需确保脚本尽可能不要运行工夫过长,要确保脚本执行的粒度最小化。 - 复用和封装。针对于一些
通用能力
的性能,把这些放到 redis 脚本中去实现。
其余客户端调用雷同的脚本代码,从而达到逻辑的复用
。
比照 Lua 脚本与事务:
Lua 脚本自身也能够看作为一种事务,而且应用脚本起来更简略,并且可管制的流程更灵便。
在应用 Redis 事务的时候会遇到两种 问题
:
- 事务在调用 EXEC 之前,产生了语法错误(如参数数量,参数名等问题)或者服务器内存等问题。
遇到这一类问题是,会在服务器运行这些指令前发现这些问题(2.6.5 之后),并且终止此次的事务。 - 事务执行 EXEC 调用之后的失败,如事务中某个键的类型谬误的问题。两头指令的谬误并不会终止前面的流程,
也不会导致后面指令的回滚。然而在 Lua 脚本中,你能够齐全管制这些。
Lua-Redis 指令教程
注入和应用脚本:
-
运行脚本时把脚本发送到 Redis(网络开销较大)
EVAL script numkeys [key ...] [arg ...] # 运行脚本 redis> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second # 运行只读脚本,脚本须要不蕴含任何批改内容的操作。这个指令能够随便被 kill 掉,# 而且不会影响到正本的 stream。这个指令能够在 master 和 replica 上执行。redis> EVAL_RO "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
-
上传脚本,之后应用 SHA1 校验和来调用脚本。(潜在碰撞问题,在应用时个别会漠视)
SCRIPT LOAD script EVALSHA sha1 numkeys key [key ...] arg [arg ...] redis> SCRIPT LOAD "return'hello moto'""232fd51614574cf0867b83d384a5e898cfd24e5a" # 运行脚本 redis> EVALSHA 232fd51614574cf0867b83d384a5e898cfd24e5a 0 "hello moto" # 运行只读脚本,脚本须要不蕴含任何批改内容的操作。这个指令能够随便被 kill 掉,# 而且不会影响到正本的 stream。这个指令能够在 master 和 replica 上执行。redis> EVALSHA 232fd51614574cf0867b83d384a5e898cfd24e5a 0
- 其余一些指令
- SCRIPT DEBUG 用来调试脚本 Document
- SCRIPT EXISTS 通过校验值用来查看脚本是否存在 Document
- SCRIPT FLUSH 革除脚本 Document
- SCRIPT KILL 停到当初执行中的脚本,默认脚本没有写操作 Document
- 留神点
-
运行脚本须要严格依照 Keys 和 Args 的要求来进行传参。
所有操作到的 redis key 应放到 Keys 对象中,否则可能会影响到在 redis 集群中谬误体现。# Bad > eval "return redis.call('set','foo','bar')" 0 OK # Good > eval "return redis.call('set',KEYS[1],'bar')" 1 foo OK
调用 redis 指令
在 redis lua 脚本中最罕用的就是调用 redis 原生的指令。有以下两个指令:
- redis.call(command, key, arg1, arg2…): 当调用产生谬误时,主动终止脚本,强制把相干 Lua 谬误返回给客户端。
- redis.pcall(command, key, arg1, arg2…): 当调用产生谬误时,会进行谬误拦挡,并返回相干谬误。
当调用 redis.call 和 redis.pcall 指令时 Redis Reply 会转换为 Lua 类型,当 Lua 脚本返回时,会将 Lua 类型转换为 Redis Reply。
因而这两种类型的转换是须要通晓的。能够浏览此文档理解 Redis 协定。Link
- Redis integer reply: 如 EXISTS…
- Redis bulk reply: 如 GET…
- Redis multi bulk reply: 如 LRANGE…
- Redis status reply: 如 SET…
- Redis error reply: 指令谬误 …
转换表
-
Redis 回复类型转 Lua 类型转换表:
Redis integer reply -> Lua number Redis bulk reply -> Lua string Redis multi bulk reply -> Lua table (may have other Redis data types nested) Redis status reply -> Lua table with a single ok field containing the status Redis error reply -> Lua table with a single err field containing the error Redis Nil bulk reply -> Lua false boolean type Redis Nil multi bulk reply -> Lua false boolean type
-
Lua 类型类型转 Redis 回复转换表:
Lua number -> Redis integer reply (the number is converted into an integer) Lua string -> Redis bulk reply Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside the Lua array if any) Lua table with -> Redis status reply a single ok field Lua table with -> Redis error reply a single err field Lua boolean false -> Redis Nil bulk reply.
- 注意事项
- Lua 只有
一个数字类型
,Lua number。没有辨别 integer 和 floats,因而将永远转换 Lua numbers 为 integer 回复
。
如果须要 floats 类型,请 return 字符串。(ZSCORE 指令就是这么实现的) - 因为 Lua
语义
起因,Lua array 不能够有nils
。当 redis reply 转换到 Lua array 时会终止运行
。 - 当
Lua Table
蕴含 keys(和其 values),转换成 redis reply 将不会蕴含 keys
。
RESP3 – Redis 6 协定
如须要理解请查看官网文档 Link
示例
Link
Reference:
- Redis Lua 实战 Link
- Redis 官网文档 Link
正文完