1

免责声明:我已经问过这个问题,但没有部署要求。我得到了一个得到 3 票赞成的答案,当我编辑问题以包含部署要求时,答案就变得无关紧要了。我重新提交的原因是因为 SO 认为原始问题“已回答”,即使我没有得到有意义的赞成答案。我打开了有关此问题的用户语音提交。我重新发布的原因是 StackOverflow 认为原始问题已回答,因此它不会显示在“未回答的问题”选项卡上。

你会使用哪种分布式锁服务?

要求是:

  1. 可以从不同进程/机器看到的互斥(锁)
  2. 锁定...释放语义
  3. 一定超时后自动释放锁 - 如果锁持有者死亡,它将在 X 秒后自动释放
  4. Java 实现
  5. 易于部署- 除了 Netapp、MySql 或 GigaSpaces 之外,不需要复杂的部署。必须与这些产品配合使用(尤其是 GigaSpaces - 这就是 TerraCotta 被排除在外的原因)。
  6. 很高兴拥有:.Net 实施
  7. 如果它是免费的:死锁检测/缓解

我对“可以通过数据库完成”或“可以通过 JavaSpaces 完成”之类的答案不感兴趣——我知道。相关答案应该只包含一个现成的、开箱即用的、经过验证的实施。

4

4 回答 4

4

您的 .Net 实现与 Java API 提供的现有开箱即用的锁定/解锁 API 非常接近。请参阅: http ://www.gigaspaces.com/docs/JavaDoc8.0/org/openspaces/core/DefaultGigaMap.html

您可以在产品随附的 gs-openspaces-src.zip 文件中找到该 Java 类的源代码。与 Gigaspaces .Net API 相同应该是直接的。

于 2011-04-30T14:18:21.613 回答
1

这是符合您的标准的基于 GigaSpaces 的答案的大纲,具体取决于您在标准 3 中的确切含义。我使用 .Net 的 GigaSpaces,而不是 Java:

使用 SpaceID+SpaceRouting 属性 IDing 锁定内容和 DataMember 布尔属性 Unlocked 创建一个锁定类:

sealed public class IdLockTrans
{
    [SpaceID]
    [SpaceRouting]
    public string ID
    {
        get;
        set;
    }

    [DataMember]
    public bool Unlocked
    {
        get;
        set;
    }

    public IdLockTrans(Id id)
    {
        ID = id.ID;
    }

    public IdLockTrans()
    {
    }
}

在特定超时后,您将使用 GigaSpaces 的租用时间来释放锁。这将导致 GigaSpaces 在 IdLockTrans 对象在超时期间处于空闲状态后自动从空间中删除它们。ID 缺少 IdLockTrans 意味着 ID 已解锁。

您的 locker 类将定义和初始化这些类成员

    private readonly ISpaceProxy _proxy;
    private readonly long _leaseTime;

    public override bool Lock(Id id, long timeout)
    {
        bool locked;
        IdLockTrans lockTransTemplate = new IdLockTrans(id);
        // Assume that this is a new id.
        try
        {
            _proxy.Write(lockTransTemplate, null, _leaseTime, 0, UpdateModifiers.WriteOnly);
            locked = true;
        }
        catch (EntryAlreadyInSpaceException)
        {
            using (ITransaction tx = _proxy.CreateLocalTransaction())
            {
                try
                {
                    lockTransTemplate.Unlocked = true;
                    IdLockTrans lockTrans = _proxy.Take(lockTransTemplate, tx, timeout);
                    locked = (lockTrans != null);
                    if (lockTrans != null)
                    {
                        lockTrans.Unlocked = false;
                        _proxy.Write(lockTrans, tx, _leaseTime, 0, UpdateModifiers.WriteOnly);
                    }
                    tx.Commit();
                }
                catch
                {
                    tx.Abort();
                    throw;
                }
            }
        }
        return locked;
    }

    public override void Unlock(Id lockedId)
    {
        IdLockTrans lockTrans = new IdLockTrans(lockedId);
        lockTrans.Unlocked = true;
        try
        {
            _proxy.Update(lockTrans, null, _leaseTime, 0, UpdateModifiers.UpdateOnly);
        }
        catch (EntryNotInSpaceException)
        {
            throw new Exception("IdLockTrans for " + lockTrans.ID
                + " not found on Unlock. Lock time exceeded lease time.");
        }
    }
于 2010-05-11T20:54:38.110 回答
0

如果您仍在寻找,请查看Apache Zookeeper

ZooKeeper 是一个集中式服务,用于维护配置信息、命名、提供分布式同步和提供组服务。所有这些类型的服务都以某种形式被分布式应用程序使用。

Zookeeper 文档提供了如何在 Zookeeper 之上构建 Lock 服务的示例。

于 2010-10-05T00:42:46.467 回答
0

使用 mysql 锁定一个唯一的密钥非常简单。

假设1:

您使用事务并且您的隔离级别是读取提交的。

假设 2:您通过唯一键锁定处理线程,并在事务提交时释放它。

然后您可以将此 sql 用作分发锁:

插入distributed_lock(key) values(#{key}) ON DUPLICATE KEY UPDATE key=key;

于 2017-07-27T07:57:55.607 回答