如何进行延续并将其作为 MULTI 命令的一部分包含在内?
How to do a continuation and include it as part of the MULTI command?
总而言之,我正在尝试调用 ITransaction.SetPopAsync(...)
并执行其他写入操作作为底层 MULTI
Redis 原子操作的一部分。
我尝试执行SetPopAsync(...)
调用Task.ContinueWith
的延续,并在回调中执行所谓的其他写入操作,但当我发现这些被执行时,我感到很惊讶在基础 MULTI
操作结束后(即当 ITransaction.ExecuteAsync()
完成时)。
也许我弄错了,但我觉得只有将 LUA 脚本加载到 Redis 并从 C# 调用它才能完成此原子操作。
对于我的案例,是否有任何其他解决方案可以完全在 C# 和 StackExchange.Redis
库中实现?
更多信息...
我发现有关于此主题的特定文档 here。
现在我更困惑了,因为 *如果你执行整个 spop
而它不是 MULTI
命令的一部分,并且当你在 [= 之后创建其他键时会发生什么18=], 系统崩溃导致数据损坏?
所以...我是否遗漏了一些可以让我执行整个 spop
并确保所有其他操作都将完成并持续存在的东西?
示例场景...
正如@BerinLoritsch 在这里的一些评论中所要求的,我将在这里抛出一个 伪代码 使用 Redis 命令来举例说明这里发生了什么:
MULTI
key1MemberValue = spop key1 1
sadd key2 key1MemberValue
zadd key3 1 key1MemberValue
EXEC
请注意,我不能使用 smove
,因为我不知道真实情况下的集合成员。我需要随机弹出一个。
现在,实际上在我的特殊情况下,有另一种方法可以解决同样的问题,它允许我以原子性进行操作。
不使用 spop
,而是使用 Redis 命令检查以下伪代码:
time = [current time]
member = zrangebyscore key1 -inf +inf limit 0 1
zrem key1 member
zadd key2 time member
zadd key3 time member
目前,这里的最佳解决方案似乎是 LUA 调用上述代码清单命令的脚本,因为 Redis 是单线程的,它可以一次发生一个操作,LUA 脚本本身被认为是一个操作,如果我想确保其他操作不会尝试弹出相同的 set
值,我觉得这应该是要走的路......
此外,我不得不将 常规集 转换为 有序集 。由于 Redis 在复制和集群环境中避免数据损坏的限制,您不能在非确定性命令之后调用写入命令,无论是读取还是写入操作。感谢 zrangebyscore
(也可能是 zrange
、zrevrange
、zrevrangebyscore
...),因为 它是确定性的 ,我可以模拟pop操作,仍然使用集合语义
最终,您需要了解 Redis multi/exec 块不像 ADO.NET 事务。从根本上说,以下(来自问题)在redis中是不可能的:
MULTI
key1MemberValue = spop key1 1
sadd key2 key1MemberValue
zadd key3 1 key1MemberValue
EXEC
因为你从 spop
得到的是:QUEUED
。就这样。在 EXEC
之前,您不会得到任何 答案,因此您不能 在 sadd
/zadd
在 MULTI
.
里面
你可以可以想象,在原始redis中,涉及WATCH
的事情;然而,所有这一切意味着如果 WATCH
-ed 键被另一个连接改变,MULTI
/EXEC
块被 abandoned,未执行;你会仍然有spop
-ped.
所以从根本上说:是的,如果您希望在没有竞争连接使状态无效的情况下发生这种情况:您将必须通过 Lua 和 EVAL
/EVALSHA
来实现 - 或者它会需要更改 Condition
API.
总而言之,我正在尝试调用 ITransaction.SetPopAsync(...)
并执行其他写入操作作为底层 MULTI
Redis 原子操作的一部分。
我尝试执行SetPopAsync(...)
调用Task.ContinueWith
的延续,并在回调中执行所谓的其他写入操作,但当我发现这些被执行时,我感到很惊讶在基础 MULTI
操作结束后(即当 ITransaction.ExecuteAsync()
完成时)。
也许我弄错了,但我觉得只有将 LUA 脚本加载到 Redis 并从 C# 调用它才能完成此原子操作。
对于我的案例,是否有任何其他解决方案可以完全在 C# 和 StackExchange.Redis
库中实现?
更多信息...
我发现有关于此主题的特定文档 here。
现在我更困惑了,因为 *如果你执行整个 spop
而它不是 MULTI
命令的一部分,并且当你在 [= 之后创建其他键时会发生什么18=], 系统崩溃导致数据损坏?
所以...我是否遗漏了一些可以让我执行整个 spop
并确保所有其他操作都将完成并持续存在的东西?
示例场景...
正如@BerinLoritsch 在这里的一些评论中所要求的,我将在这里抛出一个 伪代码 使用 Redis 命令来举例说明这里发生了什么:
MULTI
key1MemberValue = spop key1 1
sadd key2 key1MemberValue
zadd key3 1 key1MemberValue
EXEC
请注意,我不能使用 smove
,因为我不知道真实情况下的集合成员。我需要随机弹出一个。
现在,实际上在我的特殊情况下,有另一种方法可以解决同样的问题,它允许我以原子性进行操作。
不使用 spop
,而是使用 Redis 命令检查以下伪代码:
time = [current time]
member = zrangebyscore key1 -inf +inf limit 0 1
zrem key1 member
zadd key2 time member
zadd key3 time member
目前,这里的最佳解决方案似乎是 LUA 调用上述代码清单命令的脚本,因为 Redis 是单线程的,它可以一次发生一个操作,LUA 脚本本身被认为是一个操作,如果我想确保其他操作不会尝试弹出相同的 set
值,我觉得这应该是要走的路......
此外,我不得不将 常规集 转换为 有序集 。由于 Redis 在复制和集群环境中避免数据损坏的限制,您不能在非确定性命令之后调用写入命令,无论是读取还是写入操作。感谢 zrangebyscore
(也可能是 zrange
、zrevrange
、zrevrangebyscore
...),因为 它是确定性的 ,我可以模拟pop操作,仍然使用集合语义
最终,您需要了解 Redis multi/exec 块不像 ADO.NET 事务。从根本上说,以下(来自问题)在redis中是不可能的:
MULTI
key1MemberValue = spop key1 1
sadd key2 key1MemberValue
zadd key3 1 key1MemberValue
EXEC
因为你从 spop
得到的是:QUEUED
。就这样。在 EXEC
之前,您不会得到任何 答案,因此您不能 在 sadd
/zadd
在 MULTI
.
你可以可以想象,在原始redis中,涉及WATCH
的事情;然而,所有这一切意味着如果 WATCH
-ed 键被另一个连接改变,MULTI
/EXEC
块被 abandoned,未执行;你会仍然有spop
-ped.
所以从根本上说:是的,如果您希望在没有竞争连接使状态无效的情况下发生这种情况:您将必须通过 Lua 和 EVAL
/EVALSHA
来实现 - 或者它会需要更改 Condition
API.