我有大约50个网站,在5个Web服务器之间进行负载平衡。它们都使用企业库缓存,并访问相同的缓存数据库。使用ICacheItemRefreshAction实现,每隔几个小时刷新一次缓存数据库中的项目。

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


如果网站在单个服务器上的单个应用程序池中运行,则可以使用lock()
如果网站在单个服务器上的不同应用程序池中运行,则可以使用Mutex


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

当前,我正在缓存数据库中创建一个新密钥来充当互斥体。这通常可以正常工作,但是我看到两个进程可以进入关键部分的机会很小。

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");
        }
    }
}


有没有一种保证关键部分可以确保我不会两次调用Web服务的方法?

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

StackOverflow参考:


Will lock() statement block all threads in the proccess/appdomain?
Sharing cache between multiple web-sites.

最佳答案

您必须涉及一些通用的外部锁获取。例如,SQL中的表t具有一行和一个锁字段,您将在其中获取具有以下内容的锁:

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


检查受影响的行,如果它的1具有锁,则通过将锁更新为0来释放它。这实际上是对SQLServer的行锁的back带,如果两个同时启动,则只有一个在S锁之后将获得U锁,另一个将被阻塞然后返回受影响的0行(因为第一个事务将其翻转为1)。

关于c# - 网络农场中的分布式关键部分,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5354362/

10-09 08:19