【问题标题】:Acquiring Locks when updating a Redis key/value更新 Redis 键/值时获取锁
【发布时间】:2013-02-05 14:18:54
【问题描述】:

在更新和获取这样的键/值时,我正在使用 ServiceStack Redis 中的 AcquireLock 方法:

public virtual void Set(string key, T entity)
{
    using (var client = ClientManager.GetClient())
    {
        using (client.AcquireLock(key + ":locked", DefaultLockingTimeout, DefaultLockExpire))
        {
            client.Set(key, entity);
        }
    }
}

我已经扩展了 AcqurieLock 方法来接受额外的参数用于锁定密钥的到期。所以我想知道我是否需要AcquireLock?我的班级在 Get、GetAll、ExpireAt、SetAll 等每个操作中都使用 AcquireLock。

但这种方法并非每次都有效。例如,如果锁中的操作抛出异常,则密钥保持锁定状态。对于这种情况,我在 AcquireLock 方法中添加了 DefaultLockExpire 参数以使“锁定”密钥过期。

有没有更好的解决方案,或者我们什么时候需要获取锁,比如多线程编程中的“锁”块。

【问题讨论】:

    标签: locking timeout redis servicestack


    【解决方案1】:

    我不会将锁用于获取/设置操作。 Redis 会以原子方式执行这些操作,因此在设置或获取时不会“在你下面改变”。我已经构建了数百个客户端同时更新/操作值的系统,并且从不需要锁来执行这些操作(尤其是过期)。

    我不知道 Service Stack redis 是如何实现它的锁定的,所以我不能说它为什么会失败。但是,我不确定我是否会相信它,因为 Redis 端不需要真正的锁定来进行数据操作。 Redis 是单线程的,所以在那里锁定没有意义。

    如果您正在执行复杂操作并获得一个值,则基于它对事物进行操作,然后在一段时间后对其进行更新,并且在此期间不能更改值,我建议您阅读和摸索http://redis.io/topics/transactions 到看看你想要的是否是 Redis 的优点,你的代码是否需要重构以消除问题,或者至少找到更好的方法。

    例如,SETNX 可能是您获得想要的东西所需的路线,但如果没有详细信息,我不能说它会起作用。

    【讨论】:

    • ServiceStack Redis 客户端使用 SETNX 来完成其锁定。锁定几乎是 Redis 公开的 API 之上的抽象构建。
    • 无需做出假设,也无需相信您不知道的东西。您可以阅读有关distributed locking with redis here 的信息。是为分布式应用加锁的,不是为redis加锁的。
    • 我不相信所描述的锁定 redis 数据的方法。至于原因,请查看 setnx 文档——特别是关于锁定的讨论。当所述数据存储不直接支持时,使用数据存储作为应用程序级锁定机制,但您必须解决它,只有在语言不支持标准并发机制(例如锁定)时才应该这样做。我不完全信任它,因为我知道使用 redis 进行应用程序级锁定。
    • 旨在锁定redis数据,它用于在您的分布式锁定机制中提供b>应用程序 恰好使用 Redis。这并不重要,但实现同时使用 SETNX 和 GETSET。
    • 重点不在于你是否同意它的存在。您最初声明您不信任它(对它一无所知),然后在被告知它仅用于 应用程序级分布式锁定 后回复:not a good idea to use redis in this fashion - 没有提供任何具体或具体信息至于为什么或什么时候它不能达到预期的目的。基本上,除非你知道一个正当的理由,否则你不应该就你不知道的事情提供建议。
    【解决方案2】:

    正如 The Real Bill 的回答所说,Redis 本身不需要锁。 ServiceStack 客户端在锁定方面提供的不是 Redis,而是您的应用程序。在 C# 应用程序中,您可以使用 lock(obj) 在本地锁定事物,这样就不会同时发生某些事情(一次只有一个线程可以访问锁定的部分),但这只有在您有一个网络服务器时才有效。如果你想防止某些事情同时发生,你需要一个位于网络服务器之外的锁定机制。 Redis 非常适合这种情况。

    我们有一个案例,它检查客户是否已经拥有购物车,如果没有,则创建它。在检查和创建它之间,有时另一个请求也可能发现购物车不存在并且也可能继续创建购物车。这是锁定的经典案例,但简单的lock 在这里不起作用,因为请求可能来自完全不同的 Web 服务器。因此,为此,我们使用 ServiceStack Redis 客户端(带有一些抽象)来使用 Redis 进行锁定,并且一次只允许一个请求进入“创建购物车”部分。

    所以要回答您的实际问题:不,您不需要锁定来获取/设置 Redis 的值。

    【讨论】:

      【解决方案3】:

      正如@JulianR 所说,ServiceStack.Redis 中的锁定仅适用于应用程序级分布式锁(即在分布式文件系统上使用数据库或空.lock 文件替换)和它仅适用于使用相同密钥/API 获取锁的其他进程中的其他 ServiceStack.Redis 客户端。

      对于普通的 Redis 操作,您永远不需要这样做,因为它们都是原子的。如果您想确保 redis 操作的组合以原子方式发生,而不是 combine them within a Redis Transactionexecute them within a server-side Lua script - 两者都允许原子执行批处理操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-22
        • 2018-04-03
        相关资源
        最近更新 更多