Web-farm中的分布​​式临界区

时间:2011-03-18 15:39:43

标签: c# .net asp.net mutex critical-section

我有大约50个网站,在5个网络服务器上进行负载均衡。它们都使用Enterprise Library Caching,并访问相同的Caching数据库。使用ICacheItemRefreshAction实现,每隔几个小时刷新缓存数据库中的项目。

我想保证只有一个网站通过将刷新代码放在critical section中来刷新缓存。

  • 如果网站在单个服务器上的单个应用池中运行,我可以使用lock()

  • 如果网站在单个服务器上的不同应用池中运行,我可以使用Mutex

但是,这些不能确保跨多个Web服务器的关键部分。

目前,我正在缓存数据库中创建一个新密钥以充当互斥锁。这将通常工作,但我可以看到2个进程可能进入关键部分的可能性很小。

public class TakeLongTimeToRefresh : ICacheItemRefreshAction
{
    #region ICacheItemRefreshAction Members

    public void Refresh(string removedKey, object expiredValue, CacheItemRemovedReason removalReason)
    {
        string lockKey = "lockKey";
        ICacheManager cm = CacheFactory.GetCacheManager();

        if (!cm.Contains(lockKey))
        {
            Debug.WriteLine("Entering critical section");
            // Add a lock-key which will never expire for synchronisation.
            // I can see a small window of opportunity for another process to enter
            // the critical section here...
            cm.Add(lockKey, lockKey, 
                   CacheItemPriority.NotRemovable, null, 
                   new NeverExpired());

            object newValue = SomeLengthyWebserviceCall();
            cm.Remove(removedKey);
            Utilities.AddToCache(removedKey, newValue);

            cm.Remove("lockkey");
        }
    }
}

有没有办法让保证关键部分确保我不会两次调用网络服务?

编辑我应该补充一点,我不能使用共享文件,因为部署策略会阻止它。

StackOverflow引用:

2 个答案:

答案 0 :(得分:4)

你必须涉及一些共同的外部锁定。例如,SQL中的表t包含一行和一个锁定字段,您将获得锁定:

set transaction isolation serializable;
update t set lock = 1 where lock = 0;

检查受影响的行,如果它有1个你有锁,则通过将lock更新为0来释放它。这基本上搭载SQLServer的行锁定,如果两个同时启动,只有一个在S锁定后获得U锁定,另一个一个将阻止并随后返回受影响的0行(因为第一个事务将其翻转为1)。

答案 1 :(得分:1)

我建议您将创建/返回锁定句柄的逻辑移动到数据库并合并它们,这将保证它始终是一个具有锁定的进程。

因此,数据库可能有一个存储过程,您要求锁定,并且它将返回空结果(不成功)或将创建一个记录并将其返回。