【问题标题】:Check-and-Set (CAS) operations with Booksleeve and Redis使用 Booksleeve 和 Redis 进行检查和设置 (CAS) 操作
【发布时间】:2012-10-11 16:51:17
【问题描述】:

Booksleeve 是否支持 CAS 操作(即 Redis WATCH 命令)?例如,如何实现以下内容?

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

当多个线程试图用相同的数据修改同一个对象时,我需要这个来避免竞争条件。

【问题讨论】:

  • 现在已更改,现已实施

标签: database redis booksleeve


【解决方案1】:

目前在 nuget 中,我不这么认为。因为 BookSleeve通常被用作多路复用器,这使得“watch”无法使用。我可以添加它,但您必须在操作期间将使用限制为单个调用者(每个 BookSleeve 连接)。

这个has now changed;如果我们想手动实现INCR(根据您的示例),我们可以使用:

// note this could be null if the old key didn't exist
var oldVal = await connection.Strings.GetInt64(db, key);

var newVal = (oldVal ?? 0) + 1;
using (var tran = connection.CreateTransaction())
{
    // check hasn't changed (this handles the WATCH, a checked GET,
    // and an UNWATCH if necessary); note tat conditions are not sent
    // until the Execute is called
    tran.AddCondition(Condition.KeyEquals(db, key, oldVal));

    // apply changes to perform assuming the conditions succeed
    tran.Strings.Set(db, key, newVal); // the SET

    // note that Execute includes the MULTI/EXEC, assuming the conditions pass
    if (!await tran.Execute()) return null; // aborted; either a pre-condition
                                         // failed, or a WATCH-key was changed
    return newVal; // successfully incremented
}

显然,您可能希望在重复的(在合理的范围内)循环中执行该操作,以便如果由于 WATCH 而中止它,您可以从头开始重做。

这与您的示例略有不同,实际上是这样(假设初始 GET 和第二个 GET 之间的值没有改变):

val = GET mykey
newval = (val ?? 0) + 1
WATCH mykey
chk = GET mykey // and verifies chk == val as part of the Execute
MULTI
SET mykey $newval
EXEC

请注意,如果值在 WATCHEXEC 之间更改,EXEC 仍然可以报告取消;或(如果它在两个GETs 之间发生变化):

val = GET mykey
newval = (val ?? 0) + 1
WATCH mykey
chk = GET mykey // and verifies chk == val as part of the Execute
UNWATCH

不同之处在于多了一个GET,但这是它与多路复用器一起工作的唯一方式——即,Execute 被优化为可靠快速,因此它不会影响其他调用者。

【讨论】:

  • 感谢您的回复。我想知道,因为 AppHarbor 可以启动我的后台应用程序的多个实例(它有 Quartz 进行调度,应该在某个时间范围内只执行一次),并且我想保证每个调度的操作只发生一次。我曾计划在列表中插入一个值,并保证它是唯一存在的。有什么解决办法吗?
  • @tamaslnagy 好吧,问题中的代码:这是不能用 "incr" 完成的吗?哪个是自动原子的?还有一些内置的分布式锁代码使用“监视”,但它通过短暂阻塞多路复用器来实现。如果场景合适,您可以尝试使用该代码吗?
  • 什么是ow?如果 inc 是原子的,那么这可能是合适的。删除是原子的吗?
  • @tamaslnagy "ow" 是 "now" 的错字;p 是的,remove 是原子性的。有关锁定的内容,请参见.Strings.TakeLock(...),它可以执行WATCHEXISTSUNWATCH - 或WATCHEXISTSMULTISETNXEXPIRE、@98765444关于它看起来是否可用
  • 看起来它可以工作。在我决定 ReleaseLock 或锁过期之前,我只会在一个键上 TakeLock?哦,仅供参考 Booksleeve 是一个非常棒的工具;以防万一你不知道:P
猜你喜欢
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-17
  • 2015-03-28
相关资源
最近更新 更多