Redis Lua 教程
lua-redis
简介
在Redis中使用Lua脚本在业务开发中是比较常见的事情,使用Lua的优点
有以下几点。
- 对于与多次redis指令的发送,使用Lua脚本可以
减少网络的开销
。当网络传输慢或者响应要求高的场景中尤为关键。
Lua脚本可以将多个请求通过脚本形式一次进行处理,减少网络的相关时延。Redis还提供了Pipeline来解决这个问题,
但是在前面指令会影响后面指令逻辑的场景下,Pipeline并不能满足。 - 原子操作。在Lua脚本中会将整个脚本作为一个整体来执行,中间
不会被其他指令而打断
,因此保证了原子性
。
因此在我们写Lua脚本时,无需考虑竞争而导致的整体数据状态不一致
的问题,并且无需使用事务。并且因为此特性,
需确保脚本尽可能不要运行时间过长,要确保脚本执行的粒度最小化。 - 复用和封装。针对于一些
通用能力
的功能,把这些放到redis脚本中去实现。
其他客户端调用相同的脚本代码,从而达到逻辑的复用
。
在使用Redis事务的时候会遇到两种
问题
:- 事务在调用EXEC之前,产生了语法错误(如参数数量,参数名等问题)或者服务器内存等问题。
遇到这一类问题是,会在服务器运行这些指令前发现这些问题(2.6.5之后),并且终止此次的事务。 - 事务执行EXEC调用之后的失败,如事务中某个键的类型错误的问题。中间指令的错误并不会终止后面的流程,
也不会导致前面指令的回滚。然而在Lua脚本中,你可以完全控制这些。
注入和使用脚本:
- 运行脚本时把脚本发送到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.call(command, key, arg1, arg2...): 当调用发生错误时,自动终止脚本,强制把相关Lua 错误返回给客户端。
- redis.pcall(command, key, arg1, arg2...): 当调用发生错误时,会进行错误拦截,并返回相关错误。
因此这两种类型的转换是需要知晓的。可以阅读此文档了解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 numberRedis bulk reply->Lua stringRedis multi bulk reply->Lua table (may have other Redis data types nested)Redis status reply->Lua table with a single ok field containing the statusRedis error reply->Lua table with a single err field containing the errorRedis Nil bulk reply->Lua false boolean typeRedis 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 replyLua 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 fieldLua table with->Redis error reply a single err fieldLua 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
。
示例
【Redis Lua 教程】代码
Reference:
- Redis Lua实战 Link
- Redis 官方文档 Link
推荐阅读
- 2.6|2.6 Photoshop操作步骤的撤消和重做 [Ps教程]
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- springboot使用redis缓存
- 用npm发布一个包的教程并编写一个vue的插件发布
- 20180322【w4复盘日志】
- 狗狗定点大小便视频教程下载地址
- (1)redis集群原理及搭建与使用(1)
- SwiftUI|SwiftUI iOS 瀑布流组件之仿CollectionView不规则图文混合(教程含源码)
- 【实用教程】4种获取无水印视频素材的方法
- 【糯米糖藕】教程