Redis lua何时真正使用它?

Alo*_*ius 6 lua redis

我已经开始研究和玩lua了一下,并且发现在想要获取按键范围时它很棒.例如:

business:5:visits:2013-11-12
business:5:visits:2013-11-13
etc
Run Code Online (Sandbox Code Playgroud)

使用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);

});
Run Code Online (Sandbox Code Playgroud)

上面的内容很容易转换成lua,但它的性能是否值得?

在Lua中写这个并且只需要向Redis发出1个命令会更快吗?是否会导致阻止其他命令出现问题?

Mat*_*zer 8

Lua脚本意味着像MULTI命令一样工作.实际上,您使用MULTIRedis客户端命令开发的大多数命令都可以在Lua中实现.也就是说,您可以在脚本中封装一些复杂的操作,您的数据层将执行原子写操作,而不必担心Redis上的数据建模策略.

此外,当您想要执行快速但复杂的读取操作时,我发现它们非常有用.例如,您可能希望按顺序获取对象.对象存储在散列键中,而顺序由有序集密钥定义.你得到了一系列所谓的有序集合,你可以使用哈希获得对象hmget.

最重要的一点是Lua脚本应该实现尽可能快地执行的事情,因为Redis将在Lua脚本运行时阻止其他操作.也就是说,您需要执行快速中断,否则您的整体Redis性能会下降很多.

不使用Lua的论据

我认为你应该在真正需要时使用它们.通常,客户端是使用C#,Java,JavaScript,Ruby等高级编程语言开发的......它们提供了更好的开发体验:良好的调试器,IDE,代码完成......

简介:如果您将域逻辑的某些部分转换为Redis Lua脚本,则可以证明存在实际的好处(性能),您应该使用它们.


小智 8

Redis的Lua脚本还有一个缺点:即使它们位于同一物理服务器上,您也无法向其他Redis实例发出操作.在一台服务器上运行多个Redis实例以利用所有CPU内核是一种常见做法.因此,您必须从客户端控制Redis的许多实例.

总结一下上面说的一切:

  1. Lua脚本是纯函数.您不能执行诸如http请求之类的外部请求,甚至不能向其他Redis实例发出请求.你不能产生任何副作用.
  2. Lua脚本阻止了一切.您不能并行运行两个Lua脚本.因此,你不能在Lua做任何大工作,例如你不能在Lua中运行无限循环来在后台做某事.如果你知道我的意思,就像在Windows 95上格式化软盘一样:-)

简而言之,Redis不是应用程序服务器.因此,您无法在Lua上轻松编写任何您想要的逻辑,并确保一切正常.

如果您需要NoSQL数据库中的真实应用程序服务器,那么请尝试Tarantool.它也有Lua脚本,但区别在于它们不会相互阻塞,它们仍然作为一个ACID事务执行(如果你不做外部请求),它们可能会产生你想要的任何副作用,甚至问题请求外部数据库,如Tarantool或Redis或执行任何http请求.这是通过在单独的光纤中执行每个Lua脚本以及通过Lua脚本完成的所有更改的基于行的复制来实现的.

  • 我在我的 MAC 上启动了 2 个 redis 实例,运行了一个 lua 脚本,该脚本在一个永远等待的实例上..并在另一个实例上运行了一个不同的 lua 脚本..它返回了。平也恢复得很好。这个答案是错误的和误导性的 (2认同)

Liv*_*tea 7

Lua 很好,我们在某些情况下使用了它——特别是当我们想要一些原子操作发生时,但在你的情况下,你将上面的代码转换为 Lua 脚本并运行到 Redis 时会遇到问题。那是因为这一行:

var timestmp = Date.now();
Run Code Online (Sandbox Code Playgroud)

在这样一行之后你就不能再执行 SET 操作了,主要是因为 Redis 中是如何处理主从复制的。看看这里:http : //redis.io/commands/eval#scripts-as-pure-functions
这就像另一个反对使用 Lua 脚本的论据。


Ita*_*ber 7

TL;DR:不要使用 Lua 脚本(为此)

稍微长一点:Redis 的 Lua 脚本语义反对通过代码生成键名,并声明脚本使用的任何键都应作为参数提供(使用KEYS数组)。

更长的时间:参见http://redis.io/commands/eval 的引用

在执行之前必须分析所有 Redis 命令,以确定该命令将操作哪些键。为了使 EVAL 为真,必须显式传递键。这在很多方面都很有用,尤其是要确保 Redis Cluster 可以将您的请求转发到适当的集群节点


zen*_*eni 6

Lua 脚本真的很强大。正如您正确描述的那样,它允许限制 redis 服务器和客户端之间的网络往返。此外,您不会一直将脚本作为字符串发送,只应在第一次调用后发送 SHA1,这非常小。

Lua 有一些最佳实践:如果您将数据分片或使用复制,请确保将“只读”的 lua 脚本与在集群中实际写入的脚本分开(它们必须在 master 上执行)。

在你的 lua 调用之前计算,你在 redis 中需要的所有键,而且你不能在 lua 中访问与时间相关的变量(嵌入在 redis 中),这意味着必须在 lua 之外计算与时间相关的值。通常最好在 lua 之外完成大部分工作,仅使用它来对 redis 进行批量操作并限制网络活动。

最后,要非常小心 lua 超时(您可以在 redis 中覆盖它)。由于 lua 执行在 redis 实例中被阻塞,因此它是一个 Stop-The-World 操作,因此执行时间不能太长(以“分而治之”的方式设计算法),否则一切都会变慢。

也可能出现阈值问题:考虑在 lua 脚本中清理 redis 键。如果时间太长(要处理的键/操作太多),它将由于 lua 超时而失败。然后,由于活动,您的数据在 redis 中增长。下次你尝试用 lua 清理时,它必须处理更多的键才能清理 redis,因此它成功的机会更少!由于 lua 超时,您可能会出现内存不足的情况...