StackExchange.Redis:有关事务的几个问题

12

我有几个关于在StackExchange.Redis中使用事务的问题:

  1. 在集群环境下,是否允许执行可能针对不同节点的命令?例如,第一条命令的key带有{1}哈希标签,而第二条命令的key带有{2}哈希标签。
  2. 当条件未满足时,事务的Execute()/ExecuteAsync()仅在何时返回false?如果没有设置条件,它会返回false吗?
  3. 如果发生网络或内部Redis错误,Execute()/ExecuteAsync()会抛出错误还是仅返回false?我是否需要检查命令的任务(假设命令完全正确且通常不会抛出异常),或者它们将被取消?

不幸的是,文档没有详细说明问题#2和#3。

2个回答

8

我已经深入了解了StackExchange.Redis源代码并使用了驱动程序,以下是我的观察:

  • 当您在ITransaction实例上调用操作方法时,不会发生任何实际交互。
  • 只有当您调用Execute()/ExecuteAsync()时,驱动程序才开始与Redis通信。

答案似乎是这样的:

  1. 如@royi-mindel所提到的,事务中的所有键必须针对同一个插槽。否则,您将获得“多键操作必须涉及单个插槽”异常。
  2. Execute()/ExecuteAsync()在两种情况下返回false:当由于条件未满足而丢弃事务时,以及当驱动程序无法排队命令时(例如因为服务器OOM)。所有命令任务都将标记为取消。此外,Execute()/ExecuteAsync()如果其中一个命令在执行过程中失败(例如,由于错误类型操作),则不会返回false
  3. 如果出现某些网络问题,Execute()/ExecuteAsync()将抛出异常,所有命令任务将保持“等待激活”状态。

总之,只有在Execute()/ExecuteAsync()返回true时才应检查命令任务:每个任务都将包含结果或错误(请参阅Exception属性)。


2
  1. Redis集群实现了非分布式版本中所有单键命令。执行复杂的多键操作,如Set类型的并集或交集等命令也被实现,只要这些键都属于同一个节点。 https://redis.io/topics/cluster-spec

您不能使用多个集群键发送多键操作。

  1. 在事务期间可能会遇到两种类型的命令错误:

一个命令可能无法排队,因此在调用EXEC之前可能会出现错误。例如,命令可能在语法上错误(参数数量错误,命令名称错误等),或者可能存在一些关键条件,例如内存不足条件(如果服务器使用maxmemory指令配置了内存限制)。

一个命令在调用EXEC之后可能会失败,例如由于我们针对具有错误值的键执行了操作(例如针对字符串值调用列表操作)。” https://redis.io/topics/transactions

  1. 在.Net中运行任务时,如果在其中抛出未处理的异常,则除非使用taskInstance.Wait(),否则它不会冒泡到任务外部。然后,您将获得AggregateException并需要检查InnerExceptions以获取实际异常。

1
感谢您的回答。不幸的是,第2点和第3点并没有真正回答问题,因为StackExchange.Redis中的事务API添加了一些纯“MULTI,enqueue和EXEC”场景的逻辑。请参见我在问题中添加的链接。(顺便说一句,我没有投反对票。) - andreycha
1
对于#1,你很可能是正确的。虽然集群规范没有提到事务,但我想在集群环境中,MULTI/EXEC块可以被视为多键命令。 - andreycha
1
#1 根据我的经验,使用 StackExchange.Redis 集群时,当键位于不同节点上时,多键操作会失败。 #2 #3 - 我怀疑 StackExchange.Redis 是否重新实现了基本的 Redis 功能,但我会进一步调查。 - Royi Mindel
1
正如我所料,StackExchange.Redis似乎提供了一个基本的包装器来与redis服务器进行交互,同时也支持事务。Redis服务器会将命令排队,直到调用Execute方法 - 我认为这并不是由StackExchange.Redis管理的。除了在执行后返回正确的响应之外,它没有其他作用。https://github.com/StackExchange/StackExchange.Redis/blob/master/docs/Transactions.md - Royi Mindel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接