Redis lua何时真正使用它?
我已经开始研究和使用lua,并且发现它非常适合在需要获取一段键范围时使用。例如:
business:5:visits:2013-11-12
business:5:visits:2013-11-13
使用lua,我只需要向redis发送一个命令,而不是整个日期范围的命令。
现在我正在考虑将更多的逻辑转换并移到Redis上。
以目前的消息存储过程为例:
// create a new unique id
redisClient.incr(Config.messageId, function(err, reply) {
var messageId = reply.toString();
var timestmp = Date.now();
// push message
redisClient.zadd(Config.history + ':' + obj.uid + ':' + obj.channel.replace(/\s+/g, ''), timestmp, messageId);
// store the message data by messageId
redisClient.hmset(Config.messageHash + ':' + messageId, {
'user_id': obj.uid,
'text_body': "some text",
'text_date': timestmp,
});
// set expires
redisClient.expire(Config.history + ':' + obj.uid + ':' + obj.channel.replace(/\s+/g, ''), Config.messageExpire);
redisClient.expire(Config.messageHash + ':' + messageId, Config.messageExpire);
// add to mysql-sync queue
redisClient.RPUSH(Config.messageMySQLSyncQueue, Config.messageHash + ':' + messageId);
});
以上内容可以很容易地转换为lua,但是为了性能值得吗?
使用Lua编写会更快,而且只需要向Redis发出1个命令?会导致阻塞其他命令吗?
Lua 很好,我们在某些情况下使用它 - 尤其是当我们想要一些原子操作发生时,但在你的情况下,你将无法将你的上面的代码转换为 Lua 脚本并在 Redis 中运行。这是因为这行代码:
var timestmp = Date.now();
在这样一行之后,你不能再执行 SET 操作,基本上是因为 Redis 中如何处理主从复制。在这里看一下:http://redis.io/commands/eval#scripts-as-pure-functions
这就像是反对使用 Lua 脚本的又一个论点。
TL;DR: 不要使用 Lua 脚本(用于此)
略长:Redis 的 Lua 脚本语义反对通过代码生成键名,并声明脚本使用的任何键都应作为参数提供(使用“KEYS”数组)。
更长:请参见从http://redis.io/commands/eval 的引用。
所有 Redis 命令在执行之前都必须进行分析,以确定命令将操作哪些键。为了对 EVAL 也适用这一点,必须显式传递键。这在许多方面都很有用,尤其是为了确保 Redis 集群可以将您的请求转发到适当的集群节点。
Lua脚本非常强大。
就像你描述的那样,它可以限制Redis服务器和客户端之间的网络往返次数。此外,你不需要一直发送脚本字符串,只有第一次调用后需要发送SHA1值,而它相当小。
使用Lua有最佳实践:如果你将分片数据或使用复制,请务必将“只读”Lua脚本与实际写入集群的脚本分开执行(必须在主节点上执行)。
在调用Lua之前,计算所需在Redis中使用的所有键,此外,你无法本地访问涉及时间的变量(内嵌在Redis中)。这意味着,必须计算时间相关的值。通常最好将大多数工作放在Lua之外,仅使用它来批量处理Redis操作并限制网络活动。
最后,一定要非常小心Lua超时(可以在Redis中进行覆盖)。由于Lua执行是在Redis实例中阻塞的,它是一个Stop-The-World操作,因此执行时间不应太长(通过“Divide and Conquer”设计算法)。否则,所有事情都会变慢。
还可能出现阈值问题:在Lua脚本中考虑清除Redis键。如果它需要太长时间(需要处理太多键/操作),它将因Lua超时而失败。然后,由于活动,Redis中的数据会增长。下一次尝试使用Lua清除Redis时,它必须处理更多的键,以便清除Redis,结果成功的机会更小!你可能会因Lua超时而出现内存溢出。
Redis 的 Lua 脚本还存在一个缺点:即使它们在同一台物理服务器上,你也不能向其他 Redis 实例发出操作。在一个服务器上运行多个 Redis 实例,以利用所有 CPU 核心,是一种常见的做法。因此你需要通过客户端控制多个 Redis 实例。
总结以上内容:
- Lua 脚本是纯函数。你不能执行外部请求,如 HTTP 请求,甚至不能向其他 Redis 实例发出请求。你不能产生任何副作用。
- Lua 脚本会阻塞所有操作。你不能同时运行两个 Lua 脚本。因此你不能在 Lua 中执行大量操作,例如无限循环来执行后台任务。如果你知道我的意思,这就像在 Windows 95 上格式化软盘一样 :-)
简而言之,Redis 不是应用程序服务器。因此,你不能轻松地在 Lua 中编写任何逻辑并确保一切正常。
如果你需要一个真正的应用程序服务器,内置在一个 NoSQL 数据库中,可以尝试 Tarantool。它也有 Lua 脚本,但不同的是它们不会相互阻塞,仍然作为一个 ACID 事务执行(如果你不执行外部请求),并且它们可以执行任何你想要的副作用,甚至可以向外部数据库,如 Tarantool 或 Redis 发出请求,或执行任何 HTTP 请求。这是通过在单独的纤程中执行每个 Lua 脚本并通过所有由 Lua 脚本进行的更改的基于行的复制来实现的。
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
_Lua脚本_旨在像
MULTI命令一样工作。实际上,你可以使用Lua实现使用Redis客户端开发的大多数使用MULTI命令的命令。也就是说,你可以将一些复杂的操作封装在脚本中,并且不必担心Redis上的数据建模策略,数据层将执行原子_write操作。此外,当你想执行快速但又复杂的读操作时,我发现它们非常有用。例如,你可能想按顺序获取对象,而对象则存储在_hash键_中,而顺序由_sorted set key_定义。你可以获取所谓的排序集的范围,并使用
hmget从哈希中获取对象。最重要的一点是Lua脚本应尽可能快地执行,因为Redis在运行Lua脚本时会阻塞其他操作。也就是说,你需要执行_快速中断_,否则Redis的整体性能会大大降低。
不使用Lua的理由
我认为你应该在真正需要时使用它们。通常,客户端是使用高级编程语言如C#、Java、JavaScript、Ruby等开发的,并且它们提供更好的开发体验:良好的调试器、IDE、代码完成...
总结:如果你能证明,将你的域逻辑的某个部分转换为Redis Lua脚本可以获得实际的好处(在性能方面),则应该使用它们。