【问题标题】:Redis: Why is Lua scripting going to replace transactions?Redis:为什么 Lua 脚本会取代事务?
【发布时间】:2012-05-18 22:31:00
【问题描述】:

交易文件说:

“我们可能会弃用并最终删除交易”和“您所做的一切 可以使用 Redis 事务,也可以使用脚本"

http://redis.io/topics/transactions

但是真的吗?我发现这有问题。

在一个事务中,您可以观察多个变量,读取这些变量,并且根据这些变量的独特状态,您可以在调用 EXEC 之前进行一组完全不同的写入。如果在中间时间有任何干扰这些变量的状态,EXEC 将不会执行事务。 (这让你可以重试。这是一个完美的交易系统。)

EVAL 脚本不允许您这样做。根据此页面上的文档:

“脚本作为纯函数...脚本总是计算相同的 给定相同的输入数据,Redis 写入具有相同参数的命令 放。脚本执行的操作不能依赖于任何隐藏的 (非显式)信息或状态可能会随着脚本而改变 执行继续或在脚本的不同执行之间,也不 它能否依赖于来自 I/O 设备的任何外部输入。”

http://redis.io/commands/eval

我在 EVAL 中看到的问题是,您无法在脚本中获取这些变量的状态,并根据这些变量的状态进行一组独特的写入。再说一遍:“在给定相同的输入数据集的情况下,该脚本始终使用相同的参数评估相同的 Redis 写入命令。”因此,生成的写入已经确定(从第一次运行开始缓存)并且 EVAL 脚本不关心脚本中的 GET 值是什么。您唯一能做的就是在调用 EVAL 之前对这些变量执行 GET,然后将这些变量传递给 EVAL 脚本,但问题是:现在调用 GET 和调用 EVAL 之间存在原子性问题。

换句话说,对于事务,您将执行 WATCH 的所有变量,在 EVAL 的情况下,您需要获取这些变量,然后将它们传递给 EVAL 脚本。由于在脚本实际启动之前无法保证脚本的原子性质,并且您需要在调用 EVAL 启动脚本之前获取这些变量,这留下了一个开口,这些变量的状态可能会在 GET 和传递它们之间发生变化评估。因此,对于一组非常重要的用例,WATCH 所具有的原子性保证是 EVAL 所没有的。

那么,为什么要讨论弃用事务,因为这会导致重要的 Redis 功能丢失?或者实际上有没有办法用我还不理解的 EVAL 脚本来做到这一点?或者是否有计划为 EVAL 解决这个问题的功能? (假设的例子:如果他们让 WATCH 与 EVAL 一起工作,就像 WATCH 与 EXEC 一样,那可能会奏效。)

有解决办法吗?或者我是否理解 Redis 从长远来看可能不是完全安全的交易?

【问题讨论】:

    标签: redis


    【解决方案1】:

    确实,lua 脚本可以做任何事务可以做的事情,但我认为 Redis 事务不会消失。

    EVAL 脚本不允许您查看变量

    当一个 eval 脚本正在运行时,没有其他东西可以同时运行。所以,watching 变量是没有意义的。阅读脚本中的值后,您可以确定没有其他人修改过变量。

    我在 EVAL 中看到的问题是,您无法在脚本中获取这些变量的状态,并根据这些变量的状态进行一组独特的写入。

    不正确。您可以将密钥传递给 eval 脚本。在您的 eval 脚本中,您可以从 Redis 读取值,然后根据这些值有条件地执行其他命令。

    脚本仍然是确定性的。如果你拿那个脚本在slave上运行它,它仍然会执行相同的写命令,因为master和slave拥有相同的数据。

    【讨论】:

    • 如果你说的都是实战经验就好了!它胜过我对文档的解释:“在给定相同输入数据集的情况下,该脚本始终评估具有相同参数的相同 Redis 写入命令。”对我来说,这意味着有一个缓存机制正在进行,因此脚本甚至不会被第二次评估。它只是假设给定相同输入的一组写入。听起来不是确定性的。但如果你有这方面的实际经验,我尊重你的专业知识,我感谢你的回答。
    • 另外,关于我的假设示例,我在谈论一个假设功能,其中 WATCH 可以在 EVAL 外部 和 EVAL 执行 之前 使用。 (在这个意义上,EVAL 的行为类似于 EXEC 的一个新功能。)这样,可以执行 GET 以准备将它们传递给 EVAL,而无需担心它们会发生变化。 (尽管 EVAL 内部毕竟是确定性的,但没有争议。)再次感谢。 :)
    • Redis DB Server 在 Transaction(MULTI/EXEC) 和 Eval 之间宕机时会发生什么?假设执行了一些命令,如 POP/PUSH... 并在执行更多命令之前关闭了 ..?
    【解决方案2】:

    EVAL 脚本实际上扩展并简化了事务的功能。

    通过以下方式查看 Redis 中的两种事务可能会有所帮助:

    1.程序(MULTI EXEC)

    Pure MULTI EXEC 将要一次性执行的命令分组,并从每个命令返回一组回复。它有一个严重的局限性。它不允许在事务中使用下一个命令的中间结果。在这种纯粹的形式中,它在实际应用中不是很有用。它基本上是一个保证原子性的流水线。

    在事务之前添加 WATCH key,允许乐观锁定并在事务中使用从事务之外的 Redis 获得的值。如果发生竞争条件,事务将失败并且必须重试。这会使应用程序逻辑复杂化,而且乐观通常是没有根据的,因为您可能最终会陷入无休止的重试循环。

    2。函数式(EVAL 脚本)

    EVAL 不仅对 Redis 命令进行分组,还为您提供了完整编程语言的强大功能,尤其是条件、循环和局部变量。在 Lua 脚本中,您可以在一个命令中从 Redis 读取值,然后在下一个命令中使用它们。

    您提交以原子方式执行的脚本。它由单线程“停止世界”方法保证。执行脚本时不会执行其他脚本或 Redis 命令。因此 EVAL 也有一个限制:脚本必须小而快,以防止阻塞其他客户端。

    我们还需要相信其他客户端不会提交慢速脚本,这应该被视为编程错误。它非常适合安全模型,因为“Redis 旨在由受信任环境中的受信任客户端访问”

    【讨论】:

    • Redis DB Server 在 Transaction(MULTI/EXEC) 和 Eval 之间宕机时会发生什么?假设执行了一些命令,如 POP/PUSH... 并在执行更多命令之前关闭了 ..?
    【解决方案3】:

    EVAL 脚本可以做事务可以做的所有事情,除了乐观锁定,这在单线程环境中不是很有用。

    只有通过脚本才能完成的非常有用的一件事是条件执行,例如执行一些执行并根据结果选择不同的后续执行,这只能在脚本中完成,这使得脚本在构建需要条件检查的功能时更加强大,这种情况经常发生。

    【讨论】:

      猜你喜欢
      • 2012-06-30
      • 2015-10-27
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      • 1970-01-01
      • 1970-01-01
      • 2014-02-13
      • 1970-01-01
      相关资源
      最近更新 更多