2011-03-18 60 views
3

我有大约50个网站,跨5个网络服务器负载平衡。他们都使用企业库缓存,并访问相同的缓存数据库。高速缓存数据库中的项目每隔几个小时刷新一次,使用ICacheItemRefreshAction实现。网络农场中的分布式临界区域

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

  • 如果Web站点是在一台服务器上的单个应用程序池运行时,我可以用一个lock()

  • 如果Web站点是在单独的应用程序,池在单个运行服务器,我可以使用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"); 
     } 
    } 
} 

是否有具有保证关键部分,以确保我不调用Web服务两次的一种方式?

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

StackOverflow的引用:

+0

也许某种令牌环系统? – jp2code 2011-03-18 15:53:32

回答

4

你必须涉及共同所有的一些外部锁定习得。例如,表t在SQL与一行和一个锁字段,您将获得一个锁:影响

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

检查行,如果1你有锁,通过更新锁0释放。这实际上是捎带在SQLServer的行锁上,如果两个同时启动,只有一个会在S锁定后获得U锁,另一个会阻塞并随后返回0行(因为第一个事务将其翻转为1)。

+0

我认为这是正确的做法。如果EL缓存在添加现有密钥时抛出异常,则会产生相同的效果。但是,如果没有,我需要在SQL中自己实现它。谢谢:) – 2011-03-18 15:57:42

+6

只要记住,这种锁定是不持久的,如果你的进程在获取之后但在释放锁之前发生故障,它将永久锁定。摆脱这种方式的一个好方法是强制执行超时,这意味着如果在设定时间内锁没有被释放,即使锁= 1,请求者也可以获得它,例如 'set lock = 1,locktime = getdate()where lock = 0或datediff(m,locktime,getdate())> 15' 15分钟 – mmix 2011-03-18 22:57:58

+0

@mmix感谢您的建议。我正在使用它。唯一的问题是我认为datepart“m”是几个月而不是几分钟。分钟将是“mi”。参考:https://msdn.microsoft.com/en-us/library/ms189794.aspx – 2015-07-30 00:39:54

1

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

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