19

交易文件说:

“我们可能会弃用并最终删除交易”和“你可以用 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 从长远来看可能不是完全安全的交易?

4

3 回答 3

22

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

EVAL 脚本不允许您查看变量

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

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

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

脚本仍然是确定性的。如果您使用该脚本并在从属服务器上运行它,它仍将执行相同的写入命令,因为主服务器和从服务器具有相同的数据。

于 2012-05-10T12:27:48.170 回答
19

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

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

1. 程序(MULTI EXEC)

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

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

2. 功能性(EVAL 脚本)

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

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

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

于 2014-09-02T18:09:50.263 回答
0

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

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

于 2019-10-22T06:09:13.090 回答